关于执行上下文、作用域、变量对象和活动对象
执行上下文(context)和作用域(scope)经常容易混淆,两者有什么区别? 函数执行细节有哪些?
执行上下文(context)和作用域(scope)区别?
作用域是你的代码在运行时,各个变量、函数和对象的可访问性。换句话说,作用域决定了你的代码里的变量和其他资源在各个区域中的可见性。是作用域为你的代码提供了一个安全层级。 在 JavaScript 中有两种作用域 全局作用域 局部作用域 块级声明包括if和switch,以及for和while循环,和函数不同,它们不会创建新的作用域。在块级声明中定义的变量从属于该块所在的作用域。 和var关键字不同,let和const关键字支持在块级声明中创建使用局部作用域。
关于this: 在全局作用域中,上下文总是 Window 对象。 作用域定义在一个对象的方法中,上下文this就是这个方法所在的那个对象。 是如果你使用new关键字调用函数时上下文的值会有差异。上下文会设置为被调用的函数的实例。
函数执行到底发生了哪些事情?
当一个函数被执行时, 会生成一个执行上下文. 一个执行上下文的生命周期分为两个阶段:
- 创建阶段:
- 生成变量对象
- 确定作用域链
- 确定 this 指向 :我们可以简单的理解 this 为调用函数的对象
- 执行阶段:
- 变量赋值
- 函数引用
- 执行其它代码 总的流程如下:
--> 入栈(ECStack) --> 创建阶段{生成变量, 作用域链, 明确 this} --> 执行阶段{赋值, 引用, 执行其它代码} --> 出栈(等待销毁)
生成变量——变量对象和活动变量
--> 创建 arguments 对象 --> 检查 function 函数声明 --> 检查 var 变量声明
function test() {
console.log(foo);
console.log(bar);
var foo = 'Hello';
console.log(foo);
var bar = function () {
return 'world';
}
function foo() {
return 'hello';
}
}
test();
// 解释
function test() {
function foo() {
return 'hello';
}
var foo; // 已经存在了同名函数 foo, 所以此处跳过, 不会用 undefined 覆盖引用
var bar;
console.log(foo);// function foo() { return 'hello'; }
console.log(bar);// undefined
foo = 'Hello';
console.log(foo);// Hello
bar = function () { // 把匿名函数的引用赋值给 bar
return 'world';
}
}
test();
变量提升是怎么实现的: 执行上下文的创建规则, 用代码表示:
// 创建阶段
testEC = {
// 变量对象
VO: {},
scopeChain: {},
this: {}
}
// VO 为 Variable Object的缩写, 即变量对象
VO = {
arguments: {...}, //注:在浏览器的展示中, 函数的参数可能并不是放在arguments对象中, 这里为了方便理解, 我做了这样的处理
foo: <foo reference> // 表示foo的地址引用
a: undefined
}
// `scopeChain` 和 `this` 暂时省略
//...
// 执行阶段
VO -> AO // Active Object
AO = {
arguments: {...},
foo: <foo reference>,
a: 1
}
再来一个this理解:
var value = 1;
var foo = {
value: 2,
bar: function () {
return this.value;
}
}
//示例1
console.log(foo.bar()); // 2
//示例2
console.log((foo.bar)()); // 2
//示例3
console.log((foo.bar = foo.bar)()); // 1
//示例4
console.log((false || foo.bar)()); // 1
//示例5
console.log((foo.bar, foo.bar)()); // 1
总结
变量对象和活动对象其实都是同一个对象, 只是处于执行上下文的不同生命周期. 未进入执行阶段之前, 变量对象中的属性都不能访问! 但是进入执行阶段之后, 变量对象转变为了活动对象, 里面的属性都能被访问了, 然后开始进行执行阶段的操作.
如何理解 JavaScript 中的 this 关键字? https://www.zhihu.com/question/19636194 这篇文章对函数的物种调用方式和this的指向经行了深刻解读
词法作用域和静态作用域: https://github.com/mqyqingfeng/Blog/issues/3
作用域和变量提升的两个题https://segmentfault.com/a/1190000003114255
JavaScript中valueOf函数与toString方法深入理解http://samgui.com/blog/JavaScript%E4%B8%ADvalueOf%E5%87%BD%E6%95%B0%E4%B8%8EtoString%E6%96%B9%E6%B3%95%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3/
解析引擎看js解析: http://www.html5jscss.com/js-data-scope.html
求教console.log(foo);输出function foo() { return 'hello'; }是因为函数的优先级最高的关系吗?
请教如何理解console.log((foo.bar = foo.bar)());和console.log((foo.bar, foo.bar)());最终输出结果为1?