一、前提

解决ES5中只有全局作用域和函数作用域,没有块级作用域而带来的不合理的场景。
复制代码

let


基本用法

用法和var 一样,只是let声明的变量只有在let命令所在的代码块有效

{let a = 10;var b = 1;
}a // ReferenceError: a is not defined.
b // 1
复制代码

可以看出var 声明的变量在代码块之外也是可以调用,而let声明的则调用报错。所以let 声明只在它声明的当前代码块中才能调用。


变量提升

在使用 var 的时候会出现 “变量提升”的现象,即变量可以在声明之前使用,值为undefined。let 改变了这种现状,但是必须先声明在使用,如果在声明之前使用则会出现报错。如下:

// var 的情况
console.log(foo); // 输出undefined
var foo = 2;// let 的情况
console.log(bar); // 报错ReferenceError
let bar = 2;
复制代码
暂时性死区

只要块级作用域内部存在 let 或者 const 命令,它所声明的变量就“绑定”在这个区域,不会受外部影响。且暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。如下:

var tmp = 123;if (true) {tmp = 'abc'; // ReferenceErrorlet tmp;
}
复制代码

ES6 明确规定,如果区块中存在 letconst 命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。

总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。如下:

if (true) {// TDZ开始tmp = 'abc'; // ReferenceErrorconsole.log(tmp); // ReferenceErrorlet tmp; // TDZ结束console.log(tmp); // undefinedtmp = 123;console.log(tmp); // 123
}
复制代码
注意:

++使用let声明变量时,只要变量在还没有声明完成前使用,就会报错。上面这行就属于这个情况,在变量x的声明语句还没有执行完成前,就去取x的值,导致报错”x 未定义“。++

不允许重复声明

let 不允许在同一个作用域内声明同一个变量,如下:

// 报错
function func() {let a = 10;var a = 1;
}// 报错
function func() {let a = 10;let a = 1;
}
复制代码

或者如下:

function func(arg) {let arg;
}
func() // 报错function func(arg) {{let arg;}
}
func() // 不报错
复制代码
块级作用域

上面也提到过在es5中没有块级作用域的概念,只有函数作用域和全局作用域,那么就带来了一些问题,如下:

var tmp = new Date();function f() {console.log(tmp);if (false) {var tmp = 'hello world';}
}f(); // undefined外层声明被内层声明所覆盖,内层使用的是外层的声明,内层变量提升导致 undefinded
复制代码
第二种:计数循环全局泄露,如下:
var s = 'hello';for (var i = 0; i < s.length; i++) {console.log(s[i]);
}console.log(i); // 5常见的面试题,最后输出不是预料中的 1 2 3 4 5   而全部是 5
复制代码
ES6的块级作用域,实际上就是let 新增的,如下:
function f1() {let n = 5;if (true) {let n = 10;}console.log(n); // 5
}内外层的 n 互不干扰
复制代码
ES6中 允许作用域任意嵌套,并且互不干扰,如下:
内外层可以同名{{{{let insane = 'Hello World';{let insane = 'Hello World'}
}}}};或者{{{{{let insane = 'Hello World'}console.log(insane); // 报错
}}}};
复制代码

块级作用域的出现可以让以下立即执行函数的写法不必要,如下:

// IIFE 写法
(function () {var tmp = ...;...
}());// 块级作用域写法
{let tmp = ...;...
}
复制代码
块级作用域和函数声明

在ES5中,函数只能在顶层作用域和函数作用域中声明,不能在块级作用域中声明,但是浏览器为了兼容性,还是可以在块级作用域中声明,理论上在ES6中 块级作用域中声明的函数,在外部调用会报错,考虑环境的问题,应当避免在块级作用域中声明函数,如果需要也应当写成函数表达式的方式,而不是函数声明语句,如下:

// 函数声明语句
{let a = 'secret';function f() {return a;}
}// 函数表达式
{let a = 'secret';let f = function () {return a;};
}
复制代码

const

const声明的是一个常量 如下:

const PI = 3.1415;
PI // 3.1415PI = 3;
// TypeError: Assignment to constant variable.
复制代码

