文档章节

let和const命令 — 学习ES6(一)

XuePeng77
 XuePeng77
发布于 2017/05/10 08:38
字数 1173
阅读 16
收藏 0

1.let命令

基本用法

ES6新增了一个let命令,用于声明变量,与var命令用法类似,但是用let声明的变量只在let命令所在的代码块有效。

    {
        let name = "abc";
        var age = 18
    }
    console.log(name);
    console.log(age);

 

上面的代码在代码块中,分别用let和var定义了两个变量,在代码块外,可以打印出用var声明的age,但是打印不出用let声明的name。这表明,用let声明的变量只在其所在的代码块中有效。

for循环现在就很适合使用let命令了。

    {
        let arr = [];
        for (let i = 0, len = arr.length; i < len; i++) {
        }
    }

另外,使用let命令可以解决之前的闭包问题。

    var a = [];
    for (var i = 0; i < 10; i++) {
        a[i] = function () {
            console.log(i);
        };
    }
    a[6]();  // 10

上面代码用var声明了变量i后,是在全局范围内都有效的。所以每一次循环,新的i都会覆盖之前的旧值,导致最后输出的是最后一个i的值。

在ES6以前,解决方式通常是采用闭包的方式。

    var a = [];
    for (var i = 0; i < 10; i++) {
        (function (i) {
            a[i] = function () {
                console.log(i);
            }
        })(i);
    }
    a[6](); // 6

现在有了let命令,可以不再使用闭包方式解决该问题,直接通过let声明变量i就可以达到该效果。

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

上面的代码用let声明了i变量,当前的i只在本轮循环有效,所以每一次循环的i都是一个新的变量,最后输出的是6。

不存在变量提升

let命令声明的变量不会像用var声明的一样,发生“变量提升”的现象。所以,变量一定要在声明后使用。

    console.log(name); // abc
    var name = 'abc';

    console.log(name); // ReferenceError: can't access lexical declaration `name' before initialization
    let name = 'abc';

暂时性死区(temporal dead zone, TDZ)

只要块作用于中存在let命令声明的变量,该变量就“绑定”在这个块级作用域中,不再受外部声明的变量影响。

    var name = 'abc';
    {
        name = 'jack';
        let name;
    }
    // ReferenceError: can't access lexical declaration `name' before initialization

上面的代码先声明了name,又在块级作用域中用let声明了name,导致后者绑定了这个作用域,所以在let声明name前,对name赋值会报错。

不允许重复声明

let不允许在相同的作用域内重复声明一个变量。

    function test() {
        let a = 10;
        let a = 20; // SyntaxError: redeclaration of let a
    }
    function test1() {
        let a = 10;
        var a = 30; // SyntaxError: redeclaration of let a
    }
    function test2(arg) {
        let arg; // SyntaxError: redeclaration of formal parameter arg
    }
    function test3(arg) {
        {
            let arg; // ok
        }
    }

上面代码中,前三个函数都报错了,因为在同一个作用域下存在对let声明的变量进行了重复用声明,而test3函数没有报错,因为不在同一个作用域中。

2.const命令

const用来声明常量。一旦声明,其值就不可以再改变。

    const PI = 3.14;
    PI = 3; // TypeError: invalid assignment to const `PI'

const与let一样,只在声明所在的作用域有效,也同样存在TDZ,只能在声明后使用,也不可以重复声明。

对于对象类型的变量,其声明不指向对象的数据,而是指向对象所在的地址。const命令只是保证变量名指向的地址不变,并不保证该地址下的数据不变。

    const user = {};
    user.name = 'jack';
    console.log(user.name); // jack

    user = {}; // TypeError: invalid assignment to const `user'

上面的代码中,常量user保存着一个对象地址,该对象本身是可变的,可以添加name属性,但是地址不可变,将user重新复制给一个地址会报错。

如果想使const声明的对象数据也不可变,可以使用Object.freeze方法冻结对象。

    const user = Object.freeze({
        name: 'jack'
    });

    console.log(user.name); // jack
    user.name = 'mark';
    console.log(user.name); // jack

上面的代码中,常量user所指向的对象被冻结,修改name属性无效,但是如果name属性指向的不是字符串,而是一个对象,该处理方式则无效。

    let role = {name: 'admin'};
    const user = Object.freeze({
        name: 'jack',
        role: role
    });

    console.log(user.name); // jack
    console.log(user.role.name); // admin
    user.name = 'mark';
    user.role.name = 'qa';
    console.log(user.name); // jack
    console.log(user.role.name); // qa

可以看到,user的role属性是个对象,而role的name属性仍然可以修改,想要解决这种情况,需要将对象的属性也冻结。

    let role = {name: 'admin'};
    const user = {
        name: 'jack',
        role: role
    };

    let constantize = (obj) => {
        Object.freeze(obj);
        Object.keys(obj).forEach((key, value) => {
            if (typeof obj[key] === 'object') {
                constantize(obj[key]);
            }
        });
    };

    constantize(user);

    console.log(user.name); // jack
    console.log(user.role.name); // admin
    user.name = "mark";
    user.role.name = "qa";
    console.log(user.name); // jack
    console.log(user.role.name); // admin

上面代码中,constantize是一个将对象彻底冻结的函数,调用该函数后,则user对象就彻底冻结了。

© 著作权归作者所有

XuePeng77
粉丝 45
博文 143
码字总数 192187
作品 0
丰台
私信 提问
ECMAScript6入门 学习之简介

1.什么是ECMAScript 6? ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准,已经在2015年6月正式发布了。它的目标,是使得JavaScript语言可以用来编写复杂的大型应用程序,成为企业...

w-rain
2016/06/12
711
0
ES6、ES7、ES8特性-学习提炼总结(一)

ES6 ECMAScript 6.0,简称ES6是JavaScript语言的下一代标准,在2015年6月发布。目的是让JavaScript语言可以用来编写复杂的大型应用程序,成为企业级开发语言。 Babel转码器 Babel是一个广泛使...

永远保留内心的简单和单纯
2018/11/22
0
0
ECMAScript 6教程 (一)

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出 原文连接,博客地址为 http://www.cnblogs.com/jasonnode/ 。该系列课程是汇智网 整理编...

笔阁
2015/07/20
0
0
ES6中let 和 const 的新特性

在javascript中,我们都知道使用var来声明变量。javascript是函数级作用域,函数内可以访问函数外的变量,函数外不能访问函数内的变量。 ECMAScript 6 是 JavaScript 语言教程,全面介绍 EC...

peakedness丶
2018/11/18
0
0
ES6走走看看—由块级作用域引出的一场变革

持续更新的github笔记,链接地址:Front-End-Basics 此篇文章的笔记地址:由块级作用域引出的一场变革 ES6走走看看系列,特别鸣谢奇舞读书会~ 块级作用域又称词法作用域,存在于: 函数内部(...

cfangxu
2018/09/07
0
0

没有更多内容

加载失败,请刷新页面

加载更多

阿里云POLARDB如何助力轻松筹打造5亿用户信赖的大病筹款平台?

轻松筹首创了“大病救助”模式,帮助了众多病患在第一时间解決了医疗资金等问题,为了从源头解决了医疗资金问题。而在轻松筹这样全球5.5亿用户信赖的大病筹款平台的背后,是日益增长的各种数...

阿里云云栖社区
4分钟前
1
0
Confluence 6 在升级过程中查看合并日志

为了监控升级的过程,你应该查看 application log 日志中的输出。 通常日志经常将会显示多个日志实例,这个实例是定义在日志的 INFO 级别的,通常格式如下: WikiToXhtmlMigrationThread-n -...

honeymoose
4分钟前
0
0
git diff 文件对比

git diff filepath 工作区与暂存区比较 git diff HEAD filepath 工作区与HEAD ( 当前工作分支) 比较 git diff --staged 或 --cached filepath 暂存区与HEAD比较 git diff branchName filepa......

李佳顺
5分钟前
0
0
spring mvc 定制化配置

spring mvc 自定义配置 1.实现某些接口,然后让上面的类加载进去. class MyHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver { @Override public boolean......

最爱肉肉
7分钟前
0
0
OSG_采样像机的内容如果不显示到窗口上

cameraLight->setRenderTargetImplementation(Camera::FRAME_BUFFER_OBJECT);// 这句使内容不渲染到屏幕上cameraLight->setRenderOrder(Camera::PRE_RENDER); 1.setRenderTargetImplement......

洛克人杰洛
11分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部