资讯专栏INFORMATION COLUMN

JS 中 TDZ 的理解

stackvoid / 2610人阅读

摘要:由于当时我本身也还不知道这一回事没有看懂,所以就花了一些时间去搞清楚什么是及会带来一些什么问题,本文主要是用于介绍我对的一些理解,如有问题,多谢指出。

原文链接:https://acrens.github.io/2017/01/22/2017-01-22-TDZ/
春节快到了,假期也快到了,空闲之余刷个微博,看见 @ruanyf 提出了一个问题与 TDZ 有关,但是貌似阮大当时还没有意识到这个问题,多亏一些其他业内同仁提出了与 TDZ 相关;当然,以阮大的能力这都不是事。由于当时我本身也还不知道 TDZ 这一回事没有看懂,所以就花了一些时间去搞清楚什么是 TDZ 及TDZ会带来一些什么问题,本文主要是用于介绍我对 TDZ 的一些理解,如有问题,多谢指出。

示例

案例一

代码

let y = 1;
function foo(x = y, y) {
    console.log(x);
}
foo();  // ReferenceError: y is not defined

解读

当函数存在默认参数时,且调用方法不传任何参数,会存在三个作用域环境;

全局作用域、参数作用域、函数体作用域;

当执行 foo 函数时,参数作用域在 x = y 之后才定义 let y,注意:let 定义,所以根据 let 定义变量的作用知道 x = y 肯定会报错;

代码翻译:将以上代码翻译之后可以按下面代码片段阅读更易于理解

function analysis() {
    "use strict";
    let y = 1;

    function foo() {  
        let x = arguments[0] !== (void 0) ? arguments[0] : y;   // y not defined
        let y = arguments[1];
    }
    foo();

    return {};
}

案例二

代码

let y = 1;
function foo(x = function(){console.log(y)}, y = 2) {
    x(); // 2
    y = 3;
    x(); // 3
}
foo();
console.log(y); //1

解读

当函数存在默认参数时,且调用方法不传任何参数,会存在三个作用域环境;

全局作用域、参数作用域、函数体作用域;

当执行 foo 函数时,x 被申明为匿名函数变量,此时函数并未被执行,所以正常;之后定义 y 值为 2,此时调用 x() 输出的当然是变量 y 的值,之后继续修改 y 的值,再继续调用 x(),输出 y 最新值 3;当执行外部 console.log(y) 时并不能访问内部函数变量,访问的变量是当前域下的 y = 1 的值 1,所以输出 1;

代码翻译:将以上代码翻译之后可以按下面代码片段阅读更易于理解

function analysis() {
    "use strict";
    let y = 1;

    function foo() {  
        let x = arguments[0] !== (void 0) ? arguments[0] : function() {
            console.log(y);
        };
        let y = arguments[1] !== (void 0) ? arguments[1] : 2;
        x(); // 2
        y = 3;
        x();    // 3
    }
    foo();
    console.log(y); // 1

    return {};
}

案例三

代码

let y = 1;
function foo(x = function(){console.log(y)}) {
    let y = 3;
    x(); // 1
}
foo();

解读

当函数存在默认参数时,且调用方法不传任何参数,会存在三个作用域环境;

全局作用域、参数作用域、函数体作用域;

当执行 foo 函数时,x 被赋值为一个匿名函数的变量,且存在与参数作用域内,let y = 3 会被定义到函数体作用域内,属于参数作用域的内部函数;当 x() 执行时是在函数体作用域定被调用,但是其定义是在参数作用域,所以执行环境是在参数作用域内,此时在参数作用域没有定义 y 变量,也不能访问内部函数 funBody 内部定义的变量 y,此时往上级函数查找是否存在 y 被定义,如果被定义则输出其值,所以输出最外层变量 y 的值 1;

代码翻译:将以上代码翻译之后可以按下面代码片段阅读更易于理解

function analysis() {
    "use strict";
    let y = 1;

    function foo() {  
        let x = arguments[0] !== (void 0) ? arguments[0] : function() {
            console.log(y);
        };

        function funBody() {
            let y = 3;
            x();
        }
        funBody();
    }
    foo();

    return {};
}

