重学ES6基础语法(四)

1,081 阅读11分钟

本系列博客为ES6基础语法的使用及总结,如有错误,欢迎指正。 重学ES6基础语法(四)主要包括 Array.from()Array.of()find()/findIndex()some()/every()PromiseSymbol() 等。

Array.from()/Array.of()

这两个方法不是原型上面的方法,直接使用会报错

let arr = [1,2,3];
console.log(arr.from());
//Uncaught TypeError: arr.from is not a function

console.log(arr.of()); 
//Uncaught TypeError: arr.of is not a function

Array.from()

1.用法

用于把一个类数组对象或者是一个可遍历对象转换为一个真正的数组

类数组对象是啥? 具有索引属性(数字),有length属性的对象;比如NodeList对象 可遍历对象是啥? 别问,问就是让你去看前面两篇笔记

(1) 格式: Array.from(arrayLike[, mapFn[, thisArg]])

(2) 参数:

  • arrayLike 想要转换成数组的伪数组对象或可迭代对象。
  • mapFn 可选 如果指定了该参数,新数组中的每个元素会执行该回调函数。
  • thisArg 可选 执行回调函数 mapFn 时 this 对象。

(3) 返回值:一个新的数组实例。

(4) 示例

// 从String生成数组
Array.from('foo'); 
// [ "f", "o", "o" ]

console.log(Array.from([1, 2, 3], x => x + x));
// expected output: Array [2, 4, 6]

Array.from(obj, mapFn, thisArg)的格式相当于 Array.from(obj).map(mapFn, thisArg)

let oLis = document.querySelectorAll('li');
let num = Array.from(oLis).map(li => li.innerHTML);
console.log(num); //["1", "2", "3"]
//等价于
let liArr = Array.from(oLis,li => li.innerHTML);
console.log(liArr); //["1", "2", "3"]

2.应用场景

  • 将字符串转为字符串数组
    let arr = Array.from('ridiculous');
    console.log(arr);  //["r", "i", "d", "i", "c", "u", "l", "o", "u", "s"]
    
    let str = 'ridiculous';
    let arr2 = str.split('');
    console.log(arr2); //["r", "i", "d", "i", "c", "u", "l", "o", "u", "s"]
    

Array.of()

1.用法

Array.of() 方法创建一个具有可变数量参数的新数组实例,而不考虑参数的数量或类型。

Array.of() 和 Array 构造函数之间的区别在于处理整数参数:

  • Array.of(7)创建一个具有单个元素为7的数组(注意:数组的长度是1),

  • Array(7) 创建一个长度为7的空数组(注意:这是指一个有7个空位(empty)的数组,而不是由7个undefined组成的数组)。

let arr = Array(5);
console.log(arr); //[empty × 5] 是一个长度为5,数值都为空的数组
let arr2 = Array.of(5);
console.log(arr2); //[5] 是一个长度为1,元素值为5的数组

let arr = Array(0);
console.log(arr); //[]
let arr2 = Array.of(0);
console.log(arr2); //[0]

也就是说使用 Array.of() 能够保证传入的数据和返回结果的一致性,不管传入多少个参数,返回的是由这些元素组成的数组;弥补了Array()构造函数的不足

let arr = Array(1,2,3);
console.log(arr); //[1,2,3]

let arr2 = Array.of(1,2,3);
console.log(arr2); //[1,2,3]

find()/findIndex()/some()/every()

find()

find() 方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined。 找到满足条件的第一个就会立即停止

1.用法

格式:arr.find(callback[, thisArg])

参数:① callback 在数组每一项上执行的函数,接收 3 个参数:

  • element 当前遍历到的元素。
  • index 可选 当前遍历到的索引。
  • array 可选 数组本身。

② thisArg 可选 执行回调时用作this 的对象。

返回值:数组中第一个满足所提供测试函数的元素的值,都找不到否则返回 undefined。

let inventory = [
    {name: 'apples', quantity: 2},
    {name: 'bananas', quantity: 0},
    {name: 'cherries', quantity: 5}
];

let cherry = inventory.find(fruit => fruit.name === 'cherries');
console.log(cherry); // { name: 'cherries', quantity: 5 }

findIndex()

findIndex()方法返回数组中满足提供的测试函数的第一个元素的索引。找不到则返回-1。

1.用法 格式:arr.findIndex(callback[, thisArg])

参数:① callback 针对数组中的每个元素, 都会执行该回调函数, 执行时会自动传入下面三个参数:

  • element 当前元素。
  • index 当前元素的索引。
  • array 调用findIndex的数组。

② thisArg 可选。执行callback时作为this对象的值.

返回值:数组中通过提供测试函数的第一个元素的索引。否则,返回-1

let cherryIndex = inventory.findIndex(fruit => fruit.name === 'cherries');
console.log(cherryIndex); //2

some()

some() 方法测试数组中是不是至少有1个元素通过了被提供的函数测试。它返回的是一个Boolean类型的值。

