资讯专栏INFORMATION COLUMN

深入理解ES6 - var-let-const

alexnevsky / 3144人阅读

摘要:声明变量不存在变量提升。临时死区,而且不能在声明之前访问它。禁止重复声明相同的变量,否则报错。不存在变量提升,一旦执行快外就会立即销毁。声明不允许修改绑定,但允许修改值,也就是说用创建对象后,可以修改该对象的属性值。

知识点
var 声明变量:
1、存在变量提升,实际上var无论在哪里声明,都会被当做当前的作用域顶部声明变量。
2、可以重复声明,后声明的变量会覆盖前声明的变量。
let 声明变量:
1、不存在变量提升。
2、禁止重复声明。
3、块级作用域,只在当前作用域块有用。
4、临时死区,而且不能在声明之前访问它。
const声明常量:
1、const 声明的是常量,其值一旦确定后不可以修改
2、const 声明常量时候必须要进行赋值
3、const 不存在变量提升,一旦执行快外就会立即销毁。
4、const 只能在当前代码块级有效,
5、const 不能重复声明相同常量。
6、const声明不允许修改绑定,但允许修改值,也就是说用const创建对象后,可以修改该对象的属性值。
一、声明JavaScript的变量有哪些?

每种编程语言都有变量,声明变量的方法各不同,在JavaScript里面,最经典的var声明一个变量,当ECMAScript6出现后,新增了2个声明变量的方法:let和const,那何时创建变量,用什么声明变量方法会更好呢?

二、先谈谈var声明及变量提示(hoisting)机制

var声明一个变量时候,只需要 var name; 或者声明赋值var name = "Bob";

实际上var无论在哪里声明,都会被当做当前的作用域顶部声明变量。

(1)什么是变量提示机制?
// var 的变量提升机制
function getValue(condition) {
    if (condition) {
        var values = "Bob";
        return values;

    } else {
        console.log(values); // 这里访问到values 是undefined,原因下面解释:
        return null;
        
    }
}


// 原因解释:为什么上面的代码else还能访问values的值,虽然是undefined
// 无论变量values都会被创建,在编译过程中,JavaScript引擎会将上面的getValue函数修改成这样:
function getValue(condition) {

    // 重点看这里,变量values的声明被提升到函数顶部
    var values;

    if (condition) {
        values = "Bob";
        return values;

    } else {
        console.log(values); // 所以这里访问到是声明过的但未赋值的values,所以是undefined。
        return null;
        
    }
}
三、块级声明的出现

块级声明用于声明在指定的块的作用域之外无法访问的变量

函数内部

块级中(字符{ }之间的区域)

四、let声明

let声明变量和var声明变量,但let有自己的四个特征:

块级作用域,限制在当前的块级作用域中,外面作用域无法访问。

不存在变量提升。

临时死区,而且不能在声明之前访问它。

禁止重复声明相同的变量,否则报错。

我们可以把刚才聊到的getValue函数修改一下:

// let 块级作用域 && 不存在变量提升
function getValue(condition) {
    if (condition) {

        // 使用let声明变量
        let values = "Bob";
        return values;

    } else {
        console.log(values); // 这里报错: ReferenceError: values is not defined..
        // 原因就是用let声明的变量,是不存在变量提升的,
        // 而且values变量只能在if{ 这个作用块里面有效 } 外面是访问不到的
        // 同时,在外面访问不仅会访问不到,而且会报错

        return null;

    }
}


// let 禁止重复声明相同变量
function getValue() {
    var values = "Bob";
    let values = {name: "Bob"};
    
    // 使用let声明变量禁止重复声明已经有的变量名
    // 否则报错:SyntaxError: Identifier "values" has already been declared
}
五、const声明

const 声明的是常量,其值一旦确定后不可以修改。

const 声明常量时候必须要进行赋值。

const 不存在变量提升,一旦执行快外就会立即销毁。

const 只能在当前代码块级有效,

const 不能重复声明相同常量。

const声明不允许修改绑定,但允许修改值,也就是说用const创建对象后,可以修改该对象的属性值。

function getValue() {
    // 声明一个常量
    const USER_NAME = "梁凤波";

    // 禁止重复声明相同常量,否则报错:TypeError: Assignment to constant variable.
    // const USER_NAME = "Bob";
    
    // 记住:const声明不允许修改绑定,但允许修改值,
    // 也就是说用const创建对象后,可以修改该对象的属性值
    const STUDYENT = {
        name: "梁凤波"
    };

    console.log(`STUDYENT.name =  ${STUDYENT.name}`); // STUDYENT.name =  梁凤波

    STUDYENT.name = "Bob";
    console.log(`STUDYENT.name =  ${STUDYENT.name}`); // STUDYENT.name =  Bob
}
拓展:循环中的块级作用域绑定
访问for循环后的结果
// 在for循环内用var 声明,在外面访问到的是for循环后的结果
for (var i = 0; i < 10; i++) {
}
console.log(`i = ${i}`); // i = 10