案例四

代码

function foo(x = function(){console.log(y)}) {
    let y = 3;
    x(); // // ReferenceError: y is not defined
}
foo();

解读

当函数存在默认参数时,且调用方法不传任何参数,会存在三个作用域环境;

全局作用域、参数作用域、函数体作用域;

当执行 foo 函数时,x 被赋值为一个匿名函数的变量,且存在与参数作用域内,let y = 3 会被定义到函数体作用域内,属于参数作用域的内部函数;当 x() 执行时是在函数体作用域定被调用,但是其定义是在参数作用域,所以执行环境是在参数作用域内,此时在参数作用域没有定义 y 变量,也不能访问内部函数 funBody 内部定义的变量 y,此时往上级函数查找是否存在 y 被定义,如果被定义则输出其值,否则报 y 没有被定义错误,此案例只是案例三的一种测试;

代码翻译:将以上代码翻译之后可以按下面代码片段阅读更易于理解

function analysis() {
    "use strict";
    function foo() {  
        let x = arguments[0] !== (void 0) ? arguments[0] : function() {
            console.log(y);
        };

        function funBody() {
            let y = 3;
            x();
        }
        funBody();
    }
    foo();

    return {};
}

参考

以上核心部分在代码翻译部分,通过配合一下资料及个人的理解,翻译出通俗易懂的代码:

https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/let#Temporal_dead_zone_and_errors_with_let;

http://dmitrysoshnikov.com/ecmascript/es6-notes-default-values-of-parameters/#tdz-temporal-dead-zone-for-parameters;

https://github.com/google/traceur-compiler/issues/1604。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/81315.html

相关文章

  • 理解ES6暂时死区(TDZ)

    摘要:以英文名词来说明,是时间的暂时的意义,则是死区,意指电波达不到的区域。所以可以翻为时间上暂时的无法达到的区域,简称为时间死区或暂时死区。以声明的变量或常量,必需是经过对声明的赋值语句的求值后,才算初始化完成,创建时并不算初始化。 Temporal Dead Zone(TDZ)是ES6(ES2015)中对作用域新的专用语义。TDZ名词并没有明确地写在ES6的标准文件中,一开始是出现在ES...

    Mike617 评论0 收藏0
  • 深入理解let和var区别(暂时性死区)!!!

    摘要:会出现这样的情况是因为拥有暂时性死区。规定暂时性死区和语句不出现变量提升,主要是为了减少运行时错误,防止在变量声明前就使用这个变量,从而导致意料之外的行为。 首先我们应该知道js引擎在读取js代码时会进行两个步骤: 第一个步骤是解释。 第二个步骤是执行。 所谓解释就是会先通篇扫描所有的Js代码,然后把所有声明提升到顶端,第二步是执行,执行就是操作一类的。 我们先来看个简单的变量提升...

    tanglijun 评论0 收藏0
  • 深入理解ES6笔记(一)块级作用域绑定

    摘要:和都能够声明块级作用域,用法和是类似的,的特点是不会变量提升,而是被锁在当前块中。声明常量,一旦声明,不可更改,而且常量必须初始化赋值。临时死区临时死区的意思是在当前作用域的块内,在声明变量前的区域叫做临时死区。 主要知识点有:var变量提升、let声明、const声明、let和const的比较、块级绑定的应用场景showImg(https://segmentfault.com/img...

    马忠志 评论0 收藏0
  • 深入理解ES6之《块级作用域绑定》

    摘要:众所周知,中的声明存在变量提升机制,因此引用了块级作用域来强化对变量生命周期的控制声明不会被提升,有几个需要注意的点不能被重复声明假设作用域中已经存在某个标识符无论该标识符是通过声明还是变量声明,此时再使用或关键定声明会抛错此处则会抛出错误 众所周知,js中的var声明存在变量提升机制,因此ESMAScript 6引用了块级作用域来强化对变量生命周期的控制let const 声明不会被...

    Nosee 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<