美文网首页程序员web之路让前端飞
【十二】JavaScript执行(二):闭包和执行上下文到底是怎

【十二】JavaScript执行(二):闭包和执行上下文到底是怎

作者: alanwhy | 来源:发表于2019-02-27 21:53 被阅读7次

    这次我们来了解一下网上有不同的名字的知识,如:

    • 闭包
    • 作用域链
    • 执行上下文
    • this 值

    以上其实都是指函数执行过程的相关知识,如图:

    函数执行.png

    闭包

    在古典的闭包定义下,闭包分为两个部分

    • 环境部分
      • 环境
      • 标识符列表
    • 表达式部分

    但是在JS中闭包则是

    • 环境部分
      • 环境:函数的词法环境(执行上下文的一部分)
      • 标识符列表:函数中用到的未声明的变量
    • 表达式部分:函数体

    这里要说一下,JS的执行上下文或者作用域(scope,ES3中规定的执行上下文的一部分)这个概念不是闭包

    执行上下文:执行的基础设施

    JS中与闭包“环境部分”相对应的术语是“词法环境”,词法环境只是JS执行上下文的一部分

    执行上下文在ES3中:

    • scope:作用域,常常也被叫做作用域链
    • variable object:变量对象,用于存储变量的对象
    • this value: this值

    在ES5中

    • lexical environment:词法环境,当获取变量时使用
    • variable environment:变量环境,当声明变量时使用
    • this value:this 值

    在ES2018中

    • lexical environment:词法环境,当获取变量或者this值时使用
    • variable environment:变量环境,当声明变量时使用
    • code evaluation state:用于恢复代码执行位置
    • Function:执行的任务时函数时使用,表示正在被执行的函数
    • ScriptOrModule:执行的任务时脚本或者模块时使用,表示正在被执行的代码
    • Realm:使用的基础库和内置对象实例
    • Generator:仅生成器上下文有这个属性,表示当前生成器

    来个例子:

    var b = {}
    let c = 1
    this.a = 2;
    

    想要执行上面的代码,就需要知道:

    • var把b声明到哪里
    • b表示哪个变量
    • b的原型时哪个对象
    • let 把c声明到哪里
    • this指向哪个对象

    var 声明与赋值

    var b = 1
    

    通常我们认为它声明了b,并且为它赋值为1,var声明作用域函数执行的作用域。也就是说,var 会穿透for、if 等语句。

    在没有let的旧JavaScript时代,诞生了一个技巧,叫做:立即执行的函数表达式(IIFE),通过创建一个函数, 并且立即执行,来构造一个新的域,从而控制var的范围。

    由于语法规定了function 关键字开头是函数声明,所以要想让函数变成函数表达式,我们必须得加点东西,最常见的做法是加括号。

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

    但是,括号有个缺点,那就是如果上一行代码不写纷号,括号会被解释为上一行代码最末的函数调用,产生完全不符合预期,并且难以调试的行为,加号等运算符也有类似的问题。所以一些推荐不加分号的代码风格规范,会要求在括号前面加上分号。

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

    比较推荐的写法是用void关键字,即:

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

    let

    let 是 ES6 开始引入的新的变量声明模式
    let的作用域:

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

    Realm

    在最新的标准(9.0)中,引入了新的Realm概念,看个例子

    var b = {}
    

    在ES2016之前的版本中,标准中甚少提到{}的原型问题,但在实际的开发中,iframe等方式创建的window环境并非罕见的操作,所以就有了Realm

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

    以下代码展示了浏览器环境中获取来自两个Realm对象,它们跟本土的Object做instanceOf时会产生差异

    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
    

    参考原文:JavaScript执行(二):闭包和执行上下文到底是怎么回事?

    相关文章

      网友评论

        本文标题:【十二】JavaScript执行(二):闭包和执行上下文到底是怎

        本文链接:https://www.haomeiwen.com/subject/pfuquqtx.html