ES6知识汇总_es6 catch后面绑定的error怎么省略,吊打面试官系列

24 阅读8分钟

前端资料汇总

我一直觉得技术面试不是考试,考前背背题,发给你一张考卷,答完交卷等通知。

首先,技术面试是一个 认识自己 的过程,知道自己和外面世界的差距。

更重要的是,技术面试是一个双向了解的过程,要让对方发现你的闪光点,同时也要 试图去找到对方的闪光点,因为他以后可能就是你的同事或者领导,所以,面试官问你有什么问题的时候,不要说没有了,要去试图了解他的工作内容、了解这个团队的氛围。 找工作无非就是看三点:和什么人、做什么事、给多少钱,要给这三者在自己的心里划分一个比例。 最后,祝愿大家在这并不友好的环境下都能找到自己心仪的归宿。

开源分享:docs.qq.com/doc/DSmRnRG… person.age=20;


(2)使用对象字面量的形式



const person = { name:'Mina' age:20 }


**对象字面量有几种简洁表示法:**


(1)对象的属性名和变量或者常量一样的时候,可以只写属性名



const name = 'wuva'; const person = { neme }


(2)对象方法的简介表示,省略冒号和function



const person = { speak(){     console.log('speak') } }


方括号语法增强


方括号语法的用法:



      const prop = 'age';       const person = {};       person.prop = 18; //此时属性名是prop       person[prop] = 18; //会先对方括号中的prop的求值,此时属性名是age ​       // 方括号语法可以写在对象字面中       const person2 = {           [prop] : 16       };       console.log(person2); // 会先对方括号中的prop的求值,此时属性名是age {age: 16}



方括号里面可以放什么


(1)${}


(2)值或者表达式


方括号和点语法的区别


点语法是方括号的一种特殊形式,


当属性名是合法字符串的时候,可以使用点语法,其他情况使用方括号语法,因此更推荐使用方括号语法




### 5 函数参数的默认值


(1) 函数参数默认值的生效条件是不传参或者明确传递undefined作为参数


(2) 默认参数是表达式的时候是惰性求值的


(3)小技巧:函数默认参数的设置从参数列表的右边开始设置


假如从参数列表的左边设置:



    const mul = (x=1,y) => x*y;

      console.log(mul(undefined,2)); //麻烦




### 6 剩余参数


剩余参数的本质:剩余参数永远都是一个数组,即使没有值,也是一个空数组


注意事项:


(1)箭头函数的参数即使只有一个剩余参数,也不能省略圆括弧



    const add = (...args) => {};


(2)使用剩余参数代替argument获取实际参数



    const add = function () {       console.log(arguments);     };     const add = (...args) => {       console.log(args);     };     add(1, 2);


(3)剩余参数只能是最后一个参数,之后不能再有其他参数,否则会报错



    const add = (x, y, ...args) => {       console.log(args);     };


### 7 展开运算符


认识展开运算符




> 

> 

> ```

> ...[2,3,4] => 3,2,1

>       // 1.认识展开运算符

>       // [3, 1, 2]; ==》怎么找到数组的最大值和最小值

>       // Math.min

> 

>       console.log(Math.min([3, 1, 2])); // math.min不能接收数组,接收的是参数列表的形式,如下面一行

>       console.log(Math.min(3, 1, 2));

> 

>       // [3, 1, 2]->3, 1, 2

> 

>   // 2.数组展开运算符的基本用法

>       console.log(Math.min(...[3, 1, 2]));

>       // 相当于

>       console.log(Math.min(3, 1, 2));

> 

> ```

> 

> 




区分剩余参数和展开运算符


**根本区别:**


剩余参数: 3,2,1 --> [3,2,1]


展开运算符: [3,2,1] -->3,2,1


数组的展开运算符的应用


(1)复制数组(地址不相同)



    // const a = [1, 2];     // // const b = a;     // // a[0] = 3;     // // console.log(b); //这样指向的同一个地址,修改a,b也会变 ​     const c = [...a];     // const c = [1, 2];     a[0] = 3;     console.log(a);     console.log(c);


(2)合并数组



  const a = [1, 2];
  const b = [3];
  const c = [4, 5];

  console.log([...a, ...b, ...c]);
  console.log([...b, ...a, ...c]);
  console.log([1, ...b, 2, ...a, ...c, 3]);

