【ES6】ES6语法简述

声明


1. const

静态资源变量声明,不能修改变量的指向。即
- 是基本数据类型,则不能修改它的值。
- 是引用数据类型,则不能修改它的指向。

2. let

2.1. 不能重复声明,没有变量提升
先定义后使用,变量定义不会自动提升,否则会报变量未定义的错误。
2.2 块作用域
每个大括号被视为一个作用域。逐级外层作用域查找,直到找到为止。
2.3 for语句视为一个作用域

(function(){
    let a = [];
    for (let i = 0; i < 10; i++) {
      a[i] = function () {
        console.log(i);
      };
    }
    a[6](); // 6
})();

按照我们原有的思维会认为这里应该输出的是10,但并不是。变量i的声明是在for()中,它的作用域就是(),每次循环产生的i并不是同一个i。这样会有人问i++,是怎么执行的。这是因为 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。

for的特殊使用:

(function(){
    for(let i = 0;i<3;i++){
        let i = "abc";
        console.log(i)
    }
    for(let i = 0;i<3;i++){
        console.log(i)
    }
})();

输出:abc abc abc 1 2 3


总结:

  • 善用for,为DOM节点注册事件时,可以减省闭包的使用。

基本数据类型

JS基本数据类型有String、Number、Boolean、Null、Undefined,ES6新增Symbol的基本数据类型。


1. String


1.1 扩展

startsWith、endsWith、padStart、padEnd、repeat

1.2 Unicode编码

  • 对于大于\uFFFF的数值,通过\u{20BB7}可以正常识别。 ES5的
  • charAt不能识别大于\uFFFF的字符,ES6提供at。

1.3 字符与Unicode之间的转换

  • codePointAt //返回字符的Unicode的编码
  • String.fromCodePoint() //返回Unicode编码对应的字符

1.4 模板字符串

(function(){
    let [name,time] = ["Bob","today"];
    let str = `Hello ${name}, how are you ${time}?`
    console.log(str)
})();

模板字符串中可以使用${}引用变量,有点类似与JSP的写法。需要注意的是,模板字符串可以将空格、换行如实打印出来。


2.Number

新增方法,isFinite、isNaN、isInteger

let a = Number.isNaN("abc")
let b = Number.isNaN(Number("abc"));
console.log(a,b)    //false true

在ES5中,我们知道NaN===NaN的值是false,判断一个数是不是NaN是不太容易的,ES6直接提供了isNaN方法可以判断是否是NaN。


3. Null 传导运算符

let firstName = message?.body?.user?.firstName || 'default';
console.log(firstName)

等价于

let firstName = 'default';
if(message && message.body && message.body.user && message.body.user.firstName){
    firstName = message.body.user.firstName;
}

这个设计避免了大量的判断,但是尚未支持。


4. Symbol

表示独一无二的值,没有两个相等的Symbol。一般用于对象的属性名称,避免属性的误操作。

let [a,b] = [Symbol(),Symbol()];
let [c,d] = [Symbol('abc'),Symbol('abc')];
let [e,f] = [Symbol.for('swl'),Symbol.for('swl')];

let rs_a_b = Object.is(a,b);
let rs_c_d = Object.is(c,d);
let rs_e_f = Object.is(e,f);

console.log(rs_a_b,rs_c_d,rs_e_f)   //false false true

Symbol常用于对象的key值,避免将已存在的属性覆盖。


引用数据类型

JS引用数据类型Array、Object,新增Set、WeakSet、Map、WeakSet。


1. 解构

1.1 数组解构

a. 赋值操作

(function(){
    let [a,b,c] = [1,2,3];
    console.log(a,b,c);

    let [d,...e] = [11,22,33,];     //rest操作
    console.log(d,e);
})();

数组解构时,依照一一对应关系,同时允许使用rest操作符。但是要注意的是,rest操作符只能放在最后一位,rest操作符返回的是一个数组。

b. 默认值

(function(){
    let [x, y = 'b',z = 13] = ['a',undefined,]; // undefined或者不写任何东西,默认值才生效
    console.log(x,y,z);
})();

注意:不能写null,null会赋值给变量。

c. 惰性执行

(function(){
    function a(){
        console.log("**");
        return 5;
    }

    let [aa=a()] = [];  //会输出“**”
    let [bb=a()] = [1];  //不会输出“**”
})();

