ES6学习笔记

一、let、const、块作用域

let-cont相同点:
1.强制使用严格模式;
2.不能重复声明同意变量。
3.都能在 {} 块作用域中生效;(即作用域范围是:{} )
const:
1.声明5中基本类型之后,便不能修改值;但是声明变量,则存储的是对象的内存地址。
2.初始化时,必须赋值。

二、解构赋值 :对象和数组

共同点:
1.无匹配时返回undefined;
2.可以设置默认值;
3.优先级:赋值 > 设置的默认值 .> 无匹配时的undefined
数组解构:

let [a, b, ...c] = [1,2,3,4];  // a=1,b=2,c=[3,4]

应用场景:(数组值的对换)

let a = 1;
let b = 2;

[a, b] = [b, a];  //a=2,b=1

对象解构:重命名的name写在对象的value中;

let data = {
    title: 'abc',
    list: [
        {
            title: 'test...',
            des: 'des...'
        }
    ]
}

//拿到 第一层的title和第二层的title
let {title,list: [{title: cnTitle}]} = data;  //title='abc',cnTitle='test...'

三、正则的拓展

构造函数的拓展:

1.可以在构造函数的1参和2参添加修饰符;2参>1参(2参会覆盖1参)

2.reg.flags :修饰符的查询;(其中reg是一个正则的实例)

let r1 = new RegExp(/a/);
let r2 = new RegExp(/a/i);
let r3 = new RegExp(/a/i, 'g');
let str1 = 'AbcAd';
console.log( r1.test(str1), r1.flags );  //false ''
console.log( r2.test(str1), r2.flags );  //true  'i'
console.log( r3.test(str1), r3.flags );  //false 'g'  [产生了覆盖]

y修饰符: 更加严格的匹配,第一次和第二次匹配中间不能有任何的间隔。

  1. reg.sticky: 是否使用y修饰符。
let r1 = /a/i;
let r2 = /a/iy;

let s1 = 'AbAc';
let s2 = 'AAc';

console.log(r1.test(s1), r1.sticky); //true false
console.log(r2.test(s1), r2.sticky); //true true
console.log(r1.test(s1), r1.sticky); //true false
console.log(r2.test(s1), r2.sticky); //false true  [匹配更加严格,中间不能有任何间隙]

console.log(r1.test(s2 ), r1.sticky); //true false
console.log(r2.test(s2 ), r2.sticky); //true true
console.log(r1.test(s2 ), r1.sticky); //true false
console.log(r2.test(s2 ), r2.sticky); //true true  [中间没有任何间隙]

[补充]:字符的定义:字符是指计算机中使用的字母、数字、字和符号

在 ASCII 编码中,一个英文字母字符存储需要1个字节。在 GB 2312 编码或 GBK 编码中,一个汉字字符存储需要2个字节。在UTF-8编码中,一个英文字母字符存储需要1个字节,一个汉字字符储存需要3到4个字节。在UTF-16编码中,一个英文字母字符或一个汉字字符存储都需要2个字节(Unicode扩展区的一些汉字存储需要4个字节)。在UTF-32编码中,世界上任何字符的存储都需要4个字节。

[补充]:1字符 == 2字节 == 4个十六进制字母

let a = '稳';
let b = a.charCodeAt(0);  //转unicode编码
let c = b.toString(16);   //将unicode编码转十六进制

console.log(b, c);  //31283    '7a33'    “稳”字的unicode码,十六进制
console.log( b.fromCharCode(b) );  //稳
console.log( b.fromCharCode('0x'+c) );  //稳

在Unicode编码下的例子:
稳(1字符) == 2字节 [7a,33] == 4个十六进制字符[7,a,3,3]

u修饰符:匹配unicode字符,处理大于2字节长度的字符。
下面乱码的字符是 ,unicode十六进制是:20bb7,可以使用 String.fromCodePoint('0x20bb7') 方法转回字符(此方法为ES6方法)

let a = '?'; //unicode码字符大于4字节
let b = a.codePointAt(0);  //134071
let c= b.toString(16);  //20bb7

