{"action":"created","issue":{"url":"https://api.github.com/repos/mqyqingfeng/Blog/issues/3","repository_url":"https://api.github.com/repos/mqyqingfeng/Blog","labels_url":"https://api.github.com/repos/mqyqingfeng/Blog/issues/3/labels{/name}","comments_url":"https://api.github.com/repos/mqyqingfeng/Blog/issues/3/comments","events_url":"https://api.github.com/repos/mqyqingfeng/Blog/issues/3/events","html_url":"https://github.com/mqyqingfeng/Blog/issues/3","id":223621840,"node_id":"MDU6SXNzdWUyMjM2MjE4NDA=","number":3,"title":" JavaScript深入之词法作用域和动态作用域","user":{"login":"mqyqingfeng","id":11458263,"node_id":"MDQ6VXNlcjExNDU4MjYz","avatar_url":"https://avatars3.githubusercontent.com/u/11458263?v=4","gravatar_id":"","url":"https://api.github.com/users/mqyqingfeng","html_url":"https://github.com/mqyqingfeng","followers_url":"https://api.github.com/users/mqyqingfeng/followers","following_url":"https://api.github.com/users/mqyqingfeng/following{/other_user}","gists_url":"https://api.github.com/users/mqyqingfeng/gists{/gist_id}","starred_url":"https://api.github.com/users/mqyqingfeng/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mqyqingfeng/subscriptions","organizations_url":"https://api.github.com/users/mqyqingfeng/orgs","repos_url":"https://api.github.com/users/mqyqingfeng/repos","events_url":"https://api.github.com/users/mqyqingfeng/events{/privacy}","received_events_url":"https://api.github.com/users/mqyqingfeng/received_events","type":"User","site_admin":false},"labels":[{"id":589911408,"node_id":"MDU6TGFiZWw1ODk5MTE0MDg=","url":"https://api.github.com/repos/mqyqingfeng/Blog/labels/%E6%B7%B1%E5%85%A5%E7%B3%BB%E5%88%97","name":"深入系列","color":"0e98a2","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":63,"created_at":"2017-04-23T08:44:58Z","updated_at":"2018-11-22T01:19:10Z","closed_at":null,"author_association":"OWNER","body":"## 作用域\r\n\r\n作用域是指程序源代码中定义变量的区域。\r\n\r\n作用域规定了如何查找变量，也就是确定当前执行代码对变量的访问权限。\r\n\r\nJavaScript 采用词法作用域(lexical scoping)，也就是静态作用域。\r\n\r\n## 静态作用域与动态作用域\r\n\r\n因为 JavaScript 采用的是词法作用域，函数的作用域在函数定义的时候就决定了。\r\n\r\n而与词法作用域相对的是动态作用域，函数的作用域是在函数调用的时候才决定的。\r\n\r\n让我们认真看个例子就能明白之间的区别：\r\n\r\n```js\r\nvar value = 1;\r\n\r\nfunction foo() {\r\n    console.log(value);\r\n}\r\n\r\nfunction bar() {\r\n    var value = 2;\r\n    foo();\r\n}\r\n\r\nbar();\r\n\r\n// 结果是 ???\r\n```\r\n\r\n假设JavaScript采用静态作用域，让我们分析下执行过程：\r\n\r\n执行 foo 函数，先从 foo 函数内部查找是否有局部变量 value，如果没有，就根据书写的位置，查找上面一层的代码，也就是 value 等于 1，所以结果会打印 1。\r\n\r\n假设JavaScript采用动态作用域，让我们分析下执行过程：\r\n\r\n执行 foo 函数，依然是从 foo 函数内部查找是否有局部变量 value。如果没有，就从调用函数的作用域，也就是 bar 函数内部查找 value 变量，所以结果会打印 2。\r\n\r\n前面我们已经说了，JavaScript采用的是静态作用域，所以这个例子的结果是 1。\r\n\r\n## 动态作用域\r\n\r\n也许你会好奇什么语言是动态作用域？\r\n\r\nbash 就是动态作用域，不信的话，把下面的脚本存成例如 scope.bash，然后进入相应的目录，用命令行执行 `bash ./scope.bash`，看看打印的值是多少。\r\n\r\n```bash\r\nvalue=1\r\nfunction foo () {\r\n    echo $value;\r\n}\r\nfunction bar () {\r\n    local value=2;\r\n    foo;\r\n}\r\nbar\r\n```\r\n\r\n这个文件也可以在 [Github 博客仓库](https://github.com/mqyqingfeng/Blog/blob/master/demos/scope/scope.bash)中找到。\r\n\r\n## 思考题\r\n\r\n最后，让我们看一个《JavaScript权威指南》中的例子：\r\n\r\n```js\r\nvar scope = \"global scope\";\r\nfunction checkscope(){\r\n    var scope = \"local scope\";\r\n    function f(){\r\n        return scope;\r\n    }\r\n    return f();\r\n}\r\ncheckscope();\r\n```\r\n\r\n```js\r\nvar scope = \"global scope\";\r\nfunction checkscope(){\r\n    var scope = \"local scope\";\r\n    function f(){\r\n        return scope;\r\n    }\r\n    return f;\r\n}\r\ncheckscope()();\r\n```\r\n\r\n猜猜两段代码各自的执行结果是多少？\r\n\r\n这里直接告诉大家结果，两段代码都会打印：`local scope`。\r\n\r\n原因也很简单，因为JavaScript采用的是词法作用域，函数的作用域基于函数创建的位置。\r\n\r\n而引用《JavaScript权威指南》的回答就是：\r\n\r\nJavaScript 函数的执行用到了作用域链，这个作用域链是在函数定义的时候创建的。嵌套的函数 f() 定义在这个作用域链里，其中的变量 scope 一定是局部变量，不管何时何地执行函数 f()，这种绑定在执行 f() 时依然有效。\r\n\r\n但是在这里真正想让大家思考的是：\r\n\r\n虽然两段代码执行的结果一样，但是两段代码究竟有哪些不同呢？\r\n\r\n如果要回答这个问题，就要牵涉到很多的内容，词法作用域只是其中的一小部分，让我们期待下一篇文章————《JavaScript深入之执行上下文栈》。\r\n\r\n## 下一篇文章\r\n\r\n[JavaScript深入之执行上下文栈](https://github.com/mqyqingfeng/Blog/issues/4)\r\n\r\n## 深入系列\r\n\r\nJavaScript深入系列目录地址：[https://github.com/mqyqingfeng/Blog](https://github.com/mqyqingfeng/Blog)。\r\n\r\nJavaScript深入系列预计写十五篇左右，旨在帮大家捋顺JavaScript底层知识，重点讲解如原型、作用域、执行上下文、变量对象、this、闭包、按值传递、call、apply、bind、new、继承等难点概念。\r\n\r\n如果有错误或者不严谨的地方，请务必给予指正，十分感谢。如果喜欢或者有所启发，欢迎star，对作者也是一种鼓励。\r\n\r\n"},"comment":{"url":"https://api.github.com/repos/mqyqingfeng/Blog/issues/comments/440879125","html_url":"https://github.com/mqyqingfeng/Blog/issues/3#issuecomment-440879125","issue_url":"https://api.github.com/repos/mqyqingfeng/Blog/issues/3","id":440879125,"node_id":"MDEyOklzc3VlQ29tbWVudDQ0MDg3OTEyNQ==","user":{"login":"wd2010","id":16284915,"node_id":"MDQ6VXNlcjE2Mjg0OTE1","avatar_url":"https://avatars1.githubusercontent.com/u/16284915?v=4","gravatar_id":"","url":"https://api.github.com/users/wd2010","html_url":"https://github.com/wd2010","followers_url":"https://api.github.com/users/wd2010/followers","following_url":"https://api.github.com/users/wd2010/following{/other_user}","gists_url":"https://api.github.com/users/wd2010/gists{/gist_id}","starred_url":"https://api.github.com/users/wd2010/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wd2010/subscriptions","organizations_url":"https://api.github.com/users/wd2010/orgs","repos_url":"https://api.github.com/users/wd2010/repos","events_url":"https://api.github.com/users/wd2010/events{/privacy}","received_events_url":"https://api.github.com/users/wd2010/received_events","type":"User","site_admin":false},"created_at":"2018-11-22T01:19:10Z","updated_at":"2018-11-22T01:19:10Z","author_association":"NONE","body":"@xiaofan9 我被try/catch给迷惑了，es5中他不会产生块级作用域"}}
{"actor":{"display_login":"wd2010"}}