(3)字符串/类数组 转为数组,这样就能使用数组的方法了



  //字符串
  console.log([...'alex'])  // ["a","l","e","x"]
  //类数组
 // (1) arguments
  function func() {
    console.log([...arguments]);
  }
  func(1, 2);
  //(2) NodeList
  console.log([...document.querySelectorAll('p')].push);

对象的展开运算符


(1)对象不能直接展开,要在{}中展开,将属性罗列出来放到{}中 构成一个新的对象



  const apple = {
    color: '红色',
    shape: '球形',
    taste: '甜'
  };
  console.log({...apple});  //{color: '红色', shape: '球形', taste: '甜'}
//   console.log(...apple); //报错
//   console.log([...apple]); //报错

(2)合并对象,中间用逗号隔开,合并的对象具有所有属性,相同的属性后者覆盖前者



  const apple = {
    color: '红色',
    shape: '球形',
    taste: '甜'
  };
  const pen = {
    color: '黑色',
    shape: '圆柱形',
    use: '写字'
  };
  console.log({ ...apple, ...pen }); //{color: '黑色', shape: '圆柱形', taste: '甜', use: '写字'}

**注意事项**


(1)如果展开一个空对象,则没有任何效果


(2)展开的不是一个对象的时候,会自动将其转化为对象,再将其属性罗列出来,找不到属性时候就是空对象


(3)展开的是字符串的时候,会自动将字符串转换为一个类数组对象,返回的不是一个空对象


(4)对于对象的展开,不会展开对象中的对象


对象展开运算符的应用


(1)复制对象(地址不同)



  // const a = { x: 1, y: 2 };
  // // const b = a; //这样其实是地址相同

  const c = { ...a }; //正确的复制操作
  // console.log(c, c === a);

(2)默认参数和实际参数



  const logUser = userParam => {
    const defaultParam = {
      username: 'ZhangSan',
      age: 0,
      sex: 'male'
    };

    const param = { ...defaultParam, ...userParam };
    // const param = { ...defaultParam, ...undefined };
    console.log(param.username);
    // const { username, age, sex } = { ...defaultParam, ...userParam };
    // console.log(username, age, sex);
  };
  logUser();

### 7 SetMap


#### Set


认识Set


Set是一个无序且没有重复值的数据结构,Set是没有下标标识每个值的,因此不能像数组一样通过下标值访问Set成员



const s = new Set([1,2,3,3,4]) console.log(s)


**小知识点**:Set内部NaN被视为相等的元素只会加入一个,但是其实NaN !== NaN, 但是两个空对象视为两个不同的元素


Set的方法和属性


属性:Set.size:返回 Set 实例的成员总数。



操作方法:


* Set.add(value) :添加某个值,返回 Set 结构本身。
* Set.delete(value) :删除某个值,返回一个布尔值,表示删除是否成功。
* Set.has(value) :返回一个布尔值,表示该值是否为 Set 的成员。
* Set.clear() :清除所有成员,没有返回值。


遍历方法: Set的遍历顺序就是成员的添加顺序


Set 结构的实例有四个遍历方法,可以用于遍历成员。


* Set.keys() :返回键名的遍历器
* Set.values() :返回键值的遍历器
* Set.entries() :返回键值对的遍历器
* Set.forEach() :使用回调函数遍历每个成员

 