console.log( /u{20bb7}/.test('?') );  //false
console.log( /u{20bb7}/u.test('?') )  //true

s修饰符: s修饰符,可以使 点(.)匹配 字符
正则中,点(.)是一个特殊字符,代表任意的单个字符,但是行终止符除外:

// U+000A 换行符(
)

// U+000D 回车符(
)

// U+2028 行分隔符(line separator)

// U+2029 段分隔符(paragraph separator)

只是一个提案目前还不支持,es8中实现

    let r1=/test.go/s;
    let r2=/test.go/;

    let s = 'test
go';
    console.log(r1.test(s));  //true
    console.log(r2.test(s));  //false

四、字符串的拓展

下面乱码的字符是 ,unicode十六进制是:20bb7,可以使用 String.fromCodePoint('0x20bb7') 方法转回字符(此方法为ES6方法)

[补充]:.length属性: 计算长度时,每2个字节为一个字符。

let a = '稳';
let b = String.fromCodePoint('0x20bb7');

console.log(a.length);  // 1
console.log(b.length);  // 2

[补充]:ES5转码方法介绍: (只能转<=2个字节的字符)

  1. str.charAt(0) 返回第0位的字符;

  2. str.charCodeAt(0) 返回第0位字符的Unicode编码,可以使用.toString(16)转16进制;

  3. String.fromCharCode() 将Unicode编码转字符串,十六进制转法:str.fromCharCode('0x'+'7a33')

let str = '稳';

console.log( str.charAt(0) );    //稳
console.log( str.charCodeAt(0) );    // 31283
console.log( String.fromCharCode(31283) )  //稳

ES6转码方法介绍: (可以转> || <= 2个字节的字符)

  1. str.codePointAt(0) 将第0位转Unicode吗

  2. str.fromCodePoint() 将Unicode码转字符串

  3. for...of —> 可以正确的解析 > || <= 2字节的字符。

let @a = String.fromCodePoint('0x20bb7');  //@a 即上面几例中的乱码字符,使用这个方法就可以得到这个字符
let a = @a.charCodeAt(0);    //31283
let b = @a.codePointAt(0); //134071

String.fromCharCode(a);   //String.fromCodePoint(b);  // @a  ---> 这里代指 @a表示的字符,因为这个编辑器输出这个字符会乱码

字符串的检测:

1.str.includes('s') —> str中是否包含s

2.str.startWith('st') —>str是否以st开头

  1. str.endWith('ing') —> str中是否以ing结尾
let s = 'string';

console.log( s.includes('tr') )  //ture
console.log( s.includes('ti') )  //false  [测试不连续的字符]

console.log( s.startsWith('st') )  //true
console.log( s.startsWith('sr') )  //false [测试不连续的字符]

console.log( s.endsWith('ing') )  //true
console.log( s.endsWith('ig') )   //false  [测试不连续的字符]

模板字符串:
1.

let str = 'david';
`I am ${str}`  // I am david  为变量
    2.
function add(){
    console.log(arguments);
}
let user = {
    name: 'david',
    info: 'man'
}
add`I am ${user.name},${user.info}`

//arguments --->  ['I am ',',',''] 'david' 'man'

补位:(ES7)指定长度2,不够的补’0’

1.'1'.padStart(2,'0') —> 输出为:’01’

2.'1'.padEnd(2,'0') —> 输出为:’10’

let s1 = '1';
let s2 = '1.';

s1.padStart(3, '');  // '1'
s1.padStart(1, '0'); // '1'
s1.padStart(2, '0'); // '01'

s2.padEnd(2, '0');  // '1.'
s2.padEnd(3, '0');  // '1.0'

五、数值的拓展

[补充]:二进制<—>十进制、八进制<—>十进制 的相互转化:

let a = 20;
let b = a.toString(2);   // 10100  {二进制}
let c = parseInt(b, 2);  // 20     {十进制}

let d = a.toStrging(8);  // 24     {八进制}
let e = parseInt(d, 8);  // 20     {十进制}

二进制和八进制的表示方法:

0b 或者 0B表示二进制