找到满足条件的第一个就会立即停止

1.用法

格式:arr.some(callback(element[, index[, array]])[, thisArg])

参数: ① callback用来测试每个元素的函数,接受三个参数:

  • element 数组中正在处理的元素。
  • index 可选 数组中正在处理的元素的索引值。
  • array 可选 some()被调用的数组。

② thisArg可选 执行 callback 时使用的 this 值。

返回值:数组中有至少一个元素通过回调函数的测试就会返回true;所有元素都没有通过回调函数的测试返回值才会为false。

let isZero = inventory.some(fruit => fruit.quantity === 0);
console.log(isZero); //true

every()

every() 方法测试一个数组内的所有元素是否都能通过某个指定函数的测试。它返回一个布尔值。 如果有一个为false,则立即返回false,后面的不再执行

1.用法

格式:arr.every(callback[, thisArg])

参数:① callback 用来测试每个元素的函数,它可以接收三个参数:

  • element 用于测试的当前值。
  • index 可选 用于测试的当前值的索引。
  • array 可选 调用 every 的当前数组。

② thisArg 执行 callback时使用的 this 值。

返回值:如果回调函数的每一次返回都为 truthy 值,返回 true ,否则返回 false。

let allZero = inventory.every(fruits => fruits.quantity === 0);
console.log(allZero); //false

Promise

官方说法之又臭又长不看版:

Promise 对象用于表示一个异步操作的最终完成 (或失败), 及其结果值.

Promise构造函数执行时立即调用`executor`函数, `resolve` 和 `reject` 两个函数作为参数传递给`executor`(executor 函数在Promise构造函数返回所建promise实例对象前被调用)。`resolve` 和 `reject` 函数被调用时,分别将promise的状态改为fulfilled(完成)或rejected(失败)。executor 内部通常会执行一些异步操作,一旦异步操作执行完毕(可能成功/失败),要么调用resolve函数来将promise状态改成fulfilled,要么调用`reject` 函数将promise的状态改为rejected。如果在executor函数中抛出一个错误,那么该promise 状态为rejected。executor函数的返回值被忽略。

1.Promise基本概念

1.1 what

promise是ES6中新增的异步编程解决方案。简单说就是一个容器,里面保存着某个未来才会结束的事件的结果。 从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。可以通过new Promise(function(resolve, reject){})来创建

1.2 why

通过Promise就可以实现:用同步的流程来表示异步的操作;解决回调顺序的不确定性,解决回调地狱的问题

1.3 how

Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolvereject。它们是两个函数,由JavaScript引擎提供,不用自己部署。

resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从Pending变为Resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;

reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从Pending变为Rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

let p = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

2.Promise对象三种状态(面试必问)

  • pending:默认状态,只要没有说明promise任务是成功还是失败就是pending状态
  • fulfilled(resolved):只要调用resolve函数, 状态就会变为fulfilled, 表示操作成功
  • rejected:只要调用rejected函数, 状态就会变为rejected, 表示操作失败

3.Promise 对象的特点

3.1 对象的状态不受外界影响,只有异步操作的操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。

3.2 一旦状态改变,就不会再改变,任何时候都可以得到这个结果。 Promise 对象的状态改变,只有两种可能:从Pending变为Resolved;从Pending变为Rejected

4.Promise 常用的方法有哪些?它们的作用是什么?

4.1 Promise.then()

  • Promise 实例具有then方法,也就是说,then方法是定义在原型对象Promise.prototype上的。
  • 它的作用是为 Promise 实例添加状态改变时的回调函数。
  • then方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数。

4.2 Promise.catch()

Promise.catch方法是.then(null, rejection).then(undefined, rejection)的语法糖,用于指定发生错误时的回调函数。

4.3 Promise.all()

all方法接收一个数组,,当所有实例promise的结果都是成功时,才会执行后面then方法里面的内容 如果有一个promise实例的状态是失败的,那么就会执行catch方法

const userPromise = new Promise((resolve,reject) =>{
  setTimeout(() => {
      resolve(['lucy','lily','eli']);
  },2000)
});

const moviePromise = new Promise((resolve,reject) => {
  setTimeout(() => {
      // resolve({name: '卡萨布兰卡',score: '9.8', published: '1964'});
      reject('no movie found');
  },500);
});
Promise.all([userPromise,moviePromise])
      .then(response => {
          console.log(response);
          let [user,movie] = response;
          console.log(user);
          console.log(movie);
      })
      .catch(err => console.log(err));

已知userPromise的状态已经确定了是成功的,所以all方法返回的内容取决于moviePromise的状态:

如果moviePromise的状态是成功,则all方法执行then里面的内容。正常打印response、user、movie

如果moviePromise的状态是失败,则all方法执行catch里面的内容。抛出错误

4.4 Promise.race()

