《ES6入门》学习笔记(一):let 和 const详解

210 阅读4分钟

在没有学到ES6之前,我们通常使用的都是var,来进行声明变量的. 有了ES6,我们声明变量的方式多了let和const这两种,这两种声明有什么好处呢?通过一些小例子来了解一下。

你将会涉及到以下的一个概念:

  • 没有变量提升
  • 不能重复定义
  • 暂时性死区
  • 块级作用域
  • const——"常量"

没有变量提升:

变量提升指的是在Javascript解析过程将一个变量声明部分提升到作用域最前的一种现象,比如说:

var tmp = new Date();
function f(){
    console.log(tmp);
    if(false){
        var tmp = 'helloworld';
    }
}(1.1)
f(); //undefined

这里我们原本期望的结果是输出一个当前时间,但是代码却是输出了一个undefined,如果仔细分析我前面对变量提升的定义,可以知道其实这里的代码是被解释成了另一副模样:

var tmp = new Date();
function f(){
    var tmp;
    console.log(tmp);
    if(false){
        tmp = 'helloworld';
    }
}(1.1)
f(); //undefined

相信不难看出,这里的变量赋值语句被拆分成了两个部分,声明部分直接提升到了函数的最前面,从而导致了tmp输出出来是undefined(tmp当时还未被赋值)。 就这样子,没有类似概念的开发者就很觉得很困惑(懵逼..),完全不知道为什么会这样子。

变量的提升会造成开发中无可预知的一些错误,因为他不会报错。

这也是ES6中letconst出现的原因之一: 没有变量提升~它哪也不会去,就是这样恪守自己的岗位!

不能被重复定义:

这点也是从代码的规范上进行考虑设计的,一个变量只允许被定义一次,这也同样是个不可预知的错误

var可以重复的定义一个变量,如果没有良好的代码习惯,可能一个变量会在不知觉的情况下被重复的定义或者说被其他的命名空间所污染(有可能你需要引入的文件当中就有相同的变量名),那结果就会很糟糕。

在使用letconst重复声明的时候,它会引导你形成良好的编码习惯,只要在定义的地方就会形成一个暂时性的死区,只要在定义的地方,前面都不容许再次出现一个同名的变量,就像下面这样:

let a;
let a;

uh-oh~报错了!

Uncaught SyntaxError: Identifier 'a' has already been declared

这里时刻都要注意到暂时性死区这个概念,这意味着不管你是在什么地方定义的,不管贫穷富贵,只要当前的作用域能够获取的到同名的变量,这个暂时性死区都会生效(报错).

function f(tmp){
    let tmp = 'hhhhh';
    console.log(tmp)
}
f(1);
Uncaught SyntaxError: Identifier 'tmp' has already been declared

就是这样绝情...

要问如何避免他们的报错,那很简单!只需要将他们隔开就好,这时候就涉及到了块级作用域的概念了。

块级作用域:

块级作用域相信接触过其他语言的开发者都了解过,Javascript这样的脚本语言就没有这样的特性,块级作用域只需要用{}就可以划分了,被{}括住的代码将会形成一个新的作用域,与其他上下文隔绝开来。以上一节代码为例:

function f(tmp){
{let tmp = 'hhhhh'}
    console.log(tmp)
}
f(1);// 1

就是这样子,他成功的输出了数字1,块级作用域内的变量不会被获取到。 当然这样的使用在实际开发中不常见,这样仅仅是说明了ES6开始就有了块级作用域的概念了。

const——"常量":

这里的“常量”,总会让人简单地以为就是一个变量内容不可修改, 但这里它本质很少被人所探寻,所谓的不可修改其实说的就是它的指针。指针需要唠一唠: 在赋值一个变量的过程当中,其实底层在幕后为我们做了一些事情,比如:

var a = 1, 它会先将1这个值,存入到内存一个独有的空间里,然后再让a指向这个内存地址,那么这样的一个过程可以说是形成了指针了。(捂脸..)

而重新另赋一个值的过程就会对指针进行修改,这就是‘不可修改’的原因,但是对于复杂的数据结构可能就不会适用了,如下例:

const foo = {};

// 为 foo 添加一个属性,可以成功
foo.prop = 123;
foo.prop // 123

// 将 foo 指向另一个对象,就会报错
foo = {}; // TypeError: "foo" is read-only

如果是对象的话,仅仅是增加和修改属性并不会修改它的指针,所以并不会报错

结尾:

好了,这是我对于let和const现有的理解,如果有哪位前辈看到了,劳请补充指教下,非常感激~

希望未来能跟前辈们一样优秀!