ES6之let、const和块级作用域
2017-11-02 23:27
260 查看
let、const和块级作用域
目录:letconst和块级作用域
let 与 var 的异同点比较
let可用于块级作用域Block Scope
const 定义常量
变量的生命周期
使用原则
循环语句 forof
数组类型的entries方法
let 与 var 的异同点比较
let | var | |
---|---|---|
定义变量 | √ | √ |
可被释放 | √ | √ |
可被提升(Hoist) | √ | |
重复定义检查 | √ | |
可被用于块状作用于 | √ |
var foo = 'bar'; var foo = 'abc'; console.log(foo); // abc let bar = 'foo'; let bar = 'abc' // Uncaught SyntaxError: Identifier 'bar' has already been declared
let可用于块级作用域(Block Scope)
const arr1 = []; for(var i = 0; i < 3; ++i){ arr1.push(() => i); } const arr2 = arr1.map(x => x()) const arr3 = []; for(let i = 0; i < 3; ++i){ arr3.push(() => i); } const arr4 = arr3.map(x => x()) console.log('var: ' + arr2.join(', ')); //var: 3, 3, 3 console.log('let: ' + arr4.join(', ')); //var: 0, 1, 2
const 定义常量
//定义一个常量 const PI = 3.1415926; //尝试对该常量进行重新赋值 PI = 3.14 //Uncaught TypeError: Assignment to constant variable
ECMAScript 在对变量的引用进行读取时,会从该变量当前所对应的内存地址所指向的内存空间中读取内容。而当用户改变变量的值时,引擎会重新从内存中分配一个新的内存空间以存储新的值,并将新的内存地址与变量进行绑定。const 的原理便是在变量名与内存地址之间建立不可变的绑定,当后面的程序尝试申请新的内存空间时,引擎便会抛出错误。
而对于对象、数组等稀疏的引用类型值,在内存空间中可能会被拆分成若干个段落,虽然 Google V8 在对 javaScript 运行时的内存管理中使用的是堆内存 (heap) ,而不是栈内存(stack) ,但因为对象的属性是可以变化的,所以为了最快地进行内存调度,当对象的属性被改变或添加了新的属性时,都需要重新计算内存地址偏移值。
const foo = { a: 1, b: 2 }
foo对象字面量定义的内存存储空间
内存偏移值(假设) | 内容 |
---|---|
0 | Object foo |
1 | Property a |
2 | Property b |
因为const所创建的内存绑定是只绑定一处,所以默认情况下对象这种由若干内存空间片段组成的值并不会全部被锁定。
要获得值不可变的对象,需要配合 ES5 中的 Object.fressze() 方法,便可以得到一个首层属性不可变的对象。但若首层属性中存在对象,则默认情况下首层以下的对象依然可以被改变:
const obj1 = Object.freeze({ a: 1, b: 2 }) obj1.a = 2; // Uncaught TypeError: Cannot assign to read only property 'a' of object '#<Object>' const obj2 = Object.freeze({ a: {} }) obj2.a.b = 1; console.log(obj2); // {"a":{"b":1}}
为了解决首层以下的对象依然可以被改变的问题,我们需要写一个函数来实现创建一个完全的值不可变对象:
// Object.deepFreeze from MDN // To make obj fully immutable, freeze each object in obj // To do so, we use this function Object.deepFreeze = function(obj) { // Retrieve the property names defined on obj var propNames = Object.getOwnPropertyNames(obj); // Freeze properties before freezing self propNames.forEach(function(name) { var prop = obj[name]; // Freeze prop if it is an object if (typeof prop == 'object' && prop !== null) Object.deepFreeze(prop); }); // Freeze self (no-op if already frozen) return Object.freeze(obj); } const obj3 = Object.deepFreeze({ a: { b: 1 } }) obj3.a.c = 2; // Uncaught TypeError: Can't add property c, object is not extensible
const 定义的常量同样遵循变量在作用域中的生命周期( const 也可用于块级作用域)。
变量的生命周期
var foo // Declaration foo = 1 // Assignment
ECMAScript 引擎在进入一个作用域时,会扫描这个作用域内的变量(或常量)定义语句(var, let 或 const),然后在这个作用域内为扫描得到的变量名做准备,在当前作用域中被扫描到的变量名都会进入未声明(Undeclared)阶段。
进入声明语句时,var foo ,即前半句时声明部分(Declaration),用于在 ECMAScript 引擎中产生一个变量名,但此时该变量名没有对应的绑定和内存空间,所以“值”为null。
= 的作用是作为变量的赋值语句,引擎执行至此处即为该变量的赋值部分(Assignment),计算将要赋予变量名的值的物理长度(内存空间占用大小),向系统申请相应大小的内存空间,然后将数据存储到里面去,并在变量名和内存空间之间建立绑定关系(Bingding),此时变量(或常量)才得到了相应的值。
到当前作用域中的语句被执行完毕时,引擎便会检查该作用域中被定义的变量(或常量)的被引用情况,如果引用已被全部解除,引擎便会认为其应该被清除。
运行引擎会不断检查存在于运行时( Runtime )中的变量(或常量)的被引用情况,并重复第四步,直到程序结束。
console.log(foo); // ReferenceError console.log(bar); // ReferenceError let foo = 1; const bar = 2;
当变量处于未声明阶段,在ES6的 let 和 const 中,引擎将这一种行为视为错误行为,并抛出错误。
使用原则
一般情况下,使用const来定义值的存储容器(常量)。只有在值容器明确地被确定将会被改变时才使用let来定义(变量)。
不再使用var。
循环语句 for…of
它的主要用途是代替 for…in 循环语句。const arr = [1, 2, 3]; for(const item of arr){ console.log(item); //1 2 3 }
for…in 遍历的是数组的索引(即键名),而 for…of 遍历的是数组元素值。
使用 for…in 遍历数组存在以下问题:
index索引为字符串型数字,不能直接进行几何运算。
遍历顺序有可能不是按照实际数组的内部顺序。
使用 for…in 会遍历数组所有的可枚举属性,包括原型。
数组类型的entries方法
返回对应的数组中每一个元素与其下标配对的一个新数组:const arr = ['a', 'b', 'c']; for (let item of arr.entries()) { console.log(item); } // [0, "a"] // [1, "b"] // [2, "c"]
相关文章推荐
- ECMAScript6(ES6)标准之let、const关键字与块级作用域
- ES6 let命令和块级作用域和const命令
- ES6之let,const和块级作用域
- ES6 let,const命令和块级作用域
- let、const、var和块级作用域
- 初步探究ES6之let,const和块级作用域
- 开始学习es6(二) let 与 const 及 块级作用域
- 搭建Babel运行环境,Traceur ES6模板,块级作用域,let和const命令
- JS中的块级作用域,var、let、const三者的区别
- 学习笔记:ES6之let和const
- es6之let,const关键字
- ES6-let带来了更简单的块级作用域
- JavaScript块级作用域, let, const介绍
- ES6 —(let、const)
- 【es6】【块级作用域 and const】
- ES6新特性:块级作用域let和const
- 深入浅出ES6之let和const命令
- ES 6 : let与const
- const, let和var的作用域及闭包
- 学习ES6之let、const