Javascript基础之-var,let和const深入解析(二)

你想在在变量声明之前就使用变量?以后再也别这样做了。

新的声明方式(let,const)较之之前的声明方式(var),还有一个区别,就是新的方式不允许在变量声明之前就使用该变量,但是var是可以得。请看下面的代码,下面这个代码是可以正常运行的:

    function func() {

      console.log(localVariable);  // undefined

      var localVariable = 5;


      console.log(localVariable);  // 5

    }


    func();

但是这种却不可以

    function func() {

      console.log(localVariable); // ReferenceError: localVariable is not defined

      let localVariable = 10;


      console.log(localVariable); // 10

    }


    func();

等下,我们上一章曾经介绍了一个叫“提升”的概念,它会吧所有的变量定义在作用域的最前面。这是否意味着如果我不在实际的定义之前使用变量,然后就不会有提升了呢?答案是否定的。提升依然会有,并且适用于所有类型的变量类型。但是const和let却不是这样的。

首先,我们看一下var关键字是怎么工作的。规范对其是这样进行的描述的。

> var声明定义了在正在运行的执行上下文(running execution

> context)作用域内的变量环境(VariableEnvironment中)的变量。var变量在当包含的词法环境(Lexical

> Environment)初始化时被创建,在创建的时候被赋值为undefined。[...]

> 在执行VariableDeclaration时,由带有Initializer的VariableDeclaration定义的变量被赋其设定项的Initializer's

> AssignmentExpression的值。

规范中有许多的细节,让我们简单的来看一下:

当你进入到一个作用域中,在内部被定义的所有的变量都会被创建。

所有存在的变量,都可以被访问,并且会把undefined赋值给该变量。

当代码(执行时)到达初始化时,会被分配给一个实际的值。

我们来看一下规范中对let和const的表述:

> let和const声明是定义在当前执行上下文作用域中的词法环境中的变量。当包含的词法环境被初始化的时候,变量被创建。但是在变量的词法绑定时被计算之前是不允许通过任何方式来访问的。当词法绑定计算时而不是在变量被创建的时候,由词法绑定定义的变量的初始值被被赋予赋值表达式的值(也就是“=”右边的表达式)。当词法绑定被计算的时候,如果let声明中没有初始化的值的时候(也就是“let

> a;”这样的形式),会被赋值为undefined。

简单来说:

如果你进入到了指定的作用域中,它里面定义的所有的变量都会被初始化,这一点和var很像。

这里有一个不同点:像var一样,所有的变量都会存在,但是他们目前还不能被访问(里面没有值,甚至是undefined)。

如果let变量在相同的地方被定义和初始化,他们会被赋予合适的值,反之,变量就是undefined。const变量必须在定义的时候初始化。

我们来看一些相关的例子。

## 临时死区

实际上,这种描述引出了我们的另一个定义。他很让人可怕,因为他叫:临时死区(TDZ)。这个属于明确了一个我们无法访问我们的变量的代码的区域。我们来看一下下面的代码和相关联的注释,来简单的解释一下TDZ是什么。

    function func() {

      // Start of TDZ for deadVariable

      // we can still do something here, just our deadVariable is not available yet

      const exampleVariable = 5;

      console.log(exampleVariable); // 5

      // End of TDZ for deadVariable

      let deadVariable = 10;


      console.log(deadVariable);  // 10

    }


    func();

有一件事情值得去提醒。就是对于名字的建议,这是一个临时死区,意思这个区域是由时间定义的,而不是位置。因此当运行代码的时候,你的声明在被JS解析器解析之前是不能被访问的。因此你把使用的变量的位置放在哪里并不重要,只要是在声明执行后访问该变量就可以。所以看下面的代码:

    function func() {

      return deadOrAlive;

    }


    let deadOrAlive = 'alive!'

    console.log(func());  // alive!

这是运行代码的步骤:

函数被声明

变量deadOrAlive被声明,并且初始化了一个值“alive”

现在我们调用我们的函数。

由于变量deadOrAlive已经被声明,是可访问的,因此会打印出正确的结果 “alive”。

但是下面的例子却会报错,思考一下原因。

    function func() {

      return deadOrAlive;

    }


    console.log(func());  // ReferenceError: deadOrAlive is not defined

    let deadOrAlive = 'dead!'

所以TDZ是一个避免因先使用后声明而导致的一些诡异的bug而出现的一个很好机制(具体看“提升”相关内容)。我们不需要去额外做什么事情,就是记住永远不要在变量声明之前使用这个变量。即使我们这样做了,我们也会得到一个很好的报错信息。只有一个条件-你必须使用let或者是const来替换掉var。

## 双定义

var和let,const的另一个区别是 - 后者仅仅可以被定义一次。而对于var的话,如果被同时定义多次,程序也依然会很好的运行。

    var doubledVariable = 5;

    var doubledVariable = 6;


    console.log(doubledVariable); // 6

但是现在,当你用let和const来做同样的事情,就会得到一个语法错误:

    let doubledVariable = 5;

    let doubledVariable = 6;  // SyntaxError: Identifier 'doubledVariable' has already been declared

但是,在嵌套的块级作用域中,使用相同名字的变量依然会很好的工作的,这个我想大家已经清楚了,就不用过多解释了吧。

    let doubledVariable = 5;


    if (true) {

      let doubledVariable = 6;

      console.log(doubledVariable); // 6

    }


    console.log(doubledVariable); // 5

不能重复定义这个功能实际上是很有用的,可以组织很多bug的发生。比如说你曾经在一个函数内,在不同地方用var定义了多个相同名称的变量,此时之前定义的变量可能会被覆盖,这样对于代码来说无疑是一个隐患,也就是因为这样,这个特性实际上是一个简单的,开箱即用的解决方案。

## 总结

总结一下,在ES6中有两种新方法来声明变量:通过let和const关键字,除此之外,两者都是块级作用域,并且在声明之前不能访问该变量。与之前的var相比是一个主要的升级。并且会消除你很多的困扰。我提出了几个例子,可能会帮助你节省了不少调试的时间,但是还有更多。如果你感兴趣的话,可以在网上简单的搜索一下。很久之前,我个人曾建议停止使用var关键字,所以现在我的代码里充满了let和const。我建议你也是这样,在以后当你想改变变量的值,就使用let和const。不要再使用var了。

本文翻译自:

https://blog.pragmatists.com/let-your-javascript-variables-be-constant-1633e56a948d

本文转载自:http://www.lht.ren/article/16/

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容