let s = new Set([1,2,3]); s.forEach(function(value,key,set){ console.log(value); console.log(this); //#document },document);

// 该函数的参数与数组的 forEach 一致,依次为键值、键名、集合本身(上例省略了该参数),doucument所在参数位置是修改函数的this指向,不写就是默认window



`keys`方法、 `values`方法、 `entries`方法返回的都是`遍历器对象`。由于 Set 结构没有键名,只有键值(或者说键名和键值是同一个值),所以`keys`方法和 `values`方法的是相等的,都是成员的值。这意味着,可以省略`values`方法,直接用 `for...of` 循环遍历 Set



let set = new Set(['red', 'green', 'blue']); for (let x of set) { console.log(x); }


Set构造函数的参数


1.数组


2.字符串、argument、NodeListSet等具有 iterable 接口的其他数据结构。


Set的注意事项


1.判断重复的方式



  // Set 对重复值的判断基本遵循严格相等(===)
  // 但是对于 NaN 的判断与 === 不同,Set 中 NaN 等于 NaN
  // 两个空对象是不严格相等的
  const s = new Set([1, 2, 1]); 
  const s = new Set([NaN, 2, NaN,{},{}]); // {NaN,2,{},{}}

  console.log(NaN === NaN); //false NaN其实是不等于NaN的
  console.log({} === {}); //false

* 什么时候用Set

 (1)数组或者字符串去重

 (2)只需要遍历,不需要通过下标去访问

 (3)为了使用Set的属性和方法时


Set去重(最常用)


1 数组去重



  // 方法1:
    new_s1 = [...new Set(s)];
    //方法2:
    new_s2 = Array.from(new Set(s)) ; //Array.from 方法可以将 Set 结构转为数组
    console.log(new_s2);

2.字符串去重


Set->数组->字符串



    const s = new Set('abbagn');
    console.log([...s].join('')); //abgn

#### Map


认识Map


map也是一种键值对的数据结构,由于对象的键只能采用字符串,这给他带来了很大的限制,为了能够让各种类型的值都可以当做键,由此提出来Map数据结构。


Map的属性和方法


属性:


Map.size :返回Map结构的成员总数 ,对象没有size属性


操作方法:


(1Map.set(key,value): 添加新成员,如果key已经存在,后者覆盖前者,set 方法返回的是当前的 Map 对象,因此可以采用链式写法。



let map = new Map() .set(1, 'a') .set(2, 'b') .set(3, 'c');

2Map.get(key) :通过键获取某个成员。如果找不到的话,返回undefined3Map.has(key) : 返回一个布尔值,表示某个键是否在当前 Map 对象之中


(4Map.delete(key): 删除某个键,返回 true 。如果删除失败,返回 false ,不报错


(5Map.clear(): 一键清除


遍历方法:


* Map.keys() :返回键名的遍历器。
* Map.values() :返回键值的遍历器。
* Map.entries() :返回所有成员的遍历器。
* Map.forEach() :遍历 Map 的所有成员。

 
    m.forEach(function(value,key,m){
        console.log(value,key); 
        console.log(this); //doucument
    },document)


Map构造函数的参数



<script>
  // 1.数组
  // 只能传二维数组,而且必须体现出键和值
  console.log(
    new Map([
      ['name', 'alex'], //第一个键值对
      ['age', 18]
    ])
  );

  // 2.Set、Map 等
  // Set
  // Set 中也必须体现出键和值,一般还是二维数组的形式
  // const s = new Set([
  //   ['name', 'alex'],
  //   ['age', 18]
  // ]);
  // console.log(new Map(s));
  // console.log(s);

  // Map
  // 复制了一个新的 Map
  const m1 = new Map([
    ['name', 'alex'],
    ['age', 18]
  ]);
  console.log(m1);
  const m2 = new Map(m1);
  console.log(m2, m2 === m1); // false
</script>

Map的注意事项


1. 判断键名是否相等,遵循严格相等,例外的就是NaN也是等于NaN
2. 什么时候使用Map:

 如果只是需要key->value的结构或者需要字符串以外的值作为键,使用Map更合适,因为Map相对对象具有更多的方法


与其他数据结构的互相转换


(1) Map转数组



const myMap = new Map().set(true, 7).set({foo: 3}, ['abc']); [...myMap] // [ [ true, 7 ], [ { foo: 3 }, [ 'abc' ] ] ]


(2) 数组转Map



new Map([[true, 7], [{foo: 3}, ['abc']}])


(3) Map 转为对象



function mapToObj(m){
    let obj = Object.create(null);
    m.forEach(function(key,value){
        obj[key] = value;

    });
    return obj;
}

const myMap = new Map().set('yes', true).set('no', false);
console.log(mapToObj(myMap)); //{true: 'yes', false: 'no'}

(4)对象转Map,可以通过Object.entries()函数 或者如上写一个转换函数



let obj = {"a":1, "b":2}; let map = new Map(Object.entries(obj));


### 8 遍历器和For...of...


认识遍历器


1.遍历器(迭代器) Iterator


2.寻找 Iterator



  console.log([1, 2][Symbol.iterator]());
  const it = [1, 2][Symbol.iterator]();
  console.log(it); // Array Iterator {}

3.使用 Iterator



  const it = [1, 2][Symbol.iterator](); //返回一个遍历器的对象
  console.log(it.next()); // {value: 1, done: false}
  console.log(it.next()); // {value: 2, done: false} 此时遍历并没有结束,因为此时done为false,还要接着遍历
  console.log(it.next()); // {value: undefined, done: true} ,此时done为true,遍历完成
  console.log(it.next()); // {value: undefined, done: true}
  
  // it:可遍历对象(可迭代对象)
  // Symbol.iterator:可遍历对象的生成方法


4.什么是 Iterator,主要是下面这个过程被称为iterator



// 4.什么是 Iterator,主要是下面这个过程被称为iterator // Symbol.iterator(可遍历对象的生成方法) -> it(可遍历对象) -> it.next() -> it.next() -> ...(直到 done 为 true)


遍历器的意义


1. 遍历数组、 SetMap等:for of, forEach

 遍历对象:for in 循环


**例子**:



 //for...of 循环只会遍历出那些 done 为 false 时,对应的 value 值
  const arr = [1, 2, 3];
  for (const item of arr) {
    console.log(item);
  }
  //for...of的本质
  const it = arr[Symbol.iterator]();
  let next = it.next();
  console.log(next);
  while (!next.done) {
    console.log(next.value);
    next = it.next();
    console.log(next);
  }

  // 2.与 break、continue 一起使用
  const arr = [1, 2, 3];
  for (const item of arr) {
    if (item === 2) {
      // break;
      continue;
    }
    console.log(item);
  }

  // 3.在 for...of 中取得数组的索引
  const arr = [1, 2, 3];

  // keys() 得到的是索引的可遍历对象,可以遍历出索引值
  console.log(arr.keys()); //得到一个可遍历对象
  for (const key of arr.keys()) {
    console.log(key); //0 1 2
  }

  //values() 得到的是值的可遍历对象,可以遍历出值
  for (const value of arr.values()) {
    console.log(value);
  }  //和下面的方法结果一样,这种方式其实没有必要
  for (const value of arr) {
    console.log(value);
  }

  // entries() 得到的是索引+值组成的数组的可遍历对象
  for (const entries of arr.entries()) {
    console.log(entries); // [0,1] [1,2] [2,3]
  }

  // 结合解构赋值,将索引和值结构出来[index,value]
  for (const [index, value] of arr.entries()) {
    console.log(index, value);
  } 
  

//对象的遍历 let es6 = { edition: 6, committee: "TC39", standard: "ECMA-262" };

  for (let e in es6) {
	  console.log(e);
	}

2.如何更方便的使用 Iterator



Iterator 遍历器是一个统一的遍历方式,无论是数组还是对象,都可以使用iterator遍历,但是将Symbol.iterator->it->next()这种机制很麻烦,所以我们一般不会直接使用 Iterator 去遍历,通常也不会用,但是我们需要了解iterator的运行机制即可,开发人员利用这套遍历的流程封装好了,即for..of


原生可遍历和非原生可遍历


for ……of……只能循环原生可遍历数据


何为原生可遍历数据:只要有Symblo.iterator()方法且这个方法可以生成可遍历的对象就是原生可遍历


原生可遍历:数组、字符串、类数组、SetMap


非原生可遍历:


(1) 一般的对象,对象的遍历一般使用 for...in,也可以手动添加 Symbol.iterator 方法变成可遍历对象; (2) 有 length 和索引属性的对象,可以额外添加一个方法,因为比较简单,这里给出一个小例子



//原生可遍历的例子 for (const item of [1, 2, 3]) { console.log(item); } for (const item of 'hi') { console.log(item); } for (const item of new Set([1, 2])) { console.log(item); } for (const elem of document.querySelectorAll('p')) { console.log(elem); elem.style.color = 'red'; }

// 一般的对象手动添加Symbol.iterator 方法 const person = { sex: 'male', age: 18 }; person[Symbol.iterator] = () => { let index = 0; return { next() { index++; if (index === 1) { return { value: person.age, //手动可随意指定 done: false }; } else if (index === 2) { return { value: person.sex, done: false }; } else { return { done: true }; } } }; };

// 有 length 和索引属性的对象 const obj = { '0': 'alex', '1': 'male', length: 2 };

obj[Symbol.iterator] = Array.prototype[Symbol.iterator]; for (const item of obj) { console.log(item); }


使用了 Iterator 的场合



 


### 9 Promise


认识Promise


Promise是异步操作的一种解决方案


异步和同步的简单理解:



    document.addEventListener(       'click',       () => {         console.log('这里是异步的');       },       false     );     console.log('这里是同步的');     // 只有点击事件发生时,click才会发生,但是“这里是同步的”的输出是不用其他操作的,是同步的


什么时候使用 Promise


Promise一般用来解决层层嵌套的回调函数,回调地狱(callback hell)




Promise的基本用法


(1)实例化一个Promise对象



  new Promise(function(resolve,reject)=>{           })

2Promise的状态


Promise有三种状态,一开始是pending(未完成),


(1)执行了resolve, 变成了fulfilled(resolved)已成功的状态


(2)执行了reject, 变成了rejected已失败的状态


**Promise的状态一旦改变,就不会再变化**


(3)初识Then方法


then方法有两个回调函数,第一个是pedding->fulfilled的时候执行,第二个是pedding->rejected的时候执行,其中第二个函数是可选的,不一定要提供。


then执行后的返回值:


then方法执行后返回一个新的Promise对象,在then的回调函数中,return后面的东西会自动会包装成一个成功状态的Promise对象,没有return 返回值的时候,就相当于return undefined



      const p = new Promise((resolve,reject)=>{           resolve({'name':'Mina'});           reject(new Error('reason')) ​       }).then(           (data)=>{               return data;           // 自动包装成一个成功状态的Promise对象,也就是相当于           // return new Promise((resolve,reject)=>{           //     resolve(data);           // })           },           (err) =>{               console.log('error',err);           }       ).then((data)=>{           console.log(data); // {name:'Mina'}       })               // 想改变默认,从padding->reject       return new Promise((resolve,reject) => {         reject();       })  


(4)resolve和reject的参数


resolve和reject函数的参数会被传递到then方法对应的函数中的参数



      const p = new Promise((resolve,reject)=>{           resolve({'name':'Mina'});           reject(new Error('reason')) ​       }).then(           (data)=>{               console.log('success',data); //success {name: 'Mina'}           },           (err) =>{               console.log('error',err);           }       )       // 其中resolve中的参数{name: 'Mina'}是then中的data, reject中的new Error('reason')是then中的error     // 要记得Promise 的状态一旦变化,就不会再改变了,只能从等待到成功或者从等待到失败,不能从成功到失败或者失败到成功

5catch()方法


开发环境中,使用最多的还是使用成功态,catch 专门用来处理 rejected 状态, catch 本质上是 then 的特例 **因此,可以用then专门处理成功,catch处理失败**


(6finally()方法


`finally()`方法本质是then()的一个特例,用于指定不管`Promise`对象最后状态如何,都会执行的操作



promise .then(result => {···}) .catch(error => {···}) .finally(() => {···});


上面代码中,不管 promise 最后的状态,在执行完 then 或 catch 指定的回调函数以后,都会执行 finally 方法指定的回调函数。


(7all()方法


`Promise.all()`方法用于将多个`Promise` 实例,包装成一个新的 Promise 实例。



const p = Promise.all([p1, p2, p3]);


上面代码中, Promise.all() 方法接受一个数组作为参数, p1 、 p2 、 p3 都是 Promise 实例,如果不是,就会先调用下面讲到的 Promise.resolve 方法,将参数转为 Promise 实例,再进一步处理。另外, Promise.all() 方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。


p 的状态由 p1 、 p2 、 p3 决定,分成两种情况。


(1)只有 p1 、 p2 、 p3 的状态都变成 fulfilled , p 的状态才会变成 fulfilled ,此时 p1 、 p2 、 p3 的返回值组成一个数组,传递给 p 的回调函数。


(2)只要 p1 、 p2 、 p3 之中有一个被 rejected , p 的状态就变成 rejected ,此时第一个被 reject 的实例的返回值,会传递给 p 的回调函数。



//例子 const delay = ms => {   return new Promise(resolve => {     setTimeout(resolve, ms);   }); }; ​ const p1 = delay(1000).then(() => {   console.log('p1 完成了'); // 成功打印出   return 'p1'; }); ​ const p2 = delay(2000).then(() => {   console.log('p2 完成了');   return Promise.reject('reason'); }); ​ // Promise.all() 的状态变化与所有传入的 Promise 实例对象状态有关 // 所有状态都变成 resolved,最终的状态才会变成 resolved // 只要有一个变成 rejected,最终的状态就变成 rejected ​ const p = Promise.all([p1, p2]); p.then(   data => {     console.log(data);   },   err => {     console.log(err);   } );   // 如果是成功,依次执行p1和p2,然后执行第一个函数, // 如果p1成功,p2失败,首先打印p1完成了,然后因为状态是rejected,会立马执行第二个函数,打印出“reason”,然后执行p2,打印出p2执行了


### 10 Class



#### 认识class



 


#### Class的两种定义形式



 


#### 实例属性、静态方法、静态属性



 


#### 私有属性和方法



#### **ES6没有私有属性和方法,通常是模拟私有属性和方法**