0o 或者 0O 表示八进制

console.log( 0b10100 )  // 20  输出的时候会被转成10进制
console.log( 0o24 )     // 20

Number对象的属性和方法:

Number.MAX_SAFE_INTEGER –> 最大 的安全整数

Number.MIN_SAFE_INTEGER –> 最小 的安全整数

Number.isInteger(number)· –> 是一个整数? {无类型转换} true(是);false(不是)

Number.isSafeInteger(number) –> 是一个安全的整数? {无类型转换} true(是);false(不是)

console.log( Number.isInteger(10) )  //true
console.log( Number.isInteger(10.1) )//false

console.log( Number.isSafeInteger(10) )    //true
console.log( Number.isSafeInteger(10.1) ); //false

console.log( Number.MAX_SAFE_INTEGER )  //9007199254740991
console.log( Number.MIN_SAFE_INTEGER )  //-9007199254740991

Math对象的方法:

Math.trunc(Number) –> 取整 ; [-1,0,1,Infinity,NaN]

Math.sign(number) –> 判断正负 [1,0,-1,NaN]

Math.cbrt(number) –> 立方根

console.log( Math.trunc(1.1) )        //1
console.log( Math.trunc(-2.1) )       //-2
console.log( Math.trunc(Infinity) )   //Infinity
console.log( Math.trunc(NaN) )        //NaN

console.log( Math.sign(1.1) )         //1
console.log( Math.sign(-1.1) )        //-1
console.log( Math.sign(0) )           //0
console.log( Math.sign(Infinity) )    //1
console.log( Math.sign(NaN) )         //NaN

console.log( Math.cbrt(8) )           //2

六、数组的拓展

创建:

Array.of(1) –> 将传入的集合创建为数组;主要是弥补new Array(1),这个方法的缺项。

Array.from(arguments) –> 将伪数组转为数组

修改:

[1,2,3,4].fill(1,3,4) –> 将1填充进数组第3位到第4位(不含第四位)

[1,2,3,4,5,6].copyWithin(0,1,3) –> 取第1-3(不含)位: 2,3 替换 1,2; 最后结果为:[2,3,3,4,5,6]

function add(){
    let arr = Array.from(arguments);
    console.log( Object.prototype.toString.call(arguments) )  // [object Aguments]
    console.log( Object.prototype.toString.call(arr) )        // [object Array]
    console.log(arr)    // 1,2,3,4,5
    arr.fill(1,3,4);
    console.log(arr)    // 1,2,1,4,5 
    arr.fill(1,3,5);
    console.log(arr)    // 1,2,1,1,5
}
add(1,2,3,4,5)

console.log( [1,2,3,4,5,6,7,8].copyWithin(0, 1, 3) )  //[4, 5, 3, 4, 5, 6, 7, 8]

遍历:
1.数组:

[1,2,3].keys() –> 遍历键

[1,2,3].values() –>遍历值

[1,2,3].entries() –>遍历键值

2.对象:

Object.keys(obj) –>遍历键

Object.values(obj) –>遍历值

Object.entries(obj)–>遍历键值

let a = [1,2,3,4];
let b = {
    a: 1,
    b: 2,
    c: 3,
    d: 4
}

for( let k of a.keys()){
    console.log( k )  // 0,1,2,3
}
for( let v of a.values()){
    console.log( v )  // 1,2,3,4
}
for( let [k, v] of a.entries()){
    console.log( k, v)  // [0,1],[1,2],[2,3],[3,4]
}

for(let k of Object.keys(b)){
    console.log( k )  //a,b,c,d
}
for(let v of Object.values(b)){
    console.log( v )  //1,2,3,4
}
for(let [k, v] of Object.entries(b)){
    console.log( k, v )  //[a,1],[b,2],[c,3],[d,4]
}

检测:

[1,2,3].find(callback(item,index)) –> 找到符合条件的值,只返回第一个

[1,2,3].findIndex(callback(item,index)) –> 找到符合条件的值的下标,只返回第一个

[1,2,NaN].includes(NaN) –> 检测数组是否有这个值,检测NaN返回true

