重學ES6基礎語法(四)

acoderbeauty發表於2019-10-27

本系列部落格為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.應用場景

重學ES6基礎語法(四)

  • 將字串轉為字串陣列
    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);
複製程式碼

重學ES6基礎語法(四)
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]);
複製程式碼

相關文章