ECMAScript 6 教程

ECMAScript 6(简称ES6)是JavaScript语言的下一代标准。

作者 度 日期 2016-12-24
ECMAScript 6 教程

‘use strict’;
在低版本浏览器下只是一个字符串不会报错在高版本浏览器下严格执行js;


一,let和const

1,块级作用域
for (var i = 0; i < 5; i++) {
setTimeout(function(){
console.log(i);
},2000)
}
// 结果为5 正常的 因为for循环执行完才执行的settimeout
for (let i = 0; i < 5; i++) {
setTimeout(function(){
console.log(i);
},2000)
}
// 0 1 2 3 4
for (var i = 0; i < 5; i++) {
;(function(i){
setTimeout(function(){
console.log(i);
},2000)
})(i); //前后分号避免与其他代码的冲突
}
//0 1 2 3 4 闭包的方式实现
2,关于let
ES6新增了let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。
  • var 存在的问题

    1. 没有块级作用域
    2. for循环变量共享
  • let的好处

    1,块级作用域{}
    2,不会污染window

    let a = '1';
    let b = '123'; //不在window上不会污染window的全局变量
    window.b = '456';

    3,for循环都可以用i
    4,同一个作用域中 重新定义会报错

    let a = '123';
    let a = '345';

    5,不存在变量的预定义 (不会提前定义)

3,关于const
const声明一个只读的常量。一旦声明,常量的值就不能改变。const是一个新的定义方式,let 是取代var的方式;
  • 定义后不允许被修改
  • 不同块级作用域可以重名定义
    const a = '123';
    a = '345';
    console.log(a); //会报错 不允许修改值

二,解构赋值

解构赋值:变量的批量赋值(把右侧的数据类型赋值到左侧构造的相似的数据类型中)
1,示例
let arr = [1,2,3];
//console.log(arr[0]) 1
//console.log(arr[1]) 2
//console.log(arr[2]) 3
let [a,b,c] = arr;
console.log(arr); //1 2 3
let arr = [1,[2.1,2.2],3];
let [a,[b1],c] = arr;
console.log(a,b1,c); //1 2.1 3
let arr = [1,2,3,4,5];
// ...扩展运算符
let [a,b,...n] = arr;
console.log(a,b,n)
2,对象的解构赋值
'use strict';
let obj = {
a:'a',
b:'b',
c:'c'
}
let {x,y,z} = obj;
console.log(x,y,z); //underfind underfind underfind
为什么都是underfind呢 因为对象是无序的 不能保证x就对应a;
let obj = {
a:'a',
b:'b',
c:'c'
}
let {a,b,c} = obj;
console.log(a,b,c); //a,b,c
let obj = {
a:'a',
b:'b',
c:'c',
arr:[1,2,3]
}
let {a:mya,b:myb,c:myc,arr:[ , ,x]} = obj;
console.log(mya,myb,myc,x) //a,b,c,3

三,闭包的区别

1,正常js的闭包的写法
;(function(){})();
2,es6闭包
es6 只需要一个大括号 {}

四,函数

function add(x=0,y=0){
return x+y;
}
let res =add('wqeqwe',undefined);
console.log(res);
1,作用域的隔离
let x = 1;
function add(x,y){
x = 10;
return x + y;
}
let res = add(1,2);
console.log(x); //1 x与add函数内的x没有关系
console.log(res); //12
function add(...ary){
let res = 0;
for(let i=0,len=ary.length;i<=len;i++){
//for(let i=0; i<=ary.length;i++){ 为什么不用这种方法而是先定义一个len,避免每次都判断ary的长度而损耗性能
res+=i;
debugger; //自动启用debug模式,不用手动打断点
}
return res;
}
let res = add(1,2,3,4,5);
console.log(res); //15
//这个写法等同于上面的写法
function add(){
let res = 0;
for(let i = 0, len = arguments.length; i <= len; i++ ){
res += i;
}
return res;
}
let res = add(1,2,3,4,5);
console.log(res); //15
求最大值
let arr = [1,10,100,3000];
let m = Math.max.apply(null,arr);
//let m = Math.max(...arr); 扩展运算符写法
console.log(m);
2,箭头函数
let fun1 = function(num){
return num +1;
} //正常函数写法
let fun2 = (num) => num+2; //es6函数写法1 只能定义匿名函数
let fun2 = (num)=>{
return num +2;
} //es6函数写法2 只能定义匿名函数
let res1 = fun1(1);
let res2 = fun2(2);
console.log(res1,res2); //2,4
1,乘方算法
let arr = [1,3,7,9];
let r = arr.map(function(item,index,arr){
return item*item;
})
let r1 = arr.map((item,index,arr) => {
return item*item;
})
let r2 = arr.map((item,index,arr) => item*item)
let r3 = arr.map(item => item*item)
console.log(r3); //1,9,49,81
3,箭头函数的this关键字
function func(){
//setTimeout(function(){
//console.log(this.id); //dengfind
//})
setTimeout(()=>{
console.log(this.id); //这是id
})
}
let obj = {
id:'这是id'
}
func.call(obj);

五,第七种数据类型Symbol

// 第七种数据类型 Symbol
let sym = Symbol();
console.log(typeof sym); //symbol
let sym1 = Symbol('sum');
let sym2 = Symbol('sum');
console.log(sym1 == sym2); //false
console.log(sym1.toString() == sym2.toString()); //true 不可以参加运算 toString后才可以
1,模板字符串
let a = '我是'
//let es6str = `123${a+'中间数字'}456`; //${}进行转意
let es6str = `123\$\{a+'中间数字'\}456`; //这样转意${}能输出出来
console.log(es6str);

另外有 doT.js小而巧的模板引擎

//插入的可以是表达式
function jia(x,y){
return x + y;
}
let num = `1+2=${jia(3,4)}`;
console.log(num);
let isgril = `i am a ${true ? 'boy':'gril'}`;
console.log(isgril)
// 自动类型转换
let typeStr = `${1,2,3}`;
console.log(typeStr);

六,数组

1,数组拷贝slice和es6属性Array.from
let arr1 = [1,2,3];
//let arr2 = arr1.slice(0); //复制一个新数组
let arr2 = Array.from(arr1); //es6 复制一个新数组
arr1[0] = 111;
console.log(arr1,arr2)
打印出的log是:
[111,2,3]
[1,2,3]
let obj = {
a:'a',
b:'b'
}
let arr1 = [1,2,3,obj];
let arr2 = Array.from(arr1); //es6 复制一个新数组
arr1[0] = 111;
console.log(arr1,arr2)
打印出的log是:
[111,2,3,{a:'a',b:'b'}]
[1,2,3,{a:'a',b:'b'}] //obj是引用类型的,也会被拷贝进来
2,Array.of 新建数组
let arr1 = new Array(5);
let arr2 = new Array(1,2,3);
console.log(arr1,arr2);
打印出的log是:
[] //长度是5,数组就一个参数的话 会设置成是数组长度;
[1,2,3]
let arr1 = Array.of(5);
cosole.log(arr1);
打印出的log是:
[5] //Array.of传一个参数的话不会是设置数组的长度,解决上面的问题;
3,Array.copyWithin 复制并替换数组某一块
// Array.copyWithin 把数组的某一块复制并替换到另一块
// target被覆盖的下标
// start 截取开始的下标
// end 截取结束的下标的下一个
//Array.prototype.copyWithin(target,start=0,end=this.length)
let arr = [6,7,8,9,10,11,12,13];
arr.copyWithin(4,0,3); //从第三个下标开始
console.log(arr); // [6,7,8,9,6,7,8,13]
4,Array.fill 复制并替换数组某一块
// Array.fill 把数组的某一块复制并替换到另一块
// target被覆盖的下标
// start 截取开始的下标
// end 截取结束的下标的下一个
//Array.prototype.fill(target,start=0,end=this.length)
let arr = [6,7,8,9,10,11,12,13];
arr.fill('aa',1,3); //从第1个下标开始
console.log(arr); // [6,'aa','aa',9,6,7,8,13]
5,find 查找元素 和 findIndex 查找元素下标
let arr = [1,'3',3,4,5];
let res = arr.find((item,index,array)=>{
return item == '1';
})
console.log(res,typeof res); //1 number
let arr = ['1','3',3,4,5];
let res = arr.find((item,index,array)=>{
return item == '1';
})
console.log(res,typeof res); //1 string
let arr = ['9',1,'1','3',3,4,5];
let res = arr.findIndex((item,index,array)=>{
return item == '1';
})
console.log(res,typeof res); //下标为1 number
6,includes 查找元素 找到返回true 找不到返回false
let arr = [1,2,3,4];
let res1 = arr.indexOf(4);
let res2 = arr.includes(0);
console.log(res1); //下标为3
console.log(res2); //没有0这个值 返回false
let arr = [1,2,3,4,NaN];
let res1 = arr.indexOf(NaN);
let res2 = arr.includes(NaN);
console.log(res1); //-1
console.log(res2); //true
7,keys获取下标和entries获取下标及对应值
let arr = [1,3,5,7];
let res1 = arr.keys();
let res2 = arr.entries();
console.log(res1); //ArrayIterator {} 迭代器 {"1", "3", "5", "7"}
for (let item of res1){
console.log(item) //获取arr的下标 0 1 2 3
}
for (let item of res2){
console.log(item) //获取arr的下标及值 [1,2] [1,3] [2,5] [3,7]
}

七,对象

1,简写
let a = '1';
let b = '2';
let c = '3';
let obj = {
a,b,c
}
console.log(obj); //{a: "1", b: "2", c: "3"}
2,区别
let ob1 = {
add : function(){
//对象的正常写法
}
}
let ob2 = {
add(){
//对象的es6写法
},
[dele]:'1212'
}
3,is 更严格更合理的值相等
'use strict'
// == 和 === 是相等和严格相等
//Object.is() 是更严格更合理的值相等 两个对象依然是不相等的
console.log(+0 === -0); //true
console.log(Object.is(+0,-0)); //false
console.log(NaN === NaN); //false
console.log(Object.is(NaN,NaN)); //true
console.log({} === {}); //false
console.log(Object.is({},{})); //false
4,对象的合并
'use strict';
let obj1 = {x:'1'};
let obj2 = {y:'2'};
let obj3 = {x:'3'};
let obj4 = Object.assign(obj1,obj2,obj3);
console.log(obj4) //{x: "3", y: "2"} 合并了obj2里面的y,被obj3里面的x替换.

八,Set和map

1,Set (add delete has clear)
//new Set
let s = new Set('1023');
console.log(s); //{"1", "0", "2", "3"}
//delete
let s = new Set('1023');
console.log(s); //{"1","0", "2", "3"}
let dele = s.delete('1');
console.log(dele); // true删除成功
console.log(s); //所以s的结果为{"0", "2", "3"}
//add
let s = new Set('1023');
let add = s.add('bb');
console.log(add); //{"1","0", "2", "3", "bb"}
//has
let s = new Set('1023');
let add = s.has('1');
console.log(add); //true
//clear
let s = new Set('1023');
let add = s.clear();
console.log(add); //没有返回值 undefined
//entries
let s = new Set('1023');
let add = s.entries(); //迭代器
console.log(add[0]); //undefined 只能用for of遍历出来
for(item of add){
console.log(item);//["1", "1"],["0", "0"],["2", "2"],["3", "3"]
}
//keys
let s = new Set('1023');
let keey = s.keys();
console.log(keey) // {"1", "0", "2", "3"}
for(item of keey){
console.log(item) //1 0 2 3
}
let y = new Set(['a','b','c']);
let arr = [...y];
console.log(arr); //["a", "b", "c"]
//数组去重 思路
let x = [1,1,1,1,2,2,4,4,5,5,5];
let q = new Set(x); //数组放进q
console.log(q); //给q去重 [1,2,4,5]
let z = Array.from(q);//去重后放进z里面
console.log(z) //[1,2,4,5]
//数组去重 简写
let x = [1,1,1,1,2,2,4,4,5,5,5];
x = Array.from(new Set(x));
console.log(x); //[1,2,4,5]
2,Set实现js中的集合运算
集合运算有三种 并集 交集 差集
let a1 = new Set([1,3,5,7]);
let a2 = new Set([1,2,3,4]);
//并集:合并去重
let bj = new Set(a1,a2);
//let bj = new Set([...a1,...a2]);
console.log(bj); //{1, 3, 5, 7}
//交集:共有的部分
let jj = [...a1].filter((item)=>{
return a2.has(item);
})
let qq = new Set(jj);
console.log(qq) //[1,3]
//交集简写
let qq = new Set([...a1].filter(item=> a2.has(item)));
console.log(qq) //[1,3]
//差集:我有你没有的部分
let cj1 = new Set([...a1].filter(item => !a2.has(item)));
console.log(cj1);//{5, 7} a1有a2没有的
let cj2 = new Set([...a2].filter(item => !a1.has(item)));
console.log(cj2);//{2, 4} a2有a1没有的
3,map 和set的用法是一样的

九,promise

  • 每个promise有三种状态:pending,resolve,reject
  • 从初始状态到成功 pending –> resolve
  • 从初始状态到失败 pending –> reject

promise

如何构造一个promise?

构造一个promise实例需要给promise传进一个函数,传进的函数需要有两个形参,两个形参都是function类型的参数:

  • 1:第一个形参运行后会让promise实例处于resolve状态,所以我们一般给第一个形参命名为resolve,约定resolve为成功状态。
  • 2:第二个形参运行后会让promise实例处于reject状态,所以我们一般给第一个形参命名为reject,约定reject为失败状态。
let promise = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('resolve');
},2000)
})
写一个实例
'use strict'
let p = new Promise((resolve,reject)=>{
setTimeout(()=>{
//resolve('通过');//下面就会走then
reject('拒绝');//下面就会走catch
},3000)
})
p.then((value)=>{
console.log(value,':成功!');//3秒之后resolve之后才then成功; //通过:成功!
}).catch((err)=>{
console.error(err:,'捕获失败!'); //拒绝: 捕获失败!
})
let p = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('通过');
},3000)
})
//可以简写成
let p = new Promise((resolve,reject)=>{
setTimeout(resolve,3000,'通过')
})
Promise构造函数上的方法:
  • [1] Promise.all(Array)返回一个promise,等待参数中所有的promise都处于resolve状态后会触发,返回promise实例的resolve状态。

    let proimse1 = new Promise((resolve,reject)=>{
    setTimeout(resolve,1000,'proimse1');
    });
    let proimse2 = new Promise((resolve,reject)=>{
    setTimeout(resolve,3000,'proimse2');
    });
    let proimse3 = new Promise((resolve,reject)=>{
    setTimeout(resolve,2000,'proimse3');
    });
    Promise.all([proimse1,proimse2,proimse3])
    .then((value)=>{
    console.log(value);//["proimse1", "proimse2", "proimse3"]
    debugger;
    }).catch((err)=>{
    console.log(err);
    })
    注:若其中一个为reject,那整个都失败了。
  • [2] Promise.race(Array)返回一个promise,等待参数中任何一个promise先变成resolve就会触发。(最快的一个resolve触发then)

    let proimse1 = new Promise((resolve,reject)=>{
    setTimeout(resolve,4000,'proimse1');
    });
    let proimse2 = new Promise((resolve,reject)=>{
    setTimeout(resolve,3000,'proimse2');
    });
    let proimse3 = new Promise((resolve,reject)=>{
    setTimeout(resolve,2000,'proimse3');
    });
    Promise.race([proimse1,proimse2,proimse3]).then((value)=>{
    console.log(value); //proimse3
    }).catch((err)=>{
    console.log(err);
    })
  • [3] Promise.resolve()立即返回一个resolve状态的实例。

    Demo1:

    let p1 = Promise.resolve('success');
    p1.then((value)=>{
    console.log(value);
    }) //返回的是状态为resolve的promise
    new Promise(()=>{
    }) //返回的是状态为pending的promise
    let p1 = Promise.resolve('success');
    //是下面这个promise的简写
    let p1 = new Promise((resolve,reject)=>{
    resolve('success');
    })

    Demo2:

    let p1 = new Promise((resolve,reject)=>{
    setTimeout(resolve,1000,'成功!');
    })
    let p2 = Promise.resolve(p1);
    p2.then((value)=>{
    console.log(value); //成功!
    })

    Demo3:

    //类promise对象
    let thenobj = {};
    thenobj.then = (resolve,reject)=>{
    setTimeout(resolve,1000,'成功!');
    }
    let p1 = Promise.resolve(thenobj);
    p1.then((value)=>{
    console.log(value); //成功!
    })

    Demo4:

    let p1 = Promise.resolve();
    p1.then((value)=>{
    console.log(value); //undefined
    //debugger;
    })
  • [4] Promise.reject()立即返回一个reject状态的实例。

    let p1 = Promise.reject('err');
    p1.catch((error)=>{
    console.log(error);
    })
  • [5] Promise.then()的执行时机。

let p1 = Promise.resolve('chenggong');
p1.then((value)=>{
console.log(value); //后执行 因为then是处理异步的;
})
console.log('saaadfsadf'); //先执行
let p2 = new Promise((resolve,reject)=>{
console.log('inpromise'); //顺序1
resolve('chenggongle');
});
p2.then((value)=>{
console.log(value); //顺序3
});
console.log('outpromise'); //顺序2
setTimeout(()=>{
console.log('settimeout'); //顺序4
},0);
  • [6] Promise的链式调用。
    let p1 = new Promise((resolve,reject)=>{
    setTimeout(resolve,1000,'chenggongle');
    })
    p1.then((value)=>{
    console.log('1then',value); //1then chenggongle
    return 111; // 传给下一个then
    }).then((value)=>{
    console.log('2then',value); //2then 111
    return Promise.reject('1err');//传给下一个catch
    }).catch((err)=>{
    console.error('1catch',err); //1catch 1err
    return Promise.resolve('3then')//传给下一个then
    }).then((value)=>{
    console.log(value) //3then
    })

十,Generator

  • 1,有点像一个函数内部有多个函数,是一个状态机
  • 2,generator 生成器
  • 3,yield 生成
1,实例
function* gen(){ //function* 定义一个generator函数
yield 'hello';
yield 'ni';
yield 'hao';
return 'end';
}
//Genertor 返回的不是一个返回值也不是第一个生成的内容
//迭代器是一个可以遍历的对象
let res = gen();
//next() 是一个固定的属性
console.log(res.next()); //{value: "hello", done: false}
console.log(res.next()); //{value: "ni", done: false}
console.log(res.next()); //{value: "hao", done: false}
console.log(res.next()); //{value: "end", done: true}
console.log(res.next()); //{value: undefined, done: true} 迭代完了 所以done为true
function* gen(){ //function* 定义一个generator函数
yield 'hello';
yield 'ni';
yield 'hao';
return 'end';
}
//generator是个迭代器 所以可以用for of来实现;
for (let item of res) {
console.log(item); //hello ni hao !
}
console.log([...res]); //["hello", "ni", "hao"]
2,连续运行的Generator:
function* genfun(inv){
let one = yield new Promise((resolve,reject)=>{
setTimeout(resolve,1000,'one:'+ inv);
});
let two = yield new Promise((resolve,reject)=>{
setTimeout(resolve,500,'two:'+ one);
});
let three = yield new Promise((resolve,reject)=>{
setTimeout(resolve,2000,'three:'+ two);
});
}
let res = genfun('initt');
//console.log(res.next().value);
res.next().value.then((val)=>{
console.log(val);
res.next(val).value.then((val)=>{
console.log(val);
res.next(val).value.then((val)=>{
console.log(val);
})
});
});