race方法由数组里面第一个promise实例返回的状态决定,如果第一个promise返回的状态是成功,那么race方法执行then方法里面的内容; 如果第一个promise实例返回的状态是失败,则race方法执行catch方法里面的内容

const userPromise = new Promise((resolve,reject) =>{
  setTimeout(() => {
      resolve(['lucy','lily','eli']);
  },2000)
});

const moviePromise = new Promise((resolve,reject) => {
  setTimeout(() => {
      resolve({name: '卡萨布兰卡',score: '9.8', published: '1964'});
      // reject(Error('no movie found'));
  },500);
});
Promise.race([userPromise,moviePromise])
        .then(response => {
            console.log(response);
        })
        .catch(err => console.log(err));

race方法执行的结果取决于先执行的moviePromise返回的结果,

如果moviePromise的状态是成功的,那么race方法执行then里面的内容。正常打印response

如果moviePromise的状态是失败的,那么race方法执行执行catch里面的内容。抛出错误

5.Promise常见面试题

5.1

let promise = new Promise((resolve, reject)=>{
  console.log('我是promise任务');
  resolve('resolved')
})
promise.then(res =>{
  console.log(res)
})
console.log("我是同步任务");
  setTimeout(()=>{
  console.log("我是延时任务");
}, 0)

答案:执行顺序:我是promise任务、我是同步任务、resolved、我是延时任务。

5.2

console.log(1);
setTimeout(()=>{
  console.log(2);
});
setTimeout(()=>{
  console.log(3);
});
const promise = new Promise((resolve) => {
  console.log(4);
  resolve();
});
promise.then(()=>{
  console.log(5);
});
console.log(6); //1 4 6 5 2 3

6.Promise的缺点

6.1 无法取消Promise,一旦新建,它就会立即执行,无法中途取消。

6.2 如果不设置回调函数,Promise内部抛出抛出的错误不会反映到外部。

6.3 当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)

Symbol

symbol 是一种基本数据类型 (primitive data type)。
Symbol()函数会返回symbol类型的值
每个从Symbol()返回的symbol值都是唯一的。一个symbol值能作为对象属性的标识符。

1.什么Symbol?

  • Symbol是ES6中新增的一种数据类型,被划分到了基本数据类型中

  • Symbol的作用:用来表示一个独一无二的值

  • Symbol的意义:用来解决对象中属性命名的冲突问题

2.如何生成一个Symbol

2.1 采用let xxx = Symbol();即可创建一个独一无二的值;利用typeof 检查这个独一无二的值时,返回symbol(小写s)

每一次创建的Symbol不和其他Symbol相等(独一无二)

const peter = Symbol();
console.log(peter); //Symbol()
console.log(typeof peter); //symbol

const student = Symbol();
console.log(student === peter); //false

2.2 可以在括号里面为每一个Symbol添加描述,用于区分Symbol

通过Symbol生成独一无二值时传入的字符串仅仅是一个标记, 方便我们阅读代码, 没有其它任何意义

const peter = Symbol('peter');
console.log(peter); //Symbol(peter)

const student = Symbol('student');
console.log(student); //Symbol(student)

3.注意点

3.1 通过Symbol生成独一无二值时需要在后面加上(), 但是前面不能加new, 因为它不是引用类型

3.2 做类型转换的时候不能转换成数值类型,且不能做任何运算

let n = Symbol("name");
console.log(String(n));//字符串Symbol(name)
console.log(Boolean(n));//true
console.log(Number(n));//报错 Uncaught TypeError: Cannot convert a Symbol value to a number

3.3 对象的属性名是Symbol类型的话,是不可遍历的

不能用for inObject.keys()Object.getOwnPropertyNames()遍历

 const list = {
   [Symbol('Ann')]: {score: 99, gender: 'female'},
   [Symbol('Bob')]: {score: 99, gender: 'male'},
   [Symbol('Eli')]: {score: 99, gender: 'male'},
 };

 for(let key in list){
   console.log(key); //什么也没输出
   console.log(list[key]); //什么也没输出
 }

 let res = Object.keys(list);
 console.log(res); //[]

 let res2 = Object.getOwnPropertyNames(list);
 console.log(res2); //[]

3.4 Object.getOwnPropertySymbols()方法遍历属性时返回一个symbol类型的数组。

 let res3 = Object.getOwnPropertySymbols(list);
 console.log(res3);

3.5 如果想使用Symbol变量作为对象属性的名称, 那么必须使用[],获取的时候也只能用对象名称[]的方式

const list = {
   [Symbol('Ann')]: {score: 99, gender: 'female'},
   [Symbol('Bob')]: {score: 99, gender: 'male'},
   [Symbol('Eli')]: {score: 99, gender: 'male'},
};

const name = Symbol('Eli');
const say = Symbol('say');
const person = {
    [name] : 'ghk',
    [say]: function () {
         console.log('say');
    }
}
//获取属性的时候
console.log(person[name]);
console.log(person[say]);