Hibop / Hibop.github.io

Hibop 个人博客
https://hibop.github.io/
23 stars 1 forks source link

关于执行上下文、作用域、变量对象和活动对象 #8

Open Hibop opened 6 years ago

Hibop commented 6 years ago

执行上下文(context)和作用域(scope)经常容易混淆,两者有什么区别? 函数执行细节有哪些?

执行上下文(context)和作用域(scope)区别?

作用域是你的代码在运行时,各个变量、函数和对象的可访问性。换句话说,作用域决定了你的代码里的变量和其他资源在各个区域中的可见性。是作用域为你的代码提供了一个安全层级。 在 JavaScript 中有两种作用域 全局作用域 局部作用域 块级声明包括if和switch,以及for和while循环,和函数不同,它们不会创建新的作用域。在块级声明中定义的变量从属于该块所在的作用域。 和var关键字不同,let和const关键字支持在块级声明中创建使用局部作用域。

关于this: 在全局作用域中,上下文总是 Window 对象。 作用域定义在一个对象的方法中,上下文this就是这个方法所在的那个对象。 是如果你使用new关键字调用函数时上下文的值会有差异。上下文会设置为被调用的函数的实例。

函数执行到底发生了哪些事情?

当一个函数被执行时, 会生成一个执行上下文. 一个执行上下文的生命周期分为两个阶段:

生成变量——变量对象和活动变量

--> 创建 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

总结

变量对象和活动对象其实都是同一个对象, 只是处于执行上下文的不同生命周期. 未进入执行阶段之前, 变量对象中的属性都不能访问! 但是进入执行阶段之后, 变量对象转变为了活动对象, 里面的属性都能被访问了, 然后开始进行执行阶段的操作.

Hibop commented 6 years ago

如何理解 JavaScript 中的 this 关键字? https://www.zhihu.com/question/19636194 这篇文章对函数的物种调用方式和this的指向经行了深刻解读

Hibop commented 6 years ago

词法作用域和静态作用域: https://github.com/mqyqingfeng/Blog/issues/3

Hibop commented 6 years ago

作用域和变量提升的两个题https://segmentfault.com/a/1190000003114255

Hibop commented 6 years ago

为什么要变量提升? http://www.cnblogs.com/liuhe688/p/5891273.html

Hibop commented 6 years ago

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/

Hibop commented 6 years ago

js执行过程生命周期:https://wanghan0.github.io/2017/05/05/closure1/

Hibop commented 6 years ago

解析引擎看js解析: http://www.html5jscss.com/js-data-scope.html

zhoubhin commented 5 years ago

求教console.log(foo);输出function foo() { return 'hello'; }是因为函数的优先级最高的关系吗?

zhoubhin commented 5 years ago

请教如何理解console.log((foo.bar = foo.bar)());console.log((foo.bar, foo.bar)());最终输出结果为1?