如果默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值。

1.2 对象解构

对象解构时根据属性名匹配模式,不再是像数组依靠位置关系进行解构。
a. 两种解构方式

(function(){
    let { foo } = { foo: 'aaa', bar: 'bbb' };//第一种
    console.log(foo)    ///aaa

    let { foo: bar ,bar:foe} = { foo: 'aaa', bar: 'bbb' };  //第二种 通过模式解构
    console.log(bar,foe)    //aaa bbb
})();

第一种:依靠相同属性名直接获取。
第二种:通过模式将获取的value值赋值给新的变量。

b.嵌套解构

(function(){
    let obj = {
        p: [
            'Hello',
            { y: 'World' }
        ]
    };

    let { p: [x, { y }] } = obj;
    console.log(x,y)    //Hello World

ES6允许对象数字混合在一起进行解构,只要符合数组和对象的解构规则即可成功解构。

c. 字符串解构

(function(){
    let str = 'qwert';
    let [a,b,c,d] = str;
    let {length:len} = str;
    console.log(a,b,c,d,len)
})();

字符串被认为是一个数组和对象的混合体,它符合数组和对象的特性。首先,它有可遍历的字符,可以认为是数组。其次,具有可枚举的属性length,可以认为是对象。

2. 数组

新增遍历:for…of…、entries、keys、values

2.1 for…of…

  • a. 这是最简洁、最直接的遍历数组元素的语法;
  • b. 这个方法避开了for-in循环的所有缺陷;
  • c. 与forEach()不同的是,它可以正确响应break、continue和return语句。

与解构搭配使用:

let arr = [{name:'abc',id:1},{name:'def',id:2},{name:'hij',id:3}]
for(let {id,name} of arr){
    console.log(id,name)
}

2.2 entries、keys、values

返回一个迭代器,通过next进行操作。而Object.entries、Object.keys、Object.values,返回的只是一个数组,不能使用next操作。

var arr = ["a", "b", "c"];

let a = arr.entries();  //迭代器也可以使用for...of...遍历

console.log(a.next())   //{ value: [ 0, 'a' ], done: false }
console.log(a.next())   //{ value: [ 1, 'b' ], done: false }
console.log(a.next())   //{ value: [ 2, 'c' ], done: false }
console.log(a.next())   //{ value: undefined, done: true }

迭代器与Java中迭代器类似,具有next( )操作。

3. ArrayBuffer

存储二进制数据,主要在前端会使用:File API、XMLHttpRequest、Fetch API、Canvas、WebSockets
参考链接:http://es6.ruanyifeng.com/#docs/arraybuffer

4. Object

4.1 声明

(()=>{
    let [name,obj_a,obj_b] = ['abc',{},{}];
    let obj = {
        name,
        [obj_a]:'obj a',
        [obj_b]:'obj b',        // '[object Object]':'obj b'
        ['desc']:'this is description',
        [Symbol('sym')]:'this is a Symbol'
    }
    console.log(obj)
})();

与ES5向比较,声明一个对象属性的方式灵活很多,具体:
- a. 省略key的书写,默认变量名、方法名、对象名为key值。
- b. 允许使用[expression]定义key,若expression不是个字符串,则将其转化为字符串

4.2 Object.is(a,b)

返回Boolean变量,它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。

(()=>{
    Object.is('foo', 'foo')// true
    Object.is({}, {}); //false
    +0 === -0 //true
    NaN === NaN // false

    Object.is(+0, -0) // false
    Object.is(NaN, NaN) // true
})();

注意: Object.is(Nan,NaN)的返回值是true。

4.3 Object.entries、Object.keys、Object.values

返回由对象的键值对、健、值组成的数值,可使用for…of…遍历。注意:若参数不是个对象,隐式转化为对象。Boolean、Number不能被转化为对象,所以返回一个空数组。

let a = true;

console.log(Object.entries(a))  //[ ]
console.log(Object.keys(a)) //[ ]
console.log(Object.values(a))   //[ ]

注意:通过这种方式获取的数组不能使用next( )进行遍历

4.4 原型与属性获取

方法 描述 备注
Object.getPrototypeOf() 获取原型属性 不能获取proto设置的属性
Object.setPrototypeOf() 设置原型属性
Object.getOwnPropertyDescriptors() 获取自身属性 {name:{value:’swl’,writable:true,enumerable: true,configurable: true }}
Object.getOwnPropertySymbols() 获取自身的Symbol类型属性
Object.getOwnPropertyNames() 获取自身的属性名 不包含Symbol类型的key
Reflect.ownKeys(obj) 获取非原型属性名

4.5 Object.assign( )

合并对象,如果参数不是对象,则先转化为对象。Null和undefined不能转化对象,会报错。
注意:执行浅拷贝…

4.6 Map和WeakMap

(()=>{
    let map = new Map([["name","swl"],["age",12],["sex","boy"]]);
    for(let [key,value] of map){
        console.log(`key: ${key} ,value: ${value}`)
    }

    let entries = map.entries();
    for(let [key,value] of entries){
        console.log(`key: ${key} ,value: ${value}`)
    }
})();

Map可接受对象作为key,不会将对象转化为字符串。

WeakMap 与 Map 在 API 上的区别主要是两个,
- 1.没有遍历操作(即没有key()、values()和entries()方法)
- 2.没有size属性。
因此,WeakMap只有四个方法可用:get()、set()、has()、delete()。一般用于存储HTML DOM节点。

4.7 Set和WeakSet

(()=>{
    let set = new Set(['a','b','c']);
    for(let ele of set){
        console.log(ele)
    }

    let entries = set.entries();
    for(let [key,value] of entries){
        console.log(key,value)
    }
})();

Set可接受NaN值。

WeakSet只接受对象,一般用于存储HTML DOM节点。WeakSet 不能遍历(即没有key()、values()和entries()方法),也没有size属性。WeakSet只有四个方法可用:add()、has()、delete()。


箭头函数

let getName = name => name;
console.log(getName('swl'));    //swl

let sum = (a,b) => {
    let sum = a + b;
    return sum;
}
console.log(sum(2,3));  //5
  • 1.箭头函数不能使用new,它没有构造器。
  • 2.箭头函数没有自己的this,this指向宿主环境。若没有宿主环境,并且显示调用’use strict’,this为undefined;非显式调用,this指向window(global)。

拦截器 Proxy

Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程。Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。


(()=>{
    const log = console.log;
    var proxy = new Proxy({}, {
        get(target, key, receiver) {
            return `${target[key]}`;
        },
        set(target, key, value,receiver){
            return Reflect.set(target, key, `TEST-${value}`,receiver);
        }
    });

    proxy.name = 'profile';
    proxy.time = '2017/9/9';
    proxy.action = 'download';
    log(proxy.time);    //TEST-2017/9/9
    log(proxy.name);    //TEST-profile
    log(proxy.action);  //TEST-download
})();

new Proxy(obj,handler)

参数obj:对象,{}或者[ ]
参数handler:处理器对象,可选处理方法get、set、apply、has…


Iterator和Generator

ES6规定对象只要具有Symbol.iterator属性,那么此对象就是可遍历的。Symbol.iterator的返回值是一个遍历器,可以通过next()和for…of…遍历。


(()=>{
    let arr = ['a','b','c'];
    let gen = arr[Symbol.iterator]()
    console.log(gen.next())
    console.log(gen.next())
    console.log(gen.next())
    console.log(gen.next())
    console.log(gen.next())
})();

也可以使用for…of…遍历出全部内容


用户可以自定生成器,返回一个遍历器对象。

(()=>{
    function* he(){
        yield 'hello';
        yield 'world';
    }
    let a = he();
    console.log(a.next())
    console.log(a.next())
    console.log(a.next())
})();

此外,使用Generator可以实现执行同步事件的效果。原理:可以通过yield的返回值判断是否继续执行next( )。


Promise

Promise具有三个状态,pending(进行中)、resolved[fulfilled](已完成)、rejected[rejected](已拒绝)。
【ES6】ES6语法简述_第1张图片

promise的状态转换,只能由未完成到已完成或者已拒绝转换,这个过程不能逆转。

//Promise实例
new Promise((resolve,reject)=>{
    resolve('fulfilled...')
}).then((val)=>{
    console.log(val)
}).catch(error => {
    console.log(error)
})

方法:

Promise.all(arr)

参数arr:arr中存放的是promise。
返回值:当所有的promise处于完成态时, Promise.all(arr)转变为完成态,否则一直是未完成或者已拒绝。

Promise.race(arr)

参数arr:arr中存放的是promise。
返回值:当任何一个的promise处于完成态时, Promise.race(arr)转变为完成态。

Promise.resolve(func)

参数func:普通function
返回值:处于完成态的promise

Promise.reject(func)

参数func:普通function
返回值:处于已拒绝的promise


async/await

  • 同步的实现,从回调到Generator,再到Promise,再到async/await。
  • Node 7.6版本支持async/await的写法。

let timeout = (t)=>{
    return new Promise(resolve=>{   
        setTimeout(resolve,t)   
    })
}

(async ()=>{
    console.log(`两秒之后打印:`)
    await timeout(2000)
    console.log(`hello world`)
})();

async

通过关键字对function进行标识,指明这是一个异步方法。
需要注意的是:

通过async标识的function,其返回值是个Promise。比如,在函数内部返回的是个一个字符串,async自动将它封装成一个Promise。


await

await愿意是等待,它会等待它后面紧跟着的表达式的执行完成。分两种情况:

  1. 若await后面是个Promise对象,它会一直等到resolve或者reject的完成,返回最终的处理结果。
  2. 若await后面是个非Promise对象,则直接返回表达式的返回值

参考url:http://cnodejs.org/topic/5640b80d3a6aa72c5e0030b6


class


1. 构造器

class Persion {
    constructor(name,age){
        this.name = name;
        this.age = age;
    }

    getName(){
        return this.name;
    }

    static getDesc(){
        return `this is Persion class`;
    }
}

let persion = new Persion('bob',11);
console.log(persion.getName()); //bob
console.log(Persion.getDesc()); //this is Persion class

a. typeof Persion == ‘function’;
b. Constructor、普通方法是定义在class的原型上的,等同于Persion.prototype = {constructor,getName};静态方法,等同于Persion.getDesc = func;


2. class表达式

let tool =  class Tool {
    static print(){
        return Tool.getDesc();
    }

    static getDesc(){
        return `this is Tool class`;
    }
}

console.log(tool.getDesc());    //this is Persion class

Tool为内部使用,tool为外部使用。若不需要引用Tool,则可以省去Tool,即let tool = Class {……};


3. 静态方法、私有方法、私有属性

静态方法:static+方法名,如,static getDesc
私有方法:_+方法名,如,_getName(){}
私有属性:#+属性名,如,#name
私有方法、私有属性仅是一种提议,未实现


4. new.target

返回:new命令作用于的那个constructor。

使用:创建一个不允许被实例化的工具类。new.target只能在constructor使用。

class Tool {
    constructor(){
        if(new.target == Tool){
            throw new Error('this class can not be instanced')
        }
    }

    static getLocalTime(){
        return new Date().toLocaleString();
    }
}
new Tool()  //抛出一个Error
console.log(Tool.getLocalTime())

class的继承


eg:Man继承自Persion

const log = console.log;

class Persion{
    constructor(name,age){
        this.name = name;
        this.age = age;
    }
    toString(){
        return `the presion's name is ${this.name} ,and age is ${this.age}`;
    }
    static getDesc(){
        return 'this is Persion class'
    }
}
class Man extends Persion{
    constructor(name,age){
        super(name,age);
    }
    toString(){
        return super.toString();    //super指向父类的原型
    }
    static getOwnDesc(){
        return super.getDesc();
    }
}

let m = new Man("swl",2343);
log(m.toString())   //the presion's name is swl ,and age is 2343
log(Man.getOwnDesc())  //this is Persion class
log(Man.getDesc())  //this is Persion class

supper

supper:既可以当方法用,也可以当做对象使用。
1. super作为函数调用时,代表父类的构造函数。ES6规定,必须在子类的constructor中调用一次supper,否则,报错。
2. super作为对象使用时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。

extends

extends A
A可以是多种类型的值,只要A具有prototype就可以。由于函数都有prototype属性(除了Function.prototype函数),因此A可以是任意函数。


声明:参考自自阮一峰老师《ES6入门》,有兴趣的可以去看下,url:http://es6.ruanyifeng.com/

你可能感兴趣的:(WEB前端)