// 在for循环内用let 声明,在外面 访问不到,块级作用域问题
for (let i = 0; i < 10; i++) {
}
console.log(`i = ${i}`); // ReferenceError: i is not defined
循环中的var声明
// 经过for循环后,在外面访问i,是直接访问到了结果i = 10

let funcs = [];
for (var i = 0; i < 10; i++) {
    funcs.push(function () {
        console.log(i);
    })
}

funcs.forEach(func => {
    func() // 分别输出10次10
});

原因:循环里每次迭代同时共享着变量i,循环内部创建的函数全保留相同变量的引用,循环结束时候i的值变为10,所以每次调用console.log(i)时候回输出数字10

为了解决这个问题,可以在循环中使用立即调用函数表达式(IIFE),以强制生成计数器变量的副本:

使用var达到理想状态
// 如果要理想效果,在外面分别输出 0 ~ 9,
// 可以使用闭包暴露出去
let funcs = [];
for (var i = 0; i < 10; i++) {
    funcs.push((function (val) {
        return function () {
            console.log(val);
        }
    }(i)))
}

funcs.forEach(func => {
    func()
});
循环中的let声明
let funcs = [];
for (let i = 0; i < 10; i++) {
    funcs.push(function () {
        console.log(i);
    })
}

funcs.forEach(func => {
    func() // 分别输出 0 ~ 9
});

let 声明模仿上述示例IIFE所做的一切简化循环过程,每次迭代循环都会创建一个新变量,并以之前迭代中同名变量的值将其初始化。

循环中的const声明
let funcs = [];
let obj = {
    a: true,
    b: true,
    c: true
}

for (const key in obj) {
    funcs.push(function () {
        console.log(key);
    })
}

funcs.forEach(func => {
    func() // 分别输出 a, b, c Authorization
});

let和const声明循环,const循环是不能改变key的值,const 循环应该使用for-in,for-of,其他和let示例一样,因为每次迭代不会像var循环例子一样修改已有的绑定,而是会创建一个新绑定。

全局块级作用域绑定
var RegExp = "Bob";

// 即使是全局对象RegExp定义在window,也不能幸免被var声明覆盖
console.log(RegExp); // Bob
console.log(window.RegExp); // Bob

let RegExp = "Bob";

// 用let或const声明不能覆盖全局变量,而只能屏蔽它
console.log(RegExp); // Bob
console.log(window.RegExp); // undefined
console.log(window.RegExp === RegExp); // false

const ncz = "Hi!"
console.log("ncz" in window); // false
最后聊一聊块级绑定的最佳实践

默认使用const,只在确实需求改变变量的值使用let,这样就可以在某种程度上实现代码的不可变,从而防止默写错误产生。

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

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

相关文章

  • 一些当前 Node.js 中最流行 ES6 特性的 benchmark (V8 / Chakra)

    摘要:前言项目地址如果有想要增加的特性,欢迎更新,然后。环境大致结论许多情况下下的特性表现相对更好。 前言 项目 github 地址:https://github.com/DavidCai1993/ES6-benchmark 如果有想要增加的特性 benchmark ,欢迎更新benchmarks/ ,然后 PR 。 环境 CPU: Intel Core(TM) i5-2410M 2.30...

    ZHAO_ 评论0 收藏0
  • ES6-7

    摘要:的翻译文档由的维护很多人说,阮老师已经有一本关于的书了入门,觉得看看这本书就足够了。前端的异步解决方案之和异步编程模式在前端开发过程中,显得越来越重要。为了让编程更美好,我们就需要引入来降低异步编程的复杂性。 JavaScript Promise 迷你书(中文版) 超详细介绍promise的gitbook,看完再不会promise...... 本书的目的是以目前还在制定中的ECMASc...

    mudiyouyou 评论0 收藏0
  • 深入理解ES6》笔记——导读

    摘要:最近买了深入理解的书籍来看,为什么学习这么久还要买这本书呢主要是看到核心团队成员及的创造者为本书做了序,作为一个粉丝,还是挺看好这本书能给我带来一个新的升华,而且本书的作者也非常厉害。 使用ES6开发已经有1年多了,以前看的是阮一峰老师的ES6教程,也看过MDN文档的ES6语法介绍。 最近买了《深入理解ES6》的书籍来看,为什么学习ES6这么久还要买这本书呢?主要是看到Daniel A...

    Godtoy 评论0 收藏0
  • Understanding ES6 -- 深入理解ES6书籍

    摘要:块级绑定拓展对象功能解构改进的数组代理和反射附录小的改变附录 understanding es6 -- Nicholas C. Zakas 块级绑定 function 拓展对象功能 解构 symbol Sets and Maps Iterators and Generators class 改进的数组 promise 代理和反射 -- Proxy&Reflection mo...

    PAMPANG 评论0 收藏0

发表评论

0条评论

alexnevsky

|高级讲师

TA的文章

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