{"action":"created","issue":{"url":"https://api.github.com/repos/Hey-hy/Blog/issues/7","repository_url":"https://api.github.com/repos/Hey-hy/Blog","labels_url":"https://api.github.com/repos/Hey-hy/Blog/issues/7/labels{/name}","comments_url":"https://api.github.com/repos/Hey-hy/Blog/issues/7/comments","events_url":"https://api.github.com/repos/Hey-hy/Blog/issues/7/events","html_url":"https://github.com/Hey-hy/Blog/issues/7","id":395853484,"node_id":"MDU6SXNzdWUzOTU4NTM0ODQ=","number":7,"title":"JavaScript深入之执行上下文","user":{"login":"Hey-hy","id":21074161,"node_id":"MDQ6VXNlcjIxMDc0MTYx","avatar_url":"https://avatars1.githubusercontent.com/u/21074161?v=4","gravatar_id":"","url":"https://api.github.com/users/Hey-hy","html_url":"https://github.com/Hey-hy","followers_url":"https://api.github.com/users/Hey-hy/followers","following_url":"https://api.github.com/users/Hey-hy/following{/other_user}","gists_url":"https://api.github.com/users/Hey-hy/gists{/gist_id}","starred_url":"https://api.github.com/users/Hey-hy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Hey-hy/subscriptions","organizations_url":"https://api.github.com/users/Hey-hy/orgs","repos_url":"https://api.github.com/users/Hey-hy/repos","events_url":"https://api.github.com/users/Hey-hy/events{/privacy}","received_events_url":"https://api.github.com/users/Hey-hy/received_events","type":"User","site_admin":false},"labels":[{"id":1179993917,"node_id":"MDU6TGFiZWwxMTc5OTkzOTE3","url":"https://api.github.com/repos/Hey-hy/Blog/labels/%E6%B7%B1%E5%85%A5%E7%B3%BB%E5%88%97","name":"深入系列","color":"ededed","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":11,"created_at":"2019-01-04T09:02:18Z","updated_at":"2019-01-04T09:02:40Z","closed_at":null,"author_association":"OWNER","body":"_From @mqyqingfeng on April 26, 2017 2:5_\n\n# 前言\r\n\r\n在[《JavaScript深入之执行上下文栈》](https://github.com/mqyqingfeng/Blog/issues/4)中讲到，当 JavaScript 代码执行一段可执行代码(executable code)时，会创建对应的执行上下文(execution context)。\r\n\r\n对于每个执行上下文，都有三个重要属性：\r\n\r\n* 变量对象(Variable object，VO)\r\n* 作用域链(Scope chain)\r\n* this\r\n\r\n然后分别在[《JavaScript深入之变量对象》](https://github.com/mqyqingfeng/Blog/issues/5)、[《JavaScript深入之作用域链》](https://github.com/mqyqingfeng/Blog/issues/6)、[《JavaScript深入之从ECMAScript规范解读this》](https://github.com/mqyqingfeng/Blog/issues/7)中讲解了这三个属性。\r\n\r\n阅读本文前，如果对以上的概念不是很清楚，希望先阅读这些文章。\r\n\r\n因为，这一篇，我们会结合着所有内容，讲讲执行上下文的具体处理过程。\r\n\r\n## 思考题\r\n\r\n在[《JavaScript深入之词法作用域和动态作用域》](https://github.com/mqyqingfeng/Blog/issues/3)中，提出这样一道思考题：\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两段代码都会打印'local scope'。虽然两段代码执行的结果一样，但是两段代码究竟有哪些不同呢？\r\n\r\n紧接着就在下一篇[《JavaScript深入之执行上下文栈》](https://github.com/mqyqingfeng/Blog/issues/4)中，讲到了两者的区别在于执行上下文栈的变化不一样，然而，如果是这样笼统的回答，依然显得不够详细，本篇就会详细的解析执行上下文栈和执行上下文的具体变化过程。\r\n\r\n## 具体执行分析\r\n\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\n1.执行全局代码，创建全局执行上下文，全局上下文被压入执行上下文栈\r\n\r\n```js\r\n    ECStack = [\r\n        globalContext\r\n    ];\r\n```\r\n\r\n2.全局上下文初始化\r\n\r\n```js\r\n    globalContext = {\r\n        VO: [global],\r\n        Scope: [globalContext.VO],\r\n        this: globalContext.VO\r\n    }\r\n```\r\n\r\n2.初始化的同时，checkscope 函数被创建，保存作用域链到函数的内部属性[[scope]]\r\n\r\n```js\r\n    checkscope.[[scope]] = [\r\n      globalContext.VO\r\n    ];\r\n```\r\n\r\n3.执行 checkscope 函数，创建 checkscope 函数执行上下文，checkscope 函数执行上下文被压入执行上下文栈\r\n\r\n```js\r\n    ECStack = [\r\n        checkscopeContext,\r\n        globalContext\r\n    ];\r\n```\r\n\r\n4.checkscope 函数执行上下文初始化：\r\n\r\n1. 复制函数 [[scope]] 属性创建作用域链，\r\n2. 用 arguments 创建活动对象，\r\n3. 初始化活动对象，即加入形参、函数声明、变量声明，\r\n4. 将活动对象压入 checkscope 作用域链顶端。\r\n\r\n同时 f 函数被创建，保存作用域链到 f 函数的内部属性[[scope]]\r\n\r\n```js\r\n    checkscopeContext = {\r\n        AO: {\r\n            arguments: {\r\n                length: 0\r\n            },\r\n            scope: undefined,\r\n            f: reference to function f(){}\r\n        },\r\n        Scope: [AO, globalContext.VO],\r\n        this: undefined\r\n    }\r\n```\r\n\r\n5.执行 f 函数，创建 f 函数执行上下文，f 函数执行上下文被压入执行上下文栈\r\n\r\n```js\r\n    ECStack = [\r\n        fContext,\r\n        checkscopeContext,\r\n        globalContext\r\n    ];\r\n```\r\n\r\n6.f 函数执行上下文初始化, 以下跟第 4 步相同：\r\n\r\n1. 复制函数 [[scope]] 属性创建作用域链\r\n2. 用 arguments 创建活动对象\r\n3. 初始化活动对象，即加入形参、函数声明、变量声明\r\n4. 将活动对象压入 f 作用域链顶端\r\n\r\n```js\r\n    fContext = {\r\n        AO: {\r\n            arguments: {\r\n                length: 0\r\n            }\r\n        },\r\n        Scope: [AO, checkscopeContext.AO, globalContext.VO],\r\n        this: undefined\r\n    }\r\n```\r\n\r\n7.f 函数执行，沿着作用域链查找 scope 值，返回 scope 值\r\n\r\n8.f 函数执行完毕，f 函数上下文从执行上下文栈中弹出\r\n\r\n```js\r\n    ECStack = [\r\n        checkscopeContext,\r\n        globalContext\r\n    ];\r\n```\r\n\r\n9.checkscope 函数执行完毕，checkscope 执行上下文从执行上下文栈中弹出\r\n\r\n```js\r\n    ECStack = [\r\n        globalContext\r\n    ];\r\n```\r\n\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不过，在下一篇《JavaScript深入之闭包》中也会提及这段代码的执行过程。\r\n\r\n## 下一篇文章\r\n\r\n[《JavaScript深入之闭包》](https://github.com/mqyqingfeng/Blog/issues/9)\r\n\r\n## 相关链接\r\n\r\n[《JavaScript深入之词法作用域和动态作用域》](https://github.com/mqyqingfeng/Blog/issues/3)\r\n\r\n[《JavaScript深入之执行上下文栈》](https://github.com/mqyqingfeng/Blog/issues/4)\r\n\r\n[《JavaScript深入之变量对象》](https://github.com/mqyqingfeng/Blog/issues/5)\r\n\r\n[《JavaScript深入之作用域链》](https://github.com/mqyqingfeng/Blog/issues/6)\r\n\r\n[《JavaScript深入之从ECMAScript规范解读this》](https://github.com/mqyqingfeng/Blog/issues/7)\r\n\r\n## 重要参考\r\n\r\n[《一道js面试题引发的思考》](https://github.com/kuitos/kuitos.github.io/issues/18)\r\n\r\n本文写的太好，给了我很多启发。感激不尽！\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，对作者也是一种鼓励。\n\n_Copied from original issue: mqyqingfeng/Blog#8_"},"comment":{"url":"https://api.github.com/repos/Hey-hy/Blog/issues/comments/451389041","html_url":"https://github.com/Hey-hy/Blog/issues/7#issuecomment-451389041","issue_url":"https://api.github.com/repos/Hey-hy/Blog/issues/7","id":451389041,"node_id":"MDEyOklzc3VlQ29tbWVudDQ1MTM4OTA0MQ==","user":{"login":"Hey-hy","id":21074161,"node_id":"MDQ6VXNlcjIxMDc0MTYx","avatar_url":"https://avatars1.githubusercontent.com/u/21074161?v=4","gravatar_id":"","url":"https://api.github.com/users/Hey-hy","html_url":"https://github.com/Hey-hy","followers_url":"https://api.github.com/users/Hey-hy/followers","following_url":"https://api.github.com/users/Hey-hy/following{/other_user}","gists_url":"https://api.github.com/users/Hey-hy/gists{/gist_id}","starred_url":"https://api.github.com/users/Hey-hy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Hey-hy/subscriptions","organizations_url":"https://api.github.com/users/Hey-hy/orgs","repos_url":"https://api.github.com/users/Hey-hy/repos","events_url":"https://api.github.com/users/Hey-hy/events{/privacy}","received_events_url":"https://api.github.com/users/Hey-hy/received_events","type":"User","site_admin":false},"created_at":"2019-01-04T09:02:40Z","updated_at":"2019-01-04T09:02:40Z","author_association":"OWNER","body":"_From @suoz on June 8, 2017 7:48_\n\n同时 f 函数被创建，保存作用域链到 f 函数的内部属性[[scope]]\r\n```\r\n    checkscopeContext = {\r\n        AO: {\r\n            arguments: {\r\n                length: 0\r\n            },\r\n            scope: undefined,\r\n            f: reference to function f(){}\r\n        },\r\n        Scope: [AO, globalContext.VO],\r\n        this: undefined\r\n    }\r\n   checkscope();\r\n```\r\ncheckscope预编译阶段，形参、函数f声明、变量scope声明。\r\n f 函数被创建的活动是在checkscope函数预编译阶段进行还是在函数执行阶段进行的？"}}
{"actor":{"display_login":"Hey-hy"}}