声明之后如果在赋值,将会报错,同时因为声明的是常量,即const声明后即要赋值不然也会报错

const 和 let 相同,声明也只在当前的块级作用域生效。同样也不会声明提升,也存在暂时死区,只能在声明之后使用,且和 let 一样不得重复声明,不能重新赋值。

重要:

const 所不能改变的并不是值,而是变量指向的那个内存地址所保存的值不能变动,对于简单类型(数值、字符串、布尔值),值就保存在变量所指向的内存地址中,因此等同于常量。而对于复合类型(数组、对象),变量指向的内存地址,保存的只是一个指向实际数据的指针,const 只能保证这个指针是固定的(即总指向一个固定的地址)。至于它指向的数据结构则是不能控制的 ,如下:

const foo = {};// 为 foo 添加一个属性,可以成功
foo.prop = 123;
foo.prop // 123// 将 foo 指向另一个对象,就会报错
foo = {}; // TypeError: "foo" is read-only常量foo储存的是一个地址,这个地址指向一个对象。不可变的只是这个地址,
即不能把foo指向另一个地址,但对象本身是可变的,所以依然可以为其添加新属性。
复制代码

或者

const a = [];
a.push('Hello'); // 可执行
a.length = 0;    // 可执行
a = ['Dave'];    // 报错常量a是一个数组,这个数组本身是可写的,但是如果将另一个数组赋值给a,就会报错
复制代码
如果真的想将声明对象冻结,不能在改变 则应该使用object.freeze()
const foo = Object.freeze({});// 常规模式时,下面一行不起作用;
// 严格模式时,该行会报错
foo.prop = 123;对象也可以冻结var constantize = (obj) => {Object.freeze(obj);Object.keys(obj).forEach( (key, i) => {if ( typeof obj[key] === 'object' ) {constantize( obj[key] );}});
};
复制代码

ES6 声明变量的六种方法

1. function
2. var
3. let
4. const
5. import
6. class
复制代码

顶层对象的属性

在浏览器环境指的是window对象,在 Node 指的是global对象,ES5 之中,顶层对象的属性与全局变量是等价的。

window.a = 1;
a // 1a = 2;
window.a // 2
复制代码

global 对象

ES5 的顶层对象,本身也是一个问题,因为它在各种实现里面是不统一的。

  1. 浏览器里面,顶层对象是window,但 Node 和 Web Worker 没有window。
  2. 浏览器和 Web Worker 里面,self也指向顶层对象,但是 Node 没有self。
  3. Node 里面,顶层对象是global,但其他环境都不支持。

同一段代码为了能够在各种环境,都能取到顶层对象,现在一般是使用this变量,但是有局限性。

  1. 全局环境中,this会返回顶层对象。但是,Node 模块和 ES6 模块中,this返回的是当前模块。
  2. 函数里面的this,如果函数不是作为对象的方法运行,而是单纯作为函数运行,this会指向顶层对象。但是,严格模式下,这时this会返回undefined。
  3. 不管是严格模式,还是普通模式,new Function('return this')(),总是会返回全局对象。但是,如果浏览器用了 CSP(Content Security Policy,内容安全策略),那么eval、new Function这些方法都可能无法使用。

欢迎关注 公众号【前端开发小白】