console.log( [1,2,3,4].find((item,index)=>item>2&&index!=2) )  //4
console.log( [1,2,3,4].findIndex((item,index)=>item>2) )       //2

console.log( [1,2,3,NaN].includes(NaN) )  //true
console.log( [1,2,3,2,NaN].includes(2) )  //true

七、函数的拓展

箭头函数:三种写法

let add = (x,y)=>{return x+y;} —> //常规写法

let add = x=>{return x+y;} —> //一个参数时,可以省略 ()

let add = x=>x+y —> // 函数体只有一句话时,可以省略 {},默认将x+y作为返回值

优势:
1.解决了this的指向问题;
2.写法更加简洁。

参数默认值:

let add = (x=1,y=2)=>x+y —> // 给x,y设置了默认参数1,2

rest/spread参数:

//rest
function add(a, ...b){
    console.log(a)  // 1
    console.log(b)  // [2,3,4]
}
add(1,2,3,4,5);

//spread
let c = [1,2,3,4];
function add2(a,b,c){
    console.log(a,b,c)   // 1,2,3
    console.log(arguments[3]) // 4
}
add2(...c);

函数的尾调用:提升性能
在函数结束的return后跟一个函数调用

function b(){ return c(); }
function c(){};

八、对象的拓展

对象简写模式:属性和方法

let obj = {a,add(){}},a:属性名是a,属性值是:变量a;add:表示一个函数。

对象属性表达式:属性名是一个可变的值。

新增API:

Object.is(a,b) ,判断a===b? true : false 可以判断NaN

Object.assign(a,b,c) c覆盖b,b覆盖a,保留a有,b c没有。

Object.entries(obj) 遍历key和value

Object.keys() 遍历key

Object.values()遍历value

let a = 1;
let b = {
    name: 'bb'
}
let c = [1,2,3];
let d = 'dd';
let e = b;
let o1 = {
    a,
    b,
    c,
    [d]: 'dd'
}
let o2 = {
    a: '11',
    b: '22'
}
let o3 = {
    b: '222',
    c: '333'
}

console.log( o1 )
/*
{
    a: 1,
    b: {name: "bb"},
    c: [1, 2, 3],
    d: "dd"
}
*/

console.log( o1[d] )  // dd
console.log( o1.dd )  // dd


console.log( Object.is(1, '1') );  //false  [全等]
console.log( Object.is(NaN, NaN) );  //true
console.log( Object.is(b, e) );  //true


// 1.浅拷贝:复制基本类型的值,复制对象类型的内存地址
// 2,后面覆盖前面对象的值,但是保留后面对象没有的值
let f = {
    a: '1111'
};
Object.assign(f, o2, o3);  
console.log( f )
/*
{
    a: '11',
    b: '222',
    c: '333'
}
*/

console.log(Object.entries(f))  //[['a','11'],['b','222'],['c','333']]
console.log(Object.keys(f))  //['a','b','c']
console.log(Object.values(f))  //['11','222','333']

九、Symbol: [创建独一无二的值]

创建:Symbol.for('aa')

API:

Object.getOwnpropertySymbols(obj)数组返回obj中所有的Symbol 属性

Reflect.ownKeys(obj)数组返回obj中所有的普通属性和Symbol 属性

let a = Symbol.for('aa')
let b = Symbol.for('bb')

let o = {
    [a]: 1,
    aa: 2,
    [b]: 3
}

console.log(o)
/*
{
    aa: 2,
    Symbol(aa): 1
} 
*/
console.log( o[a] )  // 1

//Symbol不能被for...in遍历
for(let i in o){
    console.log(i)  //[aa]
}

console.log( Reflect.ownKeys(o) );  // ['aa', Symbol(aa), Symbol(bb)]

console.log( Object.getOwnPropertySymbols(o) );  // [Symbol(aa), Symbol(bb)]

十、数据解构

Set数据解构:类似数组集合 [‘不能出现重复的数据’]

