ES6标准入门之 let与const

var用的好好的,为甚es6要出let和const去替换var呢?

当然是为自己曾经犯下的错误买单!

在讲解es6之前,我们必须要提一下es5中的var,也就是曾经的那个错误。

if (condition) {

    var value = 1;

}

console.log(value);

很简单的分析一下,初学者可能会认为,只有在condition为true的时候,value才会被赋值,如果condition为false的时候,代码应该会报错才对!但是,事实并不是这样的,浏览器在执行这段代码的时候,并不是这么解析的!

var value;

if (condition) {

    value = 1;

}

console.log(value);

这样,很容易我们就能判断出,如果condition的值为false的时候,console出来的值为undefined。

原因就是我们常说的,变量提升。

为了加强对变量生命周期的控制,ECMAScript 6 引入了块级作用域。

块级作用域存在于:

       1.函数内部

        2.块中(字符 { 和 } 之间的区域)

引出我们今天的主角—let和const

let 和 const 都是块级声明的一种。

let和const的特点:

1.不会被提升(真的是这样的吗?)

if ( condition ) {

    let value = 1;

}

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


在代码块外面访问,直接判定,为定义。

2.重复声明报错

var value = 1;

let value = 2; // Uncaught SyntaxError: Identifier 'value' has already been declared

这在以前是完全可以的,后定义的回覆盖以前的。

3.不绑定全局作用域

let value = 1 ;

console.log(window.value);

const也是相同的,都访问不到。

const和let的区别:

const 用于声明常量,其值一旦被设定不能再被修改,否则会报错。

值得一提的是:const 声明不允许修改绑定,但允许修改值。这意味着当用 const 声明对象时:

const data = {

    value: 1

}

// 没有问题

data.value = 2;

data.num = 3;

// 报错

data = {}; // Uncaught TypeError: Assignment to constant variable.

临时死区

临时死区(Temporal Dead Zone),简写为 TDZ。

let 和 const 声明的变量不会被提升到作用域顶部,如果在声明之前访问这些变量,会导致报错。

console.log(typeof value); // Uncaught ReferenceError: value is not defined

let value = 1;

来个例子?

var value = "global";

// 例子1

(function() {

    console.log(value);

    let value = 'local';

}());

// 例子2

{

    console.log(value);

    const value = 'local';

};


结果是:都报错了!!!

这是因为 JavaScript 引擎在扫描代码发现变量声明时,要么将它们提升到作用域顶部(遇到 var 声明),要么将声明放在 TDZ 中(遇到 let 和 const 声明)。访问 TDZ 中的变量会触发运行时错误。只有执行过变量声明语句后,变量才会从 TDZ 中移出,然后方可访问。

循环中的块级作用域

var funcs = [];

for (var i = 0; i < 3; i++) {

    funcs[i] = function () {

        console.log(i);

    };

}

funcs[0](); // 3

如何改变现状呢?我要的是funcs[0]() == 0

在没有es6 之前,这个事儿麻烦了,还得使用闭包的方式!

var funcs = [];

for (var i = 0; i < 3; i++) {

    funcs[i] = (function(i){

        return function() {

            console.log(i);

        }

    }(i))

}

funcs[0](); // 0

ES6 的 let 为这个问题提供了新的解决方法:

var funcs = [];

for (let i = 0; i < 3; i++) {

    funcs[i] = function () {

        console.log(i);

    };

}

funcs[0](); // 0


问题在于,上面讲了 let 不提升,不能重复声明,不能绑定全局作用域等等特性,可是为什么在这里就能正确打印出 i 值呢?

如果是不重复声明,在循环第二次的时候,又用 let 声明了 i,应该报错呀,就算因为某种原因,重复声明不报错,一遍一遍迭代,i 的值最终还是应该是 3 呀,还有人说 for 循环的 设置循环变量的那部分是一个单独的作用域,就比如:

for (let i = 0; i < 3; i++) {

  let i = 'abc';

  console.log(i);

}

