重学前端-闭包和执行上下文

638 阅读2分钟

说明

重学前端是程劭非(winter)在极客时间开的一个专栏,在此主要整理我的学习笔记。如有侵权,请联系我,谢谢。

执行上下文在不同版本的概念

var声明与赋值

var声明能够穿透if、for等语句

立即执行函数,通过声明一个函数,并且立即执行,来构建一个新的域。来控制var的范围

语法规定function关键字开头是函数声明,为了变成函数表达式,可以在前面加东西。

  • 加括号
(function(){
    var a;
    //code
}());


(function(){
    var a;
    //code
})();

加括号有个缺点,就是如果在最后不加分号,括号会被解释为上一行代码最末的函数调用。因此有些做法是

  • 加前面加分号
    ;(function(){
        var a;
        //code
    }())
    
    
    ;(function(){
        var a;
        //code
    })()
  • void 关键字法
    void function(){
        var a;
        //code
    }();

void表示忽略后面表达式的返回值,变成undefined,在使用立即执行函数时,我们并不关系函数的返回值

在with用法里, var 的特性会导致声明的变量和被赋值的变量是两个 b

var b;
void function(){
    var env = {b:1};
    b = 2;
    console.log("In function b:", b); // 2
    with(env) {
        var b = 3;  
        console.log("In with b:", b); //3
    }
}();
console.log("Global b:", b); // undefined

在with声明的b作用到了外部function的环境上,对两个域(with和function)产生了作用,这是用with的弊端。

这里我修改一下,看看不同的写法,b的值有什么不同

var b;
void function(){
    var env = {b:1};
    b = 2;
    console.log("In function b:", b); //2
    var b = 3;
}();
console.log("Global b:", b);  //undefined

这个时候b还是不同,因为在立即执行函数里用了var关键字声明了b,所有b=2赋值的是该作用域的b,不是全局作用域的b。

var b;
void function(){
    var env = {b:1};
    b = 2;
    console.log("In function b:", b);   //2
}();
console.log("Global b:", b);  //2

这个时候b是同一个b。这个是作用域链在查找变量的时候,如果在内部的作用域找到这个变量的,就会停止查找,如果找不到,会去外层作用域继续查找,直到找到为止。

let

let是es6引入的新的变量声明模式,为了实现let,es6在运行时引入了块级作用域

以下语句会产生let使用的作用域:

  • for
  • if
  • switch
  • try/catch/finally

Realm

新概念。

Realm中包含一组完整的内置对象,而且是复制的关系

var iframe = document.createElement('iframe')
document.documentElement.appendChild(iframe)
iframe.src="javascript:var b = {};"

var b1 = iframe.contentWindow.b;
var b2 = {};

console.log(typeof b1, typeof b2); //object object

console.log(b1 instanceof Object, b2 instanceof Object); //false true

b1和b2是由同样的代码在不同的Realm中执行,在用instanceof是会有不同的行为。