<深入理解ES6>一书中,提起 let/const 这也是平常工作用的比较多,最近需要给公司做培训. 重新复习下以往的知识点.
本文首发自 . 转载请注明出处.
let/const
再聊 let/const
之前, 让我们回顾下我们的老朋友 var
, 他有什么特点或特性
var
通过下面的例子, 可以复习下, 关键字var
声明带来的影响.
console.log(typeof A) // 'function'console.log(a) // undefinedconsole.log(typeof a) // 'undefined'console.log(typeof Date) // 'function'console.log(window.Date) // function Date() {}function A() { console.log(new Date())}var a = 10var Date = 1000console.log(window.Date) // 1000复制代码
由于变量提升
的缘故, function 优先于 var提升且定义,此时 a只声明,未赋值,函数已声明且赋值.
同样的代码,把window
改成global
放在node里面运行发现结果又不一样, global.Date
没有被重新赋值, 是因为在node运行环境里面, node 出于代码安全考虑, 每一个文件最终变成了由 require('module').wrapper
方法包裹起来, 每一个node的 js 文件, 需要 通过exports或module.exports暴露出模块的方法和属性才能使用.
由此可见 var声明
会带来以下影响
- 变量提升 (一不小心就掉坑, 非前端开发者会很郁闷)
- 会覆盖/污染 (当前)作用域的变量
通常的习惯可能是, 放在 top scope 的位置, 作为一个规范来约束自己或团队.
但并不是每个人都能很好的按照规范来做, 于是ES6 推出了 let/const来解决var声明
的弊端
let/const
把上面的代码换成 let
console.log(a) // Uncaught ReferenceError: Cannot access 'a' before initializationconsole.log(typeof a) // 'undefined'console.log(typeof Date) // 'function'console.log(window.Date) // function Date() {}复制代码
之前执行的 console.log(a)
直接报错, 阻止程序运行.
直接运行console.log(typeof a)
也一样, 而不做任何声明的时候, 会输出 'undefined'
.
let a = 10let Date = 1000console.log(window.Date) // function Date() {}console.log(a) // 10console.log(Date) // 1000console.log(window.a) // undefined复制代码
正常逻辑执行后, 并没有想象中, window.a
和a
相等. 产生上面现象的原因是什么呢??
暂时性死区(temporal dead zone, TDZ)
在let/const
声明前访问其变量会造成初始化之前不能访问
,这种现象叫做 TDZ.
let/const不会对 scope 域名做覆盖/污染
上述例子中, a
和Date
声明后并没有污染 window.a
和window.Date
, 因此当使用的时候需要覆盖的时候使用 let/const
声明的变量, 需要手动覆盖.
循环中形成新的块级绑定
早年有一个经典的面试题, 叫做 创建10 个 div.点击输出对应的索引.
笔者在初次写 js 的时候, 写成了这种错误形式
// bad wayfor(var i = 0; i < 10; i++) { var div = document.createElement('div') div.className = 'item' div.innerHTML = i div.onclick = function() { alert(i) } document.body.appendChild(div)}复制代码
输出的结果也往往是 10, 需求是点击索引啊. 造成这种结果的原因是
var变量提升, 当点击的时候此时 i 是 10
因此我们常常用 IIFE(即时执行函数)
// good wayfor(var i = 0; i < 10; i++) { var div = document.createElement('div') div.className = 'item' div.innerHTML = i div.onclick = (function(i) { return function() { alert(i) } })(i) document.body.appendChild(div)}复制代码
那有木有更好的方案, 能不能每次 循环的时候创建一个新的 i, let
具备这一特性
// better wayfor (let i = 0; i < 10; i++) { let div = document.createElement("div"); div.className = "item"; div.innerHTML = i; div.onclick = function() { alert(i) } document.body.appendChild(div);}复制代码
其他
const
用来保存常量, let 在修改的使用. const 对对象处理的时候, 对象/数组属性赋值还可以修改.
关于对象的常量问题, 放到后面章节整理.