ES6新特性速览
引言
ES6引入了很多新的语言特性和能力,这篇文章仅快速地做一个概览。包括let、解构、箭头函数、模块化、Spread运算符 等。ES6还有很多更深入的内容,有时间再单独总结。大部分的ES6新特性,最新版的Chrome浏览器都原生支持,所以下面大多数代码不需要使用Babel转码器即可直接运行。但是模块化的import和export则暂未支持,只能通过Babel经过webpack等工具打包后使用。
let和var
let具有括号作用域,而var仅有函数作用域,没有括号作用域,因此在大多数情况下都推荐使用let。下面是简单的对比。
for(var i=0; i<3; i++){} console.log(i); // 3 for(let j=0; j<3; j++){} console.log(j); // Uncaught ReferenceError: j is not defined
使用var时,为了避免变量冲突,通常是使用立即执行函数来建立一个块级作用域:
(function(){ var i = 1; console.log("a:", i); // 1 })(); console.log("b:", i); // Uncaught ReferenceError: i is not defined
如果是代码块,变量在代码块结束后依然会存在:
{ var j = 1; console.log("a:", j); // 1 } console.log("b:", j); // 1
使用let则不会有这个问题:
{ let i = 1; console.log("a:", i); // 1 } console.log("b:", i); // Uncaught ReferenceError: i is not defined
一个典型的作用域问题是:遍历li对象,并赋予点击事件:
<ul> <li>项目A</li> <li>项目B</li> <li>项目C</li> </ul>
var arr = document.querySelectorAll("li"); for(var i=0; i<arr.length; i++){ arr[i].onclick = function(){ alert("你点击了第"+ i +"个项目"); } } console.log("i:", i); // 3
此时,不管点击哪个li,都会弹出“你点击了第3个项目”,因为在for循环结束后,i依然“活着”,并且值为3。
只需要将var i=0 改为 let i=0,则没有这个问题。而在let出现以前,传统的解决方案依然是利用函数作用域,将i作为立即执行函数的参数,写一个闭包函数:
var arr = document.querySelectorAll("li"); for(var i=0; i<arr.length; i++){ (function(x){ arr[x].onclick = function(){ alert("你点击了第"+ x +"个项目"); } })(i); }
const
服务端的很多语言都有const,例如我比较熟悉的C#,顾名思义,变量用const声明后值不可以再变。
const PI = 3.1415926; PI = 3; // Uncaught TypeError: Assignment to constant variable.
const还有两个注意事项,1:声明时就需要赋值。
const PI; // Uncaught SyntaxError: Missing initializer in const declaration PI = 3.1415926;
2:如果是对象,可以修改内部值,但不能重新赋值。
const loc = { x:1 , y: 2} loc.x = 3; console.log(loc); // {x:3, y:2} loc = {} // Uncaught TypeError: Assignment to constant variable.
箭头函数
箭头函数类似C#中的lambda表达式,大多数情况下,可以作为函数的简写形式。
function multiply(x){ return x*2; } // 相当于 const multiply = (x) => { return x*2; }
当函数体只有一行return时,可以再次简化,省略掉花括号和return关键字。
const multiply = (x) => x*2;
当只有一个输入参数时,参数的圆括号()也可以省略掉。(如果有多个参数或者没有参数,则必须有圆括号)。
const multiply = x => x*2; var i = multiply(1); console.log(i); // 2
箭头函数和普通函数最重要的一个区别,就是this关键字绑定到了函数定义时的作用域,而非函数运行时的作用域。下面是一个例子:
function Product(){ this.title = "NS Switch"; this.showName1 = function(){ console.log(this) console.log("showName1:", this.title); } this.showName2 = ()=>{ console.log(this) console.log("showName2:", this.title); } } var p = new Product(); var showName1 = p.showName1; var showName2 = p.showName2; showName1(); // Uncaught TypeError: Cannot read property 'title' of undefined showName2(); // NS Switch setTimeout(p.showName1, 1000) // this为window,this.title为undefined setTimeout(p.showName2, 1000) // NS Switch
import和export
import和export用于支持模块化(modules)。假设utility.js用来创建模块,而page.js使用该模块,则用法如下所示:
方式1:使用default关键字
// utility.js const Person = { name : "jimmy" } export default Person
// page.js import util from "./utility.js" console.log(util); // {name:"jimmy"}
方式2:多个对象时使用星号 *
// utility.js export const Person = { name : "jimmy" } export const Student = { score: 100 }
// page.js import * as util from "./utility.js" console.log(util.Person); // {name:"jimmy"} console.log(util.Student); // {score:100}
方式3:多个对象时使用析构
模块导出不变。模块引入才用下面的方式。
// page.js import { Person, Student } from "./utility.js" console.log(Person); // {name:"jimmy"} console.log(Student); // {score:100}
Spread和Rest运算符
这两个运算符的表示方法都是三个点:...,根据使用的位置来区分。
Spread运算符:用于展开数组或者对象。
// 数组展开 var oldArr = [1,2,3] var newArr = [0, ...oldArr, 4] console.log(newArr); // [0,1,2,3,4]
// 对象展开 var oldObj = { x:1, y:2} var newObj = { ...oldObj, z:3 } console.log(newObj); // {x: 1, y: 2, z: 3}
需要注意的是,当新对象的属性名重复时,会进行覆盖:
var oldObj = { x:1, y:2} var newObj = {...oldObj, y:3 } console.log(newObj); // {x: 1, y: 3}
Rest运算符:用于个数不定的函数参数
可以看到,实际上相当于将不定个数的函数参数合并成了数组。
function total(...args){ var t = 0; for(let i=0; i< args.length;i++){ t += args[i] } return t; } console.log(total(1,2)) // 3 console.log(total(3,4,5)) // 12
析构(destructering)
更方便地将数组元素或者对象属性提取出来保存到变量中。
// 析构数组 const arr = [1,2,3] var [x, y] = arr; console.log(x, y); // 1, 2 var [, , z] = arr; console.log(z); // 3
// 析构对象 const obj = { x:1, y:2, z:3 } var {x, z} = obj; console.log(x, z); // 1, 3
感谢阅读,希望这篇文章能给你带来帮助!