// abc

// abc

// abc

这个例子是对的,如果我们把 let 改成 var 呢?

for (var i = 0; i < 3; i++) {

  var i = 'abc';

  console.log(i);

}

// abc

经查, for 循环中使用 let 和 var,底层会使用不同的处理方式。

简单的来说,就是在 for (let i = 0; i < 3; i++) 中,即圆括号之内建立一个隐藏的作用域,这就可以解释为什么:

for (let i = 0; i < 3; i++) {

  let i = 'abc';

  console.log(i);

}

// abc

// abc

// abc

然后每次迭代循环时都创建一个新变量,并以之前迭代中同名变量的值将其初始化。

var funcs = [];

for (let i = 0; i < 3; i++) {

    funcs[i] = function () {

        console.log(i);

    };

}

funcs[0](); // 0

相当于:

// 伪代码

(let i = 0) {

    funcs[0] = function() {

        console.log(i)

    };

}

(let i = 1) {

    funcs[1] = function() {

        console.log(i)

    };

}

(let i = 2) {

    funcs[2] = function() {

        console.log(i)

    };

};

到此,我们就讲完了吗?没有,并没有,上面还有个提升的问题么!

首先明确一点:提升不是一个技术名词。

要搞清楚提升的本质,需要理解 JS 变量的「创建create、初始化initialize 和赋值assign」

假设有如下代码:

function fn(){

  var x = 1

  var y = 2

}

fn()

在执行 fn 时,会有以下过程(不完全):

进入 fn,为 fn 创建一个环境。

找到 fn 中所有用 var 声明的变量,在这个环境中「创建」这些变量(即 x 和 y)。

将这些变量「初始化」为 undefined。

开始执行代码

x = 1 将 x 变量「赋值」为 1

y = 2 将 y 变量「赋值」为 2

也就是说 var 声明会在代码执行之前就将「创建变量,并将其初始化为 undefined」。

这就解释了为什么在 var x = 1 之前 console.log(x) 会得到 undefined。

接下来来看 function 声明的「创建、初始化和赋值」过程

假设代码如下:

fn2()

function fn2(){

  console.log(2)

}

JS 引擎会有一下过程:

找到所有用 function 声明的变量,在环境中「创建」这些变量。

将这些变量「初始化」并「赋值」为 function(){ console.log(2) }。

开始执行代码 fn2()

也就是说 function 声明会在代码执行之前就「创建、初始化并赋值」。

接下来看 let 声明的「创建、初始化和赋值」过程

假设代码如下:

{

  let x = 1

  x = 2

}


我们只看 {} 里面的过程:

找到所有用 let 声明的变量,在环境中「创建」这些变量

开始执行代码(注意现在还没有初始化)

执行 x = 1,将 x 「初始化」为 1(这并不是一次赋值,如果代码是 let x,就将 x 初始化为 undefined)

执行 x = 2,对 x 进行「赋值」

这就解释了为什么在 let x 之前使用 x 会报错:

let x = 'global'

{

  console.log(x) // Uncaught ReferenceError: x is not defined 

  let x = 1

}


原因有两个:

1.console.log(x) 中的 x 指的是下面的 x,而不是全局的 x

2.执行 log 时 x 还没「初始化」,所以不能使用(也就是所谓的暂时死区)

看到这里,你应该明白了 let 到底有没有提升:

let 的「创建」过程被提升了,但是初始化没有提升。

var 的「创建」和「初始化」都被提升了。

function 的「创建」「初始化」和「赋值」都被提升了。

最后看 const,其实 const 和 let 只有一个区别,那就是 const 只有「创建」和「初始化」,没有「赋值」过程。

这四种声明,用下图就可以快速理解:

所谓暂时死区,就是不能在初始化之前,使用变量。

至此,我们结束今天的分享...

引用:https://juejin.im/post/5b0238f66fb9a07aca7a74ba

           https://zhuanlan.zhihu.com/p/28140450

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

推荐阅读更多精彩内容