ECMAScript6 | 新特性(部分)
新特性概览
参考文章:http://www.cnblogs.com/Wayou/p/es6_new_features.html
这位前辈写的很好,建议深入学习
————————————————————————————————————————————
let命令
- let命令用来声明变量,用法类似于var,但仅仅可以使用在定义的代码块中
- 不存在变量提升
- 暂时性死区:只要块级作用域内存在let命令,它所声明的变量就"绑定"binding这个区域,不再受外部影响
- 不允许重复声明:let不允许在相同作用域内重复声明同一个变量
test.js
1 // 在该代码块中声明let,外部不能调用,花括号之内 2 { 3 let a = 100; 4 var b = 200; 5 } 6 7 // console.log(a); 8 // 在这里var进行了变量提升,可以在全局中使用,let不可以变量提升 9 console.log(b); 10 // ******************************************************************** 11 // 不存在变量提升 12 // ES5 13 var arr = [], 14 arrTest = []; 15 // 在循环中c并没有赋给数组,而是被i循环覆盖为9,所以输出的都是9 16 for (var i = 0; i < 10; i++) { 17 var c = i; 18 arr[i] = function() { 19 return c; 20 } 21 } 22 // 遍历执行 23 for (var i = 0; i < 10; i++) { 24 arrTest[i] = arr[i](); 25 } 26 console.log(arrTest); 27 28 // ES6 29 var arr2 = []; 30 // var c → let d 31 for (var i = 0; i < 10; i++) { 32 let d = i; 33 arr2[i] = function() { 34 return d; 35 } 36 } 37 for (var i = 0; i < 10; i++) { 38 arrTest[i] = arr2[i](); 39 } 40 console.log(arrTest); 41 // 教学视频中没有说清楚,那么是否是因为let d 只对对应的代码块起作用,出现了10个不同的d呢? 42 // ******************************************************************** 43 // 暂时性死区 44 { 45 console.log(e); 46 let e = 100; 47 console.log(e); 48 } 49 // 在视频中得到的结果是undefined和100,而在我的测试中第一个console.log得到的是报错信息,提示未定义 50 // 在该代码块中let管辖着e,当未声明变量e时,打印e则会提示未定义的,暂时不可以使用的 51 // ******************************************************************** 52 // 不允许重复声明 53 { 54 var f = 1; 55 let f = 100; 56 } 57 { 58 let g = 100; 59 var g = 1; 60 } 61 // 重复声明会产生报错信息Identifier 'f' has already been declared
————————————————————————————————————————————
块级作用域
let实际上为JavaScript新增了块级作用域
-
在ES5中只有全局作用域和函数作用域,没有块级作用域,容易出现以下问题:
- 内层变量可能会覆盖外层变量
- 用来计数的循环变量泄露为全局变量
1 <!DOCTYPE html> 2 <html> 3 4 <head> 5 <meta charset="utf-8"> 6 <script src="traceur.js"></script> 7 <script src="bootstrap.js"></script> 8 <!-- ES5 --> 9 <script type="text/javascript"> 10 var time = new Date(); 11 12 function f1() { 13 console.log(time); 14 if (false) { 15 var time = 'hello'; // 变量重复声明了之后,内部time会覆盖已有变量的内存地址,在运行时console.log会寻找地址,此时地址还没有存入值'hello',所以输出为undefined 16 // time ='hello'; // 如果是使用赋值语句,则正常输出time为Date(); 17 } 18 } 19 f1(); 20 // **************************************** 21 // 循环变量泄露为全局变量的问题 22 for (var i = 0; i < 12; i++) {} 23 // i跳出了循环体,循环结束后i没有被销毁 24 console.log(i); 25 26 // 在其他函数中也会被使用 27 function f2() { 28 console.log(i); 29 } 30 f2(); 31 // **************************************** 32 // Demo1: 33 // 第二次声明nTest1会覆盖第一次声明,得到200的值 34 function f3() { 35 var nTest1 = 100; 36 if (true) { 37 var nTest1 = 200; 38 } 39 console.log(nTest1); 40 } 41 f3(); 42 // **************************************** 43 // Demo2:自调用函数 44 // 视频演示中ES5得到的是inside,ES6得到的是outside 45 // 测试时ES5报错,ES6正常inside 46 function fun(){ 47 console.log('i am outside'); 48 }; 49 (function (){ 50 if (false) { 51 function fun(){ 52 console.log("i am inside"); 53 }; 54 } 55 fun(); 56 })(); 57 </script> 58 <!-- ES6 --> 59 <script type="text/traceur"> 60 // **************************************** 61 // Demo1: 62 function f4() { 63 let nTest2 = 100; 64 if (true) { 65 let nTest2 = 200; 66 console.log(nTest2); 67 } 68 console.log(nTest2); 69 } 70 f4(); 71 // **************************************** 72 // Demo2:自调用函数 73 function fun(){ 74 console.log('i am outside'); 75 } 76 (function (){ 77 if (false) { 78 function fun(){ 79 console.log("i am inside"); 80 } 81 } 82 fun(); 83 }()) 84 </script> 85 </head> 86 87 <body> 88 </body> 89 90 </html>
————————————————————————————————————————————
const命令
const关键字声明的是常量,不可改变
1 <!DOCTYPE html> 2 <html> 3 4 <head> 5 <meta charset="utf-8"> 6 <script src="traceur.js"></script> 7 <script src="bootstrap.js"></script> 8 <!-- ES5 --> 9 <script type="text/javascript"> 10 // const命令 11 const Pi = 3.1415; 12 console.log(Pi); 13 // 赋值的话返回错误信息Assignment to constant variable. 14 // Pi = 1; 15 // *********************************************************** 16 // const的块级作用域问题 17 if (true) { 18 var a = 1; 19 } 20 // Error: a is not defined 21 // 可见const关键字定义的也有块级作用域的问题 22 // console.log(a); 23 </script> 24 <!-- ES6 --> 25 <script type="text/traceur"> 26 // 暂时性死区 27 if (true) { 28 console.log(b); 29 const b = 2; 30 } 31 // *********************************************************** 32 { 33 //Error:["file:///F:/6.Code/Front-End/JavaScript/Test/index_inline_script_1.js:6:16: Duplicate declaration, c"] 34 //不可重复声明 35 //var c=200; 36 const c = 300; 37 console.log(c); 38 } 39 // *********************************************************** 40 // 通过const声明对象时,显示这个对象是只读的,该对象是冻结状态的,但仍然可以写入值 41 const person = {}; 42 person.name = "hello"; 43 console.log(person); 44 person.name = "hugh"; 45 console.log(person); 46 console.log(Object.isSealed()); 47 console.log(Object.isFrozen()); 48 // 如果以冻结方法定义的对象,则是无法写入的 49 const person2 = Object.freeze({}); 50 person2.name = "hugh"; 51 person2.age = 21; 52 console.log(person2); 53 console.log(person2.name); 54 console.log(person2.age); 55 console.log(Object.isFrozen()); 56 // 正确的const冻结对象的方法 57 const person3 = Object.freeze({ 58 name: 'hhh', 59 age: 1 60 }); 61 console.log(person3); 62 console.log(Object.isFrozen()); 63 // *********************************************************** 64 // const声明的数组可以数组操作,但不可以整体赋值,视为重新定义 65 const arr1 = []; 66 arr1.push(1); 67 arr1.push(2); 68 console.log(arr1); 69 arr1.pop(); 70 console.log(arr1); 71 console.log(arr1.length); 72 //Error:["file:///F:/6.Code/Front-End/JavaScript/Test/index_inline_script_1.js:30:5: arr1 is read-only"] 73 //arr1 = ['a','b','c']; 74 //console.log(arr1); 75 // *********************************************************** 76 // 彻底冻结对象,请对比参考JavaScript中的递归冻结函数方法 77 var constantize = (obj) => { 78 Object.freeze(obj); 79 Object.keys(obj).forEach((key,value)=>{ 80 if(typeof obj[key]==='object'{ 81 constantize(obj[key]); 82 }); 83 }); 84 }; 85 </script> 86 </head> 87 88 <body> 89 </body> 90 91 </html>
————————————————————————————————————————————
跨模块常量
1 <!DOCTYPE html> 2 <html> 3 4 <head> 5 <meta charset="utf-8"> 6 <script src="traceur.js"></script> 7 <script src="bootstrap.js"></script> 8 <!-- ES5 --> 9 <script type="text/javascript"> 10 11 </script> 12 <!-- ES6 --> 13 <script type="text/traceur"> 14 // module.js, 在这里将变量输出 15 export const cVariantName = "111"; 16 export const iVariantName = 3; 17 export const fVariantName = 4.111; 18 19 // use.js, 在这里将变量全部引入 20 import * as variant from './module.js'; 21 console.log(variant.cVariantName); // 输出"111"; 22 console.log(variant.iVariantName); // 输出3; 23 console.log(variant.fVariantName); // 输出4.111; 24 25 // otherUse.js, 引入部分变量 26 import {iVariantName,fVariantName} as variant from './module.js'; 27 console.log(variant.iVariantName); // 输出3; 28 console.log(variant.fVariantName); // 输出4.111; 29 30 // onlyUse.js, 只引入一个变量 31 import iVariantName as variant from './module.js'; 32 console.log(variant.iVariantName); // 输出3; 33 </script> 34 </head> 35 36 <body> 37 </body> 38 39 </html>
————————————————————————————————————————————
全局对象属性
- 全局变量是最顶层的对象
- 浏览器环境指的是window对象
- Node.js指的是global对象
-
在JavaScript中所有全局变量都是全局对象的属性
p.s.在Node中这一条只对REPL环境使用,模块环境必须显式声明成global属性
-
ES6规定:
- var、function命令声明的全局变量,属于全局对象的属性
- let、const、class命令声明的全局变量,不属于全局对象的属性
1 <!DOCTYPE html> 2 <html> 3 4 <head> 5 <meta charset="utf-8"> 6 <script src="traceur.js"></script> 7 <script src="bootstrap.js"></script> 8 <!-- ES5 --> 9 <script type="text/javascript"> 10 11 </script> 12 <!-- ES6 --> 13 <script type="text/traceur"> 14 var varName = "varValue"; 15 // 浏览器环境 16 console.log(window.varName); // 输出varValue 17 // Node环境 18 // console.log(global.varName); 19 // 通用环境 20 console.log(this.varName); // 输出varValue 21 22 let letName = "letValue"; 23 console.log(window.letName); // 兼容模式:letValue, 严格模式:undefined 24 console.log(this.letName); // 兼容模式:letValue, 严格模式:undefined 25 </script> 26 </head> 27 28 <body> 29 </body> 30 31 </html>
————————————————————————————————————————————
解构赋值 Dustructuring
- 解构:ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值
- 不完全解构:等号左边的模式只匹配一部分等号右边的数组
- 指定默认值:ES6内部使用严格相等运算符===来判断一个位置是否有值,如果数组成员不严格等于undefined默认值不会生效
- let和const明星:只要某种数据结构具有iterator接口,都可以采用数组形式解构赋值