{"action":"created","issue":{"url":"https://api.github.com/repos/creeperyang/blog/issues/2","labels_url":"https://api.github.com/repos/creeperyang/blog/issues/2/labels{/name}","comments_url":"https://api.github.com/repos/creeperyang/blog/issues/2/comments","events_url":"https://api.github.com/repos/creeperyang/blog/issues/2/events","html_url":"https://github.com/creeperyang/blog/issues/2","id":95976938,"number":2,"title":"JavaScript问题集锦","user":{"login":"creeperyang","id":8046480,"avatar_url":"https://avatars.githubusercontent.com/u/8046480?v=3","gravatar_id":"","url":"https://api.github.com/users/creeperyang","html_url":"https://github.com/creeperyang","followers_url":"https://api.github.com/users/creeperyang/followers","following_url":"https://api.github.com/users/creeperyang/following{/other_user}","gists_url":"https://api.github.com/users/creeperyang/gists{/gist_id}","starred_url":"https://api.github.com/users/creeperyang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/creeperyang/subscriptions","organizations_url":"https://api.github.com/users/creeperyang/orgs","repos_url":"https://api.github.com/users/creeperyang/repos","events_url":"https://api.github.com/users/creeperyang/events{/privacy}","received_events_url":"https://api.github.com/users/creeperyang/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/creeperyang/blog/labels/post","name":"post","color":"009800"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":2,"created_at":"2015-07-20T03:22:21Z","updated_at":"2015-10-28T10:51:12Z","closed_at":null,"body":"从[原博客](http://creeperyang.github.io/2015/04/frontend-questions-and-answers/)迁移过来（有更改），并将保持更新。\r\n\r\n---\r\n\r\n关于JavaScript，工作和学习过程中遇到过许多问题，也解答过许多别人的问题。这篇文章记录了一些有价值的问题。\r\n\r\n\r\n### 1. 对象字面值不能正确解析\r\n\r\n**问题**：`{a:1}.a`报错，错误`Uncaught SyntaxError: Unexpected token .`。\r\n\r\n**解决**：\r\n\r\n```js\r\n({a:1}.a) // 或({a:1}).a\r\n```\r\n\r\n**原因**：\r\n\r\n[MDN: Object literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Object_literals)\r\n\r\n> An object literal is a list of zero or more pairs of property names and associated values of an object, enclosed in curly braces ({}). You should not use an object literal at the beginning of a statement. This will lead to an error or not behave as you expect, because the { will be interpreted as the beginning of a block.\r\n\r\n简单说，就是声明对象字面值时，语句开头不应该用`{`，因为js解释器会认为这是语句块（`block`）的开始。\r\n\r\n同理，类似问题`{ name: \"mc\", id: 1 }`会报错`Uncaught SyntaxError: Unexpected token :`也是这个道理。`({ name: \"mc\", id: 1 })`即可正确解析。但稍注意下，`{name: \"mc\"}`是不会报错的，它等同于`name: \"mc\"`，并返回一个字符串`\"mc\"`。\r\n\r\n\r\n### 2. 数字的点操作符\r\n\r\n**问题**：`123.toFixed(2)`报错，错误`Uncaught SyntaxError: Unexpected token ILLEGAL`\r\n\r\n**解决**：\r\n\r\n```js\r\n(123).toFixed(2) // >> \"123.00\"\r\n```\r\n\r\n**原因**：\r\n\r\n很简单，js解释器会把数字后的`.`当做小数点而不是点操作符。\r\n\r\n### 3. 连等赋值问题\r\n\r\n**问题**：尝试解释下连等赋值的过程。下面的代码为什么是这样的输出？\r\n\r\n```js\r\nvar a = {n: 1};  \r\nvar b = a; \r\na.x = a = {n: 2};  \r\nconsole.log(a.x);// --> undefined  \r\nconsole.log(b.x);// --> {n:2}\r\n```\r\n\r\n**原因**：\r\n\r\n我们可以先尝试交换下连等赋值顺序（`a = a.x = {n: 2};`），可以发现输出不变，即顺序不影响结果。\r\n\r\n那么现在来解释对象连等赋值的问题：按照[es5规范](https://es5.github.io/#x11.13)，题中连等赋值等价于\r\n`a.x = (a = {n: 2});`，按优先获取左引用（`lref`），然后获取右引用（`rref`）的顺序，`a.x`和`a`中的a都指向了`{n: 1}`。至此，至关重要或者说最迷惑的一步明确。`(a = {n: 2})`执行完成后，变量`a`指向`{n: 2}`，并返回`{n: 2}`;接着执行`a.x = {n: 2}`，这里的`a`就是`b`（指向`{n: 1}`），所以`b.x`就指向了`{n: 2}`。\r\n\r\n搜索此题答案时，[颜海镜的一篇博客](http://yanhaijing.com/javascript/2012/04/05/javascript-continuous-assignment-operator/)关于此题也有讲述，不过没有讲清楚（或许是我没有领会 :P）。\r\n\r\n### 4. 逗号操作符\r\n\r\n**问题**： 下面的代码返回什么，为什么？\r\n\r\n```js\r\nvar x = 20;\r\nvar temp = {\r\n    x: 40,\r\n    foo: function() {\r\n        var x = 10;\r\n        return this.x;\r\n    }\r\n};\r\n(temp.foo, temp.foo)(); // 20，而不是40\r\n```\r\n\r\n**原因**：\r\n\r\n[MDN逗号操作符](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator): \r\n\r\n>The comma operator evaluates each of its operands (from left to right) and returns the value of the last operand.\r\n\r\n即逗号操作符会从左到右计算它的操作数，返回最后一个操作数的值。所以`(temp.foo, temp.foo)();`等价于`var fun = temp.foo; fun();`，`fun`调用时`this`指向`window`，所以返回20。\r\n\r\n### 5. parseInt传入数字\r\n\r\n**问题**： parseInt传入数字时为什么有以下输出？\r\n\r\n```javascript\r\nparseInt(0.000008) // >> 0\r\nparseInt(0.0000008) // >> 8\r\n```\r\n\r\n**原因**：\r\n\r\n`parseInt(arg)`时会调用`arg.toString()`。\r\n\r\n```javascript\r\n(0.000008).toString() // \"0.000008\"\r\n(0.0000008).toString() // \"8e-7\"\r\n```\r\n\r\n### 6. 前端面试题，利用给定接口获得闭包内部对象\r\n\r\n**问题**： [前端面试题，利用给定接口获得闭包内部对象](http://segmentfault.com/q/1010000002916478)\r\n\r\n```js\r\nvar o = (function() {\r\n    var person = {\r\n        name: 'Vincent',\r\n        age: 24,\r\n    };\r\n    return {\r\n        run: function(k) {\r\n            return person[k];\r\n        },\r\n    }\r\n}());\r\n```\r\n\r\n在不改变上面的代码情况下， 怎么得到原有的 person 对象？\r\n\r\n**解决**：\r\n\r\n```javascript\r\nObject.defineProperty(Object.prototype, 'self', \r\n    {\r\n        get: function() {\r\n            return this;\r\n        },\r\n        configurable: true\r\n    });\r\no.run('self'); // 输出 person\r\n```\r\n\r\n但如果加上`person.__proto__ = null`，目前还没找到解决方法。"},"comment":{"url":"https://api.github.com/repos/creeperyang/blog/issues/comments/151799057","html_url":"https://github.com/creeperyang/blog/issues/2#issuecomment-151799057","issue_url":"https://api.github.com/repos/creeperyang/blog/issues/2","id":151799057,"user":{"login":"creeperyang","id":8046480,"avatar_url":"https://avatars.githubusercontent.com/u/8046480?v=3","gravatar_id":"","url":"https://api.github.com/users/creeperyang","html_url":"https://github.com/creeperyang","followers_url":"https://api.github.com/users/creeperyang/followers","following_url":"https://api.github.com/users/creeperyang/following{/other_user}","gists_url":"https://api.github.com/users/creeperyang/gists{/gist_id}","starred_url":"https://api.github.com/users/creeperyang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/creeperyang/subscriptions","organizations_url":"https://api.github.com/users/creeperyang/orgs","repos_url":"https://api.github.com/users/creeperyang/repos","events_url":"https://api.github.com/users/creeperyang/events{/privacy}","received_events_url":"https://api.github.com/users/creeperyang/received_events","type":"User","site_admin":false},"created_at":"2015-10-28T10:51:12Z","updated_at":"2015-10-28T10:51:12Z","body":"### 13. `jQuery.trigger`的`extraParameters`为`undefined`的问题\r\n\r\n**问题**： 下面`slider`为什么是`undefined`？\r\n\r\n```js\r\n// self 为 某对象\r\n$slider.trigger('slideend', self);\r\n\r\n// 监听\r\n$dom.on('slideend', function(ev, slider) {\r\n    // Uncaught TypeError: Cannot read property 'value' of undefined\r\n    console.log(slider.value); // slider 为 undefined\r\n});\r\n```\r\n\r\n刚看到错误时感觉莫名其妙：怎么就错了？jQuery用的很 **6** 好不好？:joy: \r\n\r\n调试！打了几个断点，找到了原因：\r\n\r\n```js\r\ndata = data != null ? jQuery.makeArray( data ) : [];\r\ndata.unshift( event );\r\n```\r\n\r\n`trigger`中的`self`会被`makeArray`处理，这本来没什么，坑爹的是 `self`有个属性： `self.length = 100`，然后悲剧了，`makeArray`之后`data`变成`[undefined, undefined, ...]`。\r\n\r\n好了，debug完毕，问题看起来很简单，但总结出个道理：错误常常出现在你想不到/忽视的地方。"}}