ES6学习笔记(1,let和const)

在介绍let和const之前我们先复习一下相关的知识点。

关于函数作用域

开发过程中,在ES6(ECMA2015)标准推出之前,声明变量的方式一直都是var,而变量的作用域一般也只在函数内部,即函数作用域。

function a () {
    var test = 1;
}
console.log(test); //error, test is not defined

上面的实例反应了当我们定义在函数a中定义变量test的时候,其作用域只在a函数中,在函数a外面访问test,则会抛错。

关于变量提升

在javascript中,使用var声明的变量,不论是在什么地方声明的,都会提升到当前作用域的最顶部进行初始化,这种行为叫做变量提升

function test() {
    console.log('1:', a);   //undefined
    if (false) {
        var a = 1;
    }
    console.log('2:', a);   //undefined
}
test();

关于上面的代码,两次访问a都是undefined,说明在作用域中实际上是能访问到a的,只不过未赋值,即使判断语句是false,第一个日志访问的a也不是is not defined,出现这种情况的原因实际上就是因为变量提升。
把上面的代码翻译成浏览器真正执行的代码实际上是:

function test() {
    // 变量提升,对a进行初始化,但未赋值
    var a;
    console.log('1:', a); //undefined
    if (false) {
        a = 1; 
    }
    console.log('2:', a); //undefined
} 

由于变量提升的关系,因此在es6标准推出之前,javascript中实际上只有函数作用域,而没有块作用域({}),这里的块作用域可以简单的看做用{}包起来的代码。

let

let和const都能够声明块作用域,用法和var是类似的,特别都不会进行变量提升,而是被锁在当前的代码块中。

function test() {
    if (true) {
        console.log(a); // TDZ,俗称临时死区,用来描述变量不提升的现象
        let a = 1;
    }
}
test(); // a is not defined
function test() {
    if (true) {
        let a = 1;
    }
    console.log(a);
}
test(); // a is not defined

上面的两个例子都用let进行变量声明,第一个例子反映出来let声明的变量是不会出现变量提升现象的,而第二个例子说明let声明的变量只在块作用域中生效,那么正确的使用方法应该是:在块作用域中,先声明,在访问

function test() {
    if (true) {
        let a = 1;
        console.log(a);
    }
}
test() // a

const

const和let类似,用来声明常量,不过和let的区别则是,一旦声明则不可以更改,而且必须进行初始化赋值。下面的例子很清楚来说明这一点。

const type = 'aaa';
type = 'bbb';
console.log(type); // "type" is read-only

const type;
type = 'aaa';
console.log(type); // Missing initializer in const declaration

我们再来看看下面这个例子

const type = 'aaa';
let type = 'bbb';
console.log(type); // Identifier 'type' has already been declared

同样出现的报错,实际上我们不论是使用const 还是 let都不能这样重复声明相同名称的变量,但是使用var是可以的,原因可以简单的理解为因为变量提升的存在,导致声明只有一次,赋值有两次。
const最重要的特点是一点声明,不可以修改,但是假如定义的是对象Object,那么可以修改对象内部的属性值,原因是因为当我们修改对象内部的属性值的时候对象的内存地址实际上是没有变化的,但是假如我们直接修改对象本身,则会出现报错,在这种情况下需要使用let。

const type = {
    a: 1,
}

type.a = 2 //没有直接修改type值,对象的指针不变,只是修改了type.a的属性值,这是允许的。
console.log(type) // {a: 2}

type = { // 直接修改type本身,对象的内存地址会发生变化,不允许。
    a: 2,
}
console.log(type) // Identifier 'type' has already been declared

const 和 let 的异同点。

相同点:

  • const和let都只在当前的块作用域内有效
  • 不存在变量提升
  • 不能重复声明
    不同点:
  • const不能再赋值,let可以再赋值

临时死区(TDZ)

上面我们已经提到了TDZ的场景,那么,有什么用呢?答案就是没什么用。可以理解为一个便于说明的定义。
临时死区的意思是在当前作用域的块内,在声明变量前的区域叫做临时死区。

if (true) {
    // 这块区域是TDZ
    let a = 1;
}

块级作用域的使用场景

块级作用域有哪些使用场景呢?
在for循环中使用var声明的循环变量,会跳出循环污染当前的函数作用域

for (var i = 0; i < 5; i++) {
    setTimeout(() => {
        console.log(i); // 5, 5, 5, 5, 5
    }, 0);
}
console.log(i) // 5, i跳出了循环污染当前函数作用域

for (let i = 0; i < 5; i++) {
    setTimeout(() => {
        console.log(i); // 0, 1, 2, 3, 4
    }, 0);
}
console.log(i) // i is not defined i无法污染外部函数

全局作用于声明

如果在全局作用域使用let或者const声明,那么声明的变量本身就是全局变量,并不会挂在window下

let a = 1;
var b = 2;
console.log(a); // 1
console.log(window.a) // undefined
console.log(b); // 2
console.log(window.b) // 2

实践

在实际开发中,我们是使用var, let, 还是const取决于变量是否需要更新,不更新的变量用const,更新的变量用let。var能用的场景都可以使用let来替代,但是需要注意作用域的区别。

posted @ 2017-08-18 10:56  生姜可乐  阅读(310)  评论(0编辑  收藏  举报