ES6入门之let、cont相关推荐

  1. ES6入门之对象的扩展

    1. 属性的简洁表示法 在ES6中 允许直接写入变量和函数,作为对象的属性和方法,使得代码的书写更为简洁. const f = 'a' const b = {f} b // {f: 'a'}等同于 c ...

  2. ES6入门笔记(一)

    ES6入门笔记(一) 安装babel 由于浏览器对ES6的支持还不是很好,编写ES6代码前我们要安装一个babel工具将ES6代码编译成ES5代码,用如下命令安装babel: npm install ...

  3. es6入门6--数组拓展运算符,Array.from()基本用法

    本文只是作为ES6入门第九章学习笔记,在整理知识点的同时,会加入部分个人思考与解答,若想知道更详细的介绍,还请阅读阮一峰大神的ES6入门 一.拓展运算符 ES6中新增了拓展运算(...)三个点,它的作 ...

  4. ES6 入门教程 9 数组的扩展 9.1 扩展运算符

    ES6 入门教程 ECMAScript 6 入门 作者:阮一峰 本文仅用于学习记录,不存在任何商业用途,如侵删 文章目录 ES6 入门教程 9 数组的扩展 9.1 扩展运算符 9.1.1 含义 9.1 ...

  5. ES6入门学习资源共享

    以下是收集的一些ES6学习资源,希望能帮助大伙: 学习ES6新特性: http://www.cnblogs.com/ziyunfei/ exploring-es6 https://leanpub.co ...

  6. es6入门到五连绝世之三杀(triple kill )

    es6入门到五连绝世之三杀(triple kill ) 欢迎来到e6语法笔记教学 一.Promise 简介 1.1.Promise 异步执行顺序 1.2.自定义 promise 1.3.自定义Prom ...

  7. es6入门到五连绝世之四杀(quadra kill )

    es6入门到五连绝世之四杀(quadra kill ) 欢迎来到e6语法笔记教学 一.symbol 数据类型 1.1.介绍及使用 欢迎来到e6语法笔记教学 这篇博客的记录手法,是通过 demo 记录 ...

  8. es6入门到五连绝世之一血(first blood)

    es6入门到五连绝世之一血(first blood) 欢迎来到e6语法笔记教学 一.变量声明 1.1.变量声明有三种方式 1.2.JS中的块级作用域,var.let.const 三者的区别 1.2.1 ...

  9. 阮一峰ES6入门读书笔记(十六):Moudle

    阮一峰ES6入门读书笔记(十六):Moudle 在 ES6 之前,社区制定了一些模块加载方案,最主要的有 CommonJS 和 AMD 两种.前者用于服务器,后者用于浏览器.ES6 在语言标准的层面上 ...

  10. 阮一峰ES6入门读书笔记(七):运算符的拓展

    阮一峰ES6入门读书笔记(七):运算符的拓展 1. 指数运算符 ES6新增了一个指数运算符(**). 2 ** 2 // 4 2 ** 3 // 8 这个运算符的一个特点是右结合,而不是常见的左结合. ...

最新文章

  1. RabbitMQ(三):RabbitMQ 使用场景
  2. 项目中常用的git指令
  3. 中兴被禁在全球芯片市场掀起的波澜
  4. Ubuntu下利用JDK的Keytool配置Tomcat7.0的SSL协议(单向认证简易版)
  5. SIFT原理与源码分析
  6. Python基础语法精心总结!看完都知道的可以往下继续学习了
  7. 作者:牟少敏,博士,山东农业大学教授。
  8. 计算机主机一闪一闪的无法启动,电脑启动不了灯一闪一闪的
  9. linux 编码转换-转
  10. 北海焊接机器人_北海中型机械手臂生产,机械手
  11. 【干活推送 】人工智能(AI)教程
  12. python 京东签到_Python实战—京东用户行为分析
  13. 科普 | 天才在左,疯子在右
  14. 微信小程序画布canvas制作海报图片清晰度过低
  15. html 置换元素和非置换元素
  16. aliyun的产品都是有哪些,主要是做什么的呢?
  17. 免费英文在线翻译-英文自动翻译
  18. PDF转Word方法大盘点:看了这一篇,就不用再找转换技巧了
  19. 使用Adobe Illustrate进行科研论文图片排版
  20. cad批量转换低版本如何实现?

热门文章

  1. 剑指Offer学习笔记(3)——解决面试题的思路
  2. Jqurey 得到url参数 getUrlParam
  3. C# COM Object for Use In JavaScript / HTML, Including Event Handling(转载)
  4. api hook 例子,截获封包(转载)
  5. 好程序员技术分析JavaScript闭包特性详解
  6. [IOI2018] seats 排座位
  7. 线段树2 求区间最小值
  8. axure下载及汉化
  9. jquery 动态添加,降低input表单的方法
  10. 欧洲2015年新设太阳能约8GW 为4年来首增