let arr1 = [1,2,3,4];
let obj1 = {
    a: 11,
    b: 22
}
let s1 = new Set(arr1);  // Set(4) {1,2,3,4}

//增
s1.add(NaN);  // Set(4) {1,2,3,4,5}
s1.add(1);    // Set(4) {1,2,3,4,5}

//查
s1.has(NaN);  //true
s1.has(0);    //false

//删
s1.delete(NaN) // Set(4) {1,2,3,4}
s1.clear();    // Set(0) {}

//遍历
s1 = new Set(arr1);
for(let [k, v] of s1.entries()){
    console.log( k, v )  //[[1,1], [2,2], [3,3], [4,4]]
}
for(let k of s1.keys()){
    console.log( k)  //[1,2,3,4]
}
for(let v of s1.values()){
    console.log( v )  //[1,2,3,4]
}
for(let value of s1){
    console.log(value);  //[1,2,3,4]
}
s1.forEach((item, i)=>{
    console.log( item, i )  //[[1,1], [2,2], [3,3], [4,4]]
})

WeakSet数据结构:

WeakSet和Set的区别:

// 1:支持的数据类型不一样,WeakSet的元素只能是对象
// 2:WeakSet的元素对象是个弱引用,只是个地址,不会检测这个地址是否被垃圾回收机制回收掉了
// 3:没有size属性,也不能使用clear
// 4:无法遍历

Map数据结构:类似对象 [‘可以使用对象作为属性名’]

let a = [1,2,3];
let o = {
    a: 11,
    b: 22
}
let c = 'qwe';
let m = new Map();

//增
m.set('a', a).set('o', o).set('c', c)  //添加成功  可以理解为:{a: [1,2,3], o: {a: 11, b: 22}, c: 'qwe'};

//查
m.has('a')  // true

//改
m.set('a', 'aa');  //aa

//删
m.delete('a');
m.clear();

m.set('a', a).set('o', o).set('c', c);
//遍历
for(let [k, v] of m.entries()){
    console.log(k, v);  // [ ['a',[1,2,3]], ['o', {a: 11, b: 22}], ['c', 'qwe'] ]
}
for(let k of m.keys()){
    console.log(k)  // [ 'a', 'o', 'c' ]
}
for(let v of m.values()){
    console.log(v)  // [ [1,2,3], {a: 11, b: 22}, 'qwe' ]
}
m.forEach((v, k)=> {console.log('forEach', v , k);})  //[ [[1,2,3],'a'], [{a: 11, b: 22}, 'o'], ['qwe', 'c'] ];

WeakMap数据结构:

// WeakMap和Map的区别:

// 1:支持的数据类型不一样,WeakMap的元素只能是对象
// 2:WeakMap的元素对象是个弱引用,只是个地址,不会检测这个地址是否被垃圾回收机制回收掉了
// 3:没有size属性,也不能使用clear
// 4:无法遍历

十一、数据结构的对比

结论:优先使用map,能使用map就使用map,不使用数组,object; 考虑数据存储的唯一性,则使用set

{
  //数据结构横向对比,map和数组的对比,增删改查
  let map=new Map();
  let array=[];
  //增
  map.set('a',1);
  array.push({'a':1});
  console.log('map-array-insert',map,array); // map-array Map {"a" => 1} [Object]
  //查
  let map_exist=map.has('a');
  let array_exist=array.find(item=>item.a);  //返回item.a
  console.log('map-array-exist',map_exist,array_exist);//map-array-exist true Object {a: 1}
  //改
  map.set('a',2);
  array.forEach(item=>item.a?item.a=2:'');//遍历每个item,判断key为a的item是否存在,存在则改
  console.log('map-array-update',map,array); 
  //删
  map.delete('a');
  let index=array.findIndex(item=>item.a);
  array.splice(index,1);
  console.log('map-array-delete',map,array); // map-array-delete Map {} []
}

{
  //数据结构横向对比,Set和数组的对比,增删改查
  let set=new Set();
  let arr=[];

  //增
  set.add({t:1});
  arr.push({t:1});
  console.log('set-array-insert',set,arr); //set-array-insert Set {Object {t: 1}} [Object]

  //查
  let set_exist=set.has({t:1});
  let arr_exist=arr.find(item=>item.t);  //返回item.a
  console.log('set-array-exist',set_exist,arr_exist);//set-array-exist false Object {t: 1}

  //改
  set.forEach(item=>item.t?item.t=2:'');
  arr.forEach(item=>item.t?item.t=2:'');//遍历每个item,判断key为a的item是否存在,存在则改
  console.log('set-array-update',set,arr);  //set-array-update Set {Object {t: 2}} [Object]

  //删
  set.forEach(item=>item.t?set.delete(item):'');
  let index=arr.findIndex(item=>item.t);
  arr.splice(index,1);
  console.log('set-array-delete',set,arr); // set-array-delete Set {} []

}

{
  // set,map,object对比
  let item={t:1};
  let set=new Set();
  let map=new Map();
  let obj={};

  //增
  set.add(item);
  map.set('t',1);
  obj['t']=1;
  console.log("set-map-obj",set,map,obj);//set-map-obj Set {Object {t: 1}} Map {"t" => 1} Object {t: 1}

  //查
  console.log({
    'set-exist':set.has(item),
    'map-exist':map.has('t'),
    'obj-exist':'t' in obj
  });  // Object {set-exist: true, map-exist: true, obj-exist: true}

  //改
  item.t=2; //set元素的修改,因为存储的是地址
  map.set('t',2);
  obj['t']=2;
  console.log("set-map-obj-update",set,map,obj); // set-map-obj-update Set {Object {t: 2}} Map {"t" => 2} Object {t: 2}

  //删
  set.delete(item);
  map.delete('t');
  delete obj['t'];
  console.log("set-map-obj-delete",set,map,obj); // set-map-obj-delete Set {} Map {} Object {}
}

十二、Proxy:代理对象、Reflect:映射

Proxy:

get(target, key){}

set(target, key, value){}

deleteProperty(target, key){}

has(target, key){}

ownKeys(target, key){}

let obj = {
    name: 'obj',
    time: '2018',
    age: 24
}

let proxy = new Proxy(obj, {
    get(target, key){
        if(key === 'age'){
            return 0;
        }else{
            return target[key];
        }
    },
    set(target, key, value){
        if(key === 'age'){
            return target[key];
        }else{
            return target[key] = value;
        }
    },
    //拦截for...in
    has(target, key){
        if(key === 'age'){
            return false;
        }else{
            return target[key];
        }
    },
    deleteProperty(target, key){
        if(key === 'age'){
            delete target[key];
            return true;
        }else{
            return target[key];
        }
    },
    // 拦截Object.keys,Object.getOwnPropertySymbols,Object.getOwnPropertyNames
    ownKeys(target){   //只能获取属性不为time的属性
      return Object.keys(target).filter(item=>item!='age')
    }
})

console.log( proxy.name, proxy.age )  // obj 0

proxy.name = 'obj1';  //修改成功
proxy.age = 0;        //修改失败

console.log( 'name' in proxy ) // true
console.log( 'age' in proxy )  // false

delete proxy.name;  //删除成功
delete proxy.age;   //删除失败

console.log( Object.keys(proxy) ) // [ 'name', 'time' ]

Reflect:

Reflect.get(obj, 'name')

Reflect.set(obj, 'age', 0)

Reflect.deleteProperty(obj, 'age')

Reflect.ownKeys(obj)

let obj = {
    name: 'obj',
    time: '2018',
    age: 24
}

let obj = {
    name: 'obj',
    time: '2018',
    age: 24
}

console.log( Reflect.get(obj, 'name') )  //obj
Reflect.set(obj, 'age', 0)  //修改成功:age: 0
console.log( Reflect.has(obj, 'time') )  //true
Reflect.deleteProperty(obj, 'age');  //删除成功
console.log( Reflect.ownKeys(obj) )  //['name', 'time']

十三、类和实例

1.构造函数:constructor(){} 实例化时,会执行的函数。
2.继承的关键字:extends
3.子类继承时,必须调用:super
4.定义变量获取/设置方式:get className(){}set className(){}
5.静态方法: static tell() {}
6.静态属性: [className].type = 'class'className是类名

class Person {
    constructor(x=1, y = 2){
        this.x = x;
        this.y = y;
        this.name = 'david'
    }
    get longName(){
        return '1 ' + this.name;
    }
    set longName(val){
        this.name = val;
    }
    static add (){
        console.log(111);
    }
}
let p = new Person();
p.longName;  // '1 daivd'
p.longName = 11; // 11


class Son extends Person{
    constructor(x, y){
        super(x,y)
    }
}
Person.type = 'class';
Person.add();  // 111
Person.type;   // class
let s = new Son(8, 9);  //{x: 8, y: 9}

十四、异步编程:Promise对象

详细讲解请看另一篇文章:8个例子学会Promise

promise.all([fn1, fn2, fn3]) //其中fn1fn2fn3的所的resolve()之后,执行then()
promise.rece([fn1, fn2, fn3])//其中fn1fn2fn3有一个resolve(),就执行then()

{
  //功能:所有的图片都加载完后再添加到页面里

  //加载图片
  function loadImg(src){
    return new Promise((resolve,reject)=>{
      let img=document.createElement('img');
      img.src=src;
      //图片加载完后
      img.onload=function(){
          resolve(img);
      }
      //图片加载失败
      img.onerror=function(err){
          reject(err);
      }
    });
  }

  //展示图片
  function showImgs(imgs){
    imgs.forEach(function(img){
      document.body.appendChild(img);
    })
  }

  //Promise.all([])  意思是把多个promise实例当成一个promise实例,当这些实例的状态都发生改变时
  //才会返回一个新的promise实例,才会执行then方法
  Promise.all([
    loadImg("http://i4.buimg.com/567571/df1ef0720bea6832.png"),
    loadImg("https://ss1.baidu.com/9vo3dSag_xI4khGko9WTAnF6hhy/imgad/pic/item/6f061d950a7b0208b8265dea6ad9f2d3562cc8ca.jpg"),
    loadImg("https://ss1.baidu.com/9vo3dSag_xI4khGko9WTAnF6hhy/imgad/pic/item/9f510fb30f2442a750999faed943ad4bd1130221.jpg")
  ]).then(showImgs);

}

十五、自定义接口:Symbol.iterator,for…of遍历使用的就是Symbol.iterator接口

Symbol.iterator 在对象中自定义itetator接口,然后使用for…of遍历

//数组
let arr = ['a', 'b', 'c'];
let map = arr[Symbol.iterator](); // 数组内部已经实现了Symbol.iterator接口
//arr[Symbol.iterator]会返回一个遍历的函数,再()一下执行这个函数,会返回一个对象
console.log( arr[Symbol.iterator] )  //ƒ values() { [native code] }

// // map.next()先返回第一个值,如果还有下一个值,则done为false
console.log( map.next() )  // {value: "a", done: false}
console.log( map.next() )  // {value: "b", done: false}
console.log( map.next() )  // {value: "c", done: false}
console.log( map.next() )  // {value: undefined, done: true}




//对象:自定义iterator接口,for...of循环使用的就是内部的Symbol.iterator接口遍历
let obj = {
    start: [1,2,3],
    end: [4,5,6]
    [Symbol.iterator](){
        let self = this,
        arr = self.start.concat(self.end),
        index = 0,
        len = arr.length;

        return {
            next(){
                if(index < len){
                    return {
                        value: arr[index++],
                        done: false
                    }
                }else{
                    return {
                        value: arr[index++],
                        done: true
                    }
                }
            }
        }
    }
}

十六、异步编程:Generator函数、async是Gnerator函数的语法糖

Generator也是异步编程的一种解决方案。比promise更高级。

定义:function* (){}

关键字:yield

实践:

  let tell=function* (){  // function加*
      yield 'a';
      yield 'b';
      return 'c';
  }
  let k=tell();  //调用tell时遇到yield会停下来
  //调用next时会执行第一个yield
  console.log(k.next()); // Object {value: "a", done: false}
  console.log(k.next()); // Object {value: "b", done: false}
  console.log(k.next()); // Object {value: "c", done: true}
  console.log(k.next()); // Object {value: "undefined", done: true}
  //Generator返回的就是一个Iterator接口

让对象也可以遍历,Generator就是一个遍历器生成函数:

{
  let obj={};
  obj[Symbol.iterator]=function* (){
    yield 1;
    yield 2;
    yield 3;
  }

  for(let value of obj){
    console.log('value',value);  
    // value 1
    // value 2
    // value 3
  }
}

状态机:

{
  //状态机,只存在三种状态(A,B,C)   (A->B->C->A->B....一直循环)
   let state=function* (){
    while(1){
      yield 'A';
      yield 'B';
      yield 'C';
    }
  }
  let status=state();
  console.log(status.next()); // Object {value: "A", done: false}                    
  console.log(status.next()); // Object {value: "B", done: false}
  console.log(status.next()); // Object {value: "C", done: false}
  console.log(status.next()); // Object {value: "A", done: false}
  console.log(status.next()); // Object {value: "B", done: false}
}

async:

{
  let state=async function (){
    while(1){
      await 'A';
      await 'B';
      await 'C';
    }
  }
  let status=state();
  console.log(status.next());
  console.log(status.next());
  console.log(status.next());
  console.log(status.next());
  console.log(status.next());
}

长轮询:

  let ajax=function* (){
    yield new Promise(function(resolve,reject){
        setTimeout(function(){
            resolve({code:0});
        },2000);
    });
  }

  let pull=function(){
    let genertaor=ajax();
    let step=genertaor.next();
    step.value.then(function(d){  //这里的d就是上面的{code:0}
      if(d.code!=0){
        setTimeout(function(){
           console.log('wait');
           pull(); 
        });
      }else{
        console.log(d);
      }
    })
  }

  pull();

十七、Decorator:修饰器 [作用于函数,修改行为,修改函数的行为]

需要babel导入下面的插件才能使用decorator:babel-plugin-transform-decorators-legacy

descripttor的使用:

  //定义一个decorator函数,target是要修改的类,name是要修改的类的属性名称,
  //descriptor是这个属性的描述,是一个对象
  let readonly=function(target,name,descriptor){
    console.log(descriptor); 
    // Object {writable: true, enumerable: false, configurable: true,value:function(){}}
    descriptor.writable=false; //设置这个属性不可写
    return descriptor
  };

  class Test{
    @readonly 
    time(){
      return '2017-03-11'
    }
  }

  let test=new Test();

  // 下面的会报错
  // test.time=function(){
  //   console.log('reset time');
  // };

  console.log(test.time());  //2017-03-11

* target的使用: *

  let typename=function(target,name,descriptor){
    target.myname='hello';  //设置类的属性
  }

  @typename
  class Test{

  }

  console.log('类修饰符',Test.myname);  // 类修饰符 hello
  // 第三方库修饰器的js库:core-decorators; npm install core-decorators
 //这里之所以要用箭头函数,是因为要接收@log的参数
  let log=(type)=>{
    return function(target,name,descriptor){
      console.log(descriptor); 
      // Object {writable: true, enumerable: false, configurable: true,value:function(){}}

      let src_method=descriptor.value; //获取被修饰的方法
      console.log(src_method);  
      // show(){
      //   console.info('ad is show');
      // }

      //修改方法的行为
      descriptor.value=(...arg)=>{
        src_method.apply(target,arg);
        console.info(`log ${type}`);
      }
    }
  }

  class AD{
    @log('show')
    show(){
      console.info('ad is show');
    }
    @log('click')
    click(){
      console.info('ad is click');
    } 
  }

  let ad=new AD();
  ad.show();
  ad.click();

十八、模块化

模块导入导出:

import {a,b,c} from '***'export b; export a;exprot c;

import * as all from '***' 其中 all为别名

import a from '***'export default {name: 'a'}

原文地址:https://www.cnblogs.com/wenwenwei/p/10017850.html