Dean Front-end Dev Engineer

JS ES6新特性小结

2018-02-20

变量

声明变量

let 声明一个块级作用域变量。

const 声明一个常量,也具有块级作用域。

解构赋值

解构赋值,就是同时对一组变量进行赋值。可以是数组,也可以是对象。

对数组元素进行解构赋值:

let [x,y,z] = [3,4,5];

从一个对象中取出若干属性,使用解构赋值:

let person = {
    name:'xiaowang',
    age:11,
    birthday:'May 1st'
}
let {name,birthday} = person;
console.log(name + '\'s ' + 'birthday is ' + birthday);

解构赋值的使用场景

交换变量的值

let x = 1,y = 2;
[x,y] = [y,x];

快速获取当前页面的域名和路径

let {hostname:domain, pathname:path} = location;

如果一个函数接收一个对象作为参数,那么,可以使用解构直接把对象的属性绑定到变量中。例如,下面的函数可以快速创建一个Date对象:

function buildDate({year, month, day, hour=0, minute=0, second=0}) {
    return new Date(year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second);
}

它的方便之处在于传入的对象只需要yearmonthday这三个属性:

buildDate({ year: 2017, month: 1, day: 1 });
// Sun Jan 01 2017 00:00:00 GMT+0800 (CST)

注:解构赋值的目的主要目的是解少代码量,顺便让代码更易读。

箭头函数

箭头函数有以下几个要注意的点。

  • 函数体内的 this 对象,绑定定义时所在的对象,而不是使用时所在的对象。
  • 不可以当作构造函数,也就是说,不可以使用 new 命令,否则会抛出一个错误。
  • 不可以使用 arguments对象,该对象在函数体内不存在。

箭头函数相当于匿名函数,且简化了函数的定义。下面举例说明。

只有一个语句时,可省略{}return ,下面分别是没有参数,1 个参数,多个参数的写法。

var arrowFun = () => 1 + 2;//没有参数时,括号不能省
var arrowFun1 = x => x * x;//只有一个参数时,可以省略括号
var arrowFun2 = (x,y) => x * y;//多个参数时,括号不能省
var arrowFun3 = x => ({x:1});//返回值为对象时,要加括号

多个语句时,{}return不能省

var arrowFun4 = (x,y) => {
    let sum = x + y;
    let multiply = x * y;
    return {
        sum:sum,
        multiply:multiply
    }
}

箭头函数的this指向:其实箭头函数中没有this,因此箭头函数中的this总是指向它定义时所在的环境

var obj = {
    name:'wang',
    birth:1995
    sayAge:function(){
        setTimeout(function(){
            console.log( new Date().getFullYear() - this.birth );
        },500);
    }
}
obj.sayAge();//NaN

var obj = {
    name:'wang',
    birth:1990
    sayAge:function(){
        setTimeout( () => {
            console.log( new Date().getFullYear() - this.birth );
        },500);
    }
}
obj.sayAge();//23

函数绑定运算符 ::

函数绑定运算符(::),运算符左边是一个对象,右边是一个函数。该运算符自动将左边的对象,作为上下文环境(this),绑定到右边的函数上。

generator (生成器)

generator(生成器)是ES6标准引入的新的数据类型。一个generator看上去像一个函数,但可以返回多次。

例如:要做一个自增变量,又不想污染全局变量,也不想用闭包的时候。就可以这样

function* countNum(max) {
    let num = 1;
    while( num < max ){
        yield num;
        num++;
    }
}
let count = countNum(10);
console.log( count.next().value );//1
console.log( count.next().value );//2
console.log( count.next().value );//3

遍历generator对象,可以象上面那样用next(),也可以用for ... of

当你调用一个生成器时,它并非立即执行,而是返回一个已暂停的生成器对象。你可将这个生成器对象视为一次函数调用,只不过立即冻结了,它恰好在生成器函数的最顶端的第一行代码之前冻结了。

每当你调用生成器对象的next()方法时,函数调用将其自身解冻并一直运行到下一个yield表达式,再次暂停。

generator 可以在执行过程中多次返回,看上去就像一个可以记住执行过程的函数。用一个对象来保存状态则要麻烦得多。

generator还有另一个巨大的好处,就是把异步回调代码变成“同步”代码。在写 Ajax 的时候特别好用,写起来像是同步的代码,执行的时候实际上是异步的。

拓展运算符…

可变参数个数的函数调用

rest参数只能写在最后,前面用...标识。

function sum(...rest){
    let result = 0;
    rest.forEach(function(value){
       result += value; 
    });
    return result;
}

复制数组、数组合并

var arr1 = [1,2,3];
var arr2 = [4,5,6];
var newArr1 = [...arr1];//复制数组
var concatArr = [...arr1,...arr2,7,8,9];//合并数组

将字符串转为数组

var str = 'Hello';
strArr = [...str];//['H','e','l','l','o']

替代apply

var arr = [1,2,3];
Math.max(...arr);

将实现了 Iterator 接口的对象转为数组

var nodeList = document.querySelectorAll('div');  
var array = [...nodeList];  

Map 和 Set

JavaScript对象的键必须是字符串。但实际上Number或者其他数据类型作为键也是非常合理的。

为了解决这个问题,最新的ES6引入了新的数据类型Map

Map

Map是一组键值对的结构,具有极快的查找速度。初始化、赋值、获取值、判断键是否存在,删除键、成员总数、清除全部成员操作如下:

let m = new Map([['wang',11],['li',12],['ye',13]]);
m.set(333,14);
m.get('li');//12
m.has(333);//true
m.get(333);14
m.delete('wang');
m.get('wang');//undefined
m.size;//2
m.clear();
m.size;//0

Set

SetMap类似,是一组key的集合,不过不储存value。由于 key不能重复,所以Set中没有重复的数据,所以也常常用于过滤数组中的重复数据。大致操作如下:

let s = new Set([1,2,3]);
s;//Set{1,2,3}
s.has(1);//true
s.add(4);//Set{1,2,3,4}
s.delete(1);//Set{2,3,4}
s.clear();//清除全部成员
s.size;//0

//过滤数组重复项
let arr = [1,1,2,3,4,4];
let newArr = [...new Set(arr)];//[1,2,3,4]

iterable

遍历Array可以采用下标循环,遍历MapSet就不可以。为了统一集合类型,ES6引入了新的iterable类型。

ArrayMapSet 都属于iterable类型。

iterable类型的集合可以通过新的for ... of循环来遍历。语法如下:

let m = new Map([['wang',11],['li',12],['ye',13]]);
for (let x of m){
    console.log(x);
}

for ... of循环和for ... in循环的区别:

for ... in循环遍历的实际上是对象的属性名称。一个Array数组实际上也是一个对象,它的每个元素的索引被视为一个属性。

当我们手动给Array对象添加了额外的属性后,for ... in循环将带来意想不到的意外效果:

let arr = [1,2,3];
a.name = 'Hello';
for (var x in arr) {
    console.log(x); // '0', '1', '2', 'name'
}
for (var x of arr){
    console.log(x);//1,2,3
}

for ... in循环将把name包括在内,但Arraylength属性却不包括在内。

for ... of循环则完全修复了这些问题,它只循环集合本身的元素。

这就是为什么要引入新的for ... of循环。

当然更好的方法,是直接使用iterable内置的方法forEach

let m = new Map([['wang',11],['li',12],['ye',13]]);
m.forEach(function(value,key,map){
    console.log(key + ': ' + value);
});

let a = [1,2,3];
a.forEach(function(value,index,array){
    console.log(value);
});
let s = new Set([3,2,1]);
s.forEach(function(key,samekey,set){
    console.log(key);        
});

class

ES6 引入了 class 是为了方便实现父类与子类之间的继承。让继承写起来更方便,也更易读。

举个例子:

//创建父类,定义共享函数
class Book{
    //构造函数
    constructor(props){
        this.name = props.name || '书';
        this.year = props.year || 0;
        this.author = props.author || '侠名';  
    }
    //共享函数
    sayName(){
        console.log( this.name );  
    }
}
//创建子类,继承父类
class StoryBook extends Book{
    constructor(props){
        super(props);//调用父类的构造方法
        this.kind = 'StoryBook';
        this.pages = props.pages || 0;
    }
}
//创建实例
var book_theThreeKingdoms = new StoryBook({name:'三国演义'});
console.log( book_theThreeKingdoms.name );//三国演义

symbol

symbol 是ES6引入的第 6 种基本数据类型,目的是创建独一无二的属性名,解决属性名冲突的问题。

let s = Symbol();
console.log(s);//Symbol()
console.log(typeof s);//"Symbol"
let a = Symbol('age');
let b = Symbol('age');
console.log(a === b);//false

s,a,b 都是一个 Symbol 类型的值,都是独一无二的。

Symbol 是为对象属性名而生,还是来看看 Symbol 怎么作为对象的属性名吧。

使用 Symbol 类型作为对象属性名时,要用[ ]括号记法,不能用点好看哦运算符。

let name = Symbol('name');
obj[name] = 'wang';

对象上的 Symbol 类型的属性,无法通过Object.keys()、Object.getOwnPropertyNames() 来获取。

可以使用 Object.getOwnPropertySymbols()方法获取一个对象上的Symbol属性名。

也可以通过Reflect.ownKeys() 返回所有类型的属性名,包括常规属性名和 Symbol 类型的属性名。

Symbol.for():用于创造相同的 Symbol 类型

Symbol.keyFor():用于查看 Symbol.for()指定的值。

let s0 = Symbol('s0');
let s1 = Symbol.for('s2');
let s2 = Symbol.for('s1');
let s3 = Symbol.for('s2');

console.log(Symbol.keyFor(s0));//undefined
console.log(Symbol.keyFor(s1));//s2
console.log(s3 === s1);//true

上一篇 JS 浏览器对象

下一篇 JS 中的 Ajax

Comments

Content