let 和 const 命令


学习资料:ECMAScript 6 入门

let

  • 所声明的变量,只在let命令所在的代码块内有效。用途:循环计数器。

如果使用var,只有一个全局变量i:

  1. var a = [];
  2. for (var i = 0; i < 10; i++) {
  3. a[i] = function () {
  4. console.log(i);
  5. };
  6. }
  7. a[6](); // 10

如果使用let,声明的变量仅在块级作用域内有效,JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算:

  1. var a = [];
  2. for (let i = 0; i < 10; i++) {
  3. a[i] = function () {
  4. console.log(i);
  5. };
  6. }
  7. a[6](); // 6

设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域:

  1. for (let i = 0; i < 3; i++) {
  2. let i = 'abc';
  3. console.log(i);
  4. }
  5. // abc
  6. // abc
  7. // abc
  • 不存在变量提升

let所声明的变量一定要在声明后使用:

  1. // var 的情况
  2. console.log(foo); // 输出undefined
  3. var foo = 2;
  4. // let 的情况
  5. console.log(bar); // 报错ReferenceError
  6. let bar = 2;
  • 暂时性死区

只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。所以需要先声明再使用:

  1. var tmp = 123;
  2. if (true) {
  3. tmp = 'abc'; // ReferenceError
  4. let tmp;
  5. }
  6. if (true) {
  7. // TDZ开始
  8. tmp = 'abc'; // ReferenceError
  9. console.log(tmp); // ReferenceError
  10. let tmp; // TDZ结束
  11. console.log(tmp); // undefined
  12. tmp = 123;
  13. console.log(tmp); // 123
  14. }

隐蔽的死区:

  1. function bar(x = y, y = 2) {
  2. return [x, y];
  3. }
  4. bar(); // 报错
  • 不允许重复声明

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

  1. // 报错
  2. function func() {
  3. let a = 10;
  4. var a = 1;
  5. }
  6. // 报错
  7. function func() {
  8. let a = 10;
  9. let a = 1;
  10. }
  11. function func(arg) {
  12. let arg; // 报错
  13. }
  14. function func(arg) {
  15. {
  16. let arg; // 不报错
  17. }
  18. }

块级作用域

  • ES5中没有块级作用域

ES5中没有块级作用域,内层变量可能会覆盖外层变量:

  1. var tmp = new Date();
  2. function f() {
  3. console.log(tmp);
  4. if (false) {
  5. var tmp = 'hello world';
  6. }
  7. }
  8. f(); // undefined

ES5中没有块级作用域,用来计数的循环变量泄露为全局变量:

  1. var s = 'hello';
  2. for (var i = 0; i < s.length; i++) {
  3. console.log(s[i]);
  4. }
  5. console.log(i); // 5
  • ES6 的块级作用域

    1. function f1() {
    2. let n = 5;
    3. if (true) {
    4. let n = 10;
    5. }
    6. console.log(n); // 5
    7. }
  • 块级作用域与函数声明

ES6 规定,块级作用域之中,函数声明语句的行为类似于let,在块级作用域之外不可引用。但在浏览器的 ES6 环境中,块级作用域内声明的函数,行为类似于var声明的变量。

  1. // 浏览器的 ES6 环境
  2. function f() { console.log('I am outside!'); }
  3. (function () {
  4. if (false) {
  5. // 重复声明一次函数f
  6. function f() { console.log('I am inside!'); }
  7. }
  8. f();
  9. }());
  10. // Uncaught TypeError: f is not a function

考虑到环境导致的行为差异太大,应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句。

  1. // 函数声明语句
  2. {
  3. let a = 'secret';
  4. function f() {
  5. return a;
  6. }
  7. }
  8. // 函数表达式
  9. {
  10. let a = 'secret';
  11. let f = function () {
  12. return a;
  13. };
  14. }

ES6 的块级作用域允许声明函数的规则,只在使用大括号的情况下成立,如果没有使用大括号,就会报错。

  1. // 不报错
  2. 'use strict';
  3. if (true) {
  4. function f() {}
  5. }
  6. // 报错
  7. 'use strict';
  8. if (true)
  9. function f() {}

const 命令

const声明一个只读的常量。一旦声明,常量的值就不能改变。

const一旦声明变量,就必须立即初始化,不能留到以后赋值。

与let类似,只在声明所在的块级作用域内有效。声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。不可重复声明。

const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。

如果真的想将对象冻结,应该使用Object.freeze方法。

  1. const foo = Object.freeze({});
  2. // 常规模式时,下面一行不起作用;
  3. // 严格模式时,该行会报错
  4. foo.prop = 123;

除了将对象本身冻结,对象的属性也应该冻结。下面是一个将对象彻底冻结的函数。

  1. var constantize = (obj) => {
  2. Object.freeze(obj);
  3. Object.keys(obj).forEach( (key, i) => {
  4. if ( typeof obj[key] === 'object' ) {
  5. constantize( obj[key] );
  6. }
  7. });
  8. };

顶层对象的属性

var命令和function命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。

垫片库system.global可以在所有环境拿到global。

  1. // CommonJS 的写法
  2. var global = require('system.global')();
  3. // ES6 模块的写法
  4. import getGlobal from 'system.global';
  5. const global = getGlobal();

ES6 学习笔记 - let和const的更多相关文章

  1. ES6学习笔记<一> let const class extends super

    学习参考地址1  学习参考地址2 ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准.因为当前版本的ES6是在2015年发布的,所以又称ECMAScript 2015:也 ...

  2. es6学习笔记--let和const

    今天学习了es6中的let和const命令,借此整理一下笔记. let : let 和 var 的声明方式一样,但有 var 比不上的优点.下面用 var 和 let 的例子来加深对 let 的理解. ...

  3. ES6学习笔记(let,const,变量的解构赋值)

    1.let: ; i < 3; i++) { let i = 'abc'; console.log(i); } // abc // abc // abc 不存在变量提升,它所声明的变量一定要在声 ...

  4. ES6学习笔记<五> Module的操作——import、export、as

    import export 这两个家伙对应的就是es6自己的 module功能. 我们之前写的Javascript一直都没有模块化的体系,无法将一个庞大的js工程拆分成一个个功能相对独立但相互依赖的小 ...

  5. ES6学习笔记<四> default、rest、Multi-line Strings

    default 参数默认值 在实际开发 有时需要给一些参数默认值. 在ES6之前一般都这么处理参数默认值 function add(val_1,val_2){ val_1 = val_1 || 10; ...

  6. ES6学习笔记<三> 生成器函数与yield

    为什么要把这个内容拿出来单独做一篇学习笔记? 生成器函数比较重要,相对不是很容易理解,单独做一篇笔记详细聊一聊生成器函数. 标题为什么是生成器函数与yield? 生成器函数类似其他服务器端语音中的接口 ...

  7. ES6学习笔记<二>arrow functions 箭头函数、template string、destructuring

    接着上一篇的说. arrow functions 箭头函数 => 更便捷的函数声明 document.getElementById("click_1").onclick = ...

  8. ES6学习笔记(一)——let和const

    1.ES6学习之let.const (1).var.let.const 变(常)量声明 ES5 只有全局作用域和函数作用域,没有块级作用域,这带来很多不合理的场景. 在ES6中let就诞生了,实际上它 ...

  9. es6学习笔记-class之一概念

    前段时间复习了面向对象这一部分,其中提到在es6之前,Javasript是没有类的概念的,只从es6之后出现了类的概念和继承.于是乎,花时间学习一下class. 简介 JavaScript 语言中,生 ...

随机推荐

  1. Spring Cloud体系实现标签路由

    如果你正在使用Spring Cloud体系,在实际使用过程中正遇到以下问题,可以阅读本文章的内容作为后续你解决这些问题的参考,文章内容不保证无错,请务必仔细思考之后再进行实践. 问题: 1,本地连上开 ...

  2. MongoDB学习day03--索引和explain分析查询速度

    一.索引基础 db.user.ensureIndex({"username":1}) 创建索引,username为key,数字 1 表示 username 键的索引按升序存储, - ...

  3. mvn解决jar包冲突

    转自:http://blog.csdn.net/guanglihuan/article/details/50512855 对于Jar包冲突问题,我们开发人员经常都会有碰到,当我们使用一些jar包中的类 ...

  4. [转] ASPNET Core 中获取应用程序物理路径

    如果要得到传统的ASP.Net应用程序中的相对路径或虚拟路径对应的服务器物理路径,只需要使用使用Server.MapPath()方法来取得Asp.Net根目录的物理路径,如下所示: // Classi ...

  5. iOS 设备推断 最新统计代码

    - (NSString*) deviceName {     struct utsname systemInfo;          uname(&systemInfo);          ...

  6. Linux命令输出头(标题)、输出结果排序技巧

    原文:http://blog.csdn.net/hongweigg/article/details/65446007 ----------------------------------------- ...

  7. Qt实现Windows远程控制

    实现方式为server端+client. server端为一个进程.client为图形界面程序. client连接时设置server端的Ip地址,以及须要显示的长度和宽度(不能超过相应server端显 ...

  8. node-load module

    javscript :脚本建共享全局名称空间(全局污染). node:实现CommonJS(公共)模块标准. Node加载模块,有两种方式: 1.通过名称 除非是核心模块,否则被引用的模块最后都会映射 ...

  9. 利用SEH进行代码混淆

    这几天在重看SEH机制,收获颇丰. 随手写了一个用SEH进行跳转的代码贴于此处以作纪念. 当发生异常,并捕捉了异常.在OS的异常处理机制下.会进入异常过滤函数. 过滤函数能够返回EXCEPTION_E ...

  10. python爬虫【第2篇】【多进程】

    一.多进程 1.fork方法(os模块,适用于Lunix系统) fork方法:调用1次,返回2次.原因:操作系统经当前进程(父进程)复制出一份进程(子进程),两个进程几乎完全相同,fork方法分别在父 ...