自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

五個超級好用的 JavaScript 技巧!

開發(fā) 前端
本文來分享 5 個超級實用的 JavaScript 開發(fā)技巧!

本文來分享 5 個超級實用的 JavaScript 開發(fā)技巧!

1.Promise.all()、Promise.allSettled()

我們可以使用 Promise、async/await 來處理異步請求。當(dāng)并發(fā)處理異步請求時,可以使用 Promise.all() 和 Promise.allSettled() 來實現(xiàn)。

Promise.all()

Promise.all() 靜態(tài)方法接受一個 Promise 可迭代對象作為輸入,并返回一個 Promise。當(dāng)所有輸入的 Promise 都被兌現(xiàn)時,返回的 Promise 也將被兌現(xiàn)(即使傳入的是一個空的可迭代對象),并返回一個包含所有兌現(xiàn)值的數(shù)組。如果輸入的任何 Promise 被拒絕,則返回的 Promise 將被拒絕,并帶有第一個被拒絕的原因。

const promise1 = Promise.resolve(555);
const promise2 = new Promise(resolve => setTimeout(resolve, 100, 'foo'));
const promise3 = 23;

const allPromises = [promise1, promise2, promise3];
Promise.all(allPromises).then(values => console.log(values));

// 輸出結(jié)果: [ 555, 'foo', 23 ]

可以看到,當(dāng)所有三個 Promise 都被解析時,Promise.all() 會被解析并且值會被打印出來。但是,如果有一個或多個 Promise 沒有被解析而被拒絕了怎么辦呢?

const promise1 = Promise.resolve(555);
const promise2 = new Promise(resolve => setTimeout(resolve, 100, 'foo'));
const promise3 = Promise.reject('rejected!');

const allPromises = [promise1, promise2, promise3];

Promise.all(allPromises)
  .then(values => console.log(values))
  .catch(err => console.error(err));

// 輸出結(jié)果: rejected!

如果其中至少一個元素被拒絕,Promise.all() 就會被拒絕。 在上面的例子中,如果傳遞了兩個解析的 Promise 和一個立即被拒絕的 Promise,那么 Promise.all() 會立即被拒絕。

Promise.allSettled()

Promise.allSettled() 方法是在 ES2020 中引入的。它以一個包含多個 Promise 的可迭代對象作為輸入?yún)?shù),與 Promise.all() 不同的是,它返回一個 Promise,在所有給定的 Promise 被解析或拒絕后始終會被解析。這個 Promise 會以一個描述每個 Promise 結(jié)果的對象數(shù)組來進(jìn)行解析。

對于每個 Promise 的結(jié)果,會得到以下兩種可能的狀態(tài):

  • fulfilled:包含結(jié)果的值。
  • rejected:包含拒絕的原因。
const promise1 = Promise.resolve(555);
const promise2 = new Promise(resolve => setTimeout(resolve, 100, 'foo'));
const promise3 = Promise.reject('rejected!');

const allPromises = [promise1, promise2, promise3];

Promise.allSettled(allPromises)
  .then(values => console.log(values))

// 輸出結(jié)果:
// [
//   { status: 'fulfilled', value: 555 },
//   { status: 'fulfilled', value: 'foo' },
//   { status: 'rejected', reason: 'rejected!' }
// ]

那該如何選擇兩個方法呢?如你希望"快速失敗",那么應(yīng)該選擇 Promise.all()。 考慮這樣一個場景:需要所有的請求都成功,然后基于這個成功來定義一些邏輯。在這種情況下,快速失敗是可以接受的,因為在一個請求失敗后,其他的請求的結(jié)果就無關(guān)緊要了,不希望浪費資源在剩余的請求上。

在其他情況下,希望所有的請求要么被拒絕要么被解析。如果獲取的數(shù)據(jù)用于后續(xù)的任務(wù),或者希望顯示和訪問每個請求的錯誤信息,那么 Promise.allSettled() 就是正確的選擇。

2.空值合并運算符:??

空值合并運算符在左操作數(shù)為null或undefined時返回右操作數(shù),否則返回左操作數(shù)。它是一種獲取兩個變量中第一個“定義”的值的簡潔語法。

比如,x ?? y 的結(jié)果是:

  • 如果 x 不是null或undefined,則返回 x。
  • 如果 x 是null或undefined,則返回 y。

所以,x ?? y 可以寫作:

result = (x !== null && x !== undefined) ? x : y;

?? 的常見用法是提供一個默認(rèn)值。 例如,下面的例子中,當(dāng) name 的值不是 null/undefined時,就顯示它的值,否則顯示 "Unknown":

const name = someValue ?? "Unknown";
console.log(name);

如果 someValue 不是 null 或 undefined,那么 name 的值將為 someValue;如果 someValue 是 null 或 undefined,那么 name 的值將為 "Unknown"。

?? vs ||

邏輯與運算符(||)可以與空值合并運算符(?? )以相同的方式使用。 可以用 || 替換 ??,仍然能得到相同的結(jié)果,例如:

let name;
console.log(name ?? "Unknown"); // 輸出結(jié)果: Unknown
console.log(name || "Unknown"); // 輸出結(jié)果: Unknown

它們之間的區(qū)別在于:|| 返回第一個真值。 ?? 返回第一個已定義的值(已定義 = 非 null 或 undefined)。也就是說,|| 運算符不區(qū)分 false、0、"" 和 null/undefined,它們都是假值。如果其中任何一個是 || 的第一個參數(shù),那么結(jié)果將是第二個參數(shù)。例如:

let grade = 0;
console.log(grade || 100); // 輸出結(jié)果: 100
console.log(grade ?? 100); // 輸出結(jié)果: 0

grade || 100 檢查 grade 是否是一個假值,而它的值是 0,確實是一個假值。所以 || 的結(jié)果是第二個參數(shù),即 100。而 grade ?? 100 檢查 grade 是否為 null 或 undefined,但它并不是,所以 grade 的結(jié)果為 0。

那該如何選擇兩個方法呢?

  • 空值合并運算符 (??) 的使用場景:

為變量提供默認(rèn)值:當(dāng)一個變量可能是 null 或 undefined 時,可以使用空值合并運算符為其提供默認(rèn)值。 例如:const name = inputName ?? "Unknown";

處理可能缺失的屬性:當(dāng)訪問對象屬性時,如果該屬性可能存在但值為 null 或 undefined,可以使用空值合并運算符提供默認(rèn)值。 例如:const address = user.address ?? "Unknown";

避免出現(xiàn)假值的情況:當(dāng)我們只想處理顯式定義的值,并避免處理假值(如 false、0、空字符串等)時,可以使用空值合并運算符。 例如:const value = userInputValue ?? 0;

  • 邏輯或運算符 (||) 的使用場景:

提供備選值:當(dāng)我們需要從多個選項中選擇一個有效的值時,可以使用邏輯或運算符。 例如:const result = value1 || value2 || value3;

判斷條件:當(dāng)我們需要檢查多個條件中的任一條件是否為真時,可以使用邏輯或運算符。 例如:if (condition1 || condition2) { // 執(zhí)行操作 

3.this

"this" 是 JavaScript 中一個常被誤解的概念。要在 JavaScript 中正確使用 "this",你需要真正理解它的工作方式,因為它與其他編程語言有一些不同之處。

下面是一個常見的在使用 "this" 時出現(xiàn)錯誤的示例:

const obj = {
  helloWorld: "Hello World!",
  printHelloWorld: function () {
    console.log(this.helloWorld);
  },
  printHelloWorldAfter1Sec: function () {
    setTimeout(function () {
      console.log(this.helloWorld);
    }, 1000);
  },
};

obj.printHelloWorld();
// 輸出結(jié)果: Hello World!

obj.printHelloWorldAfter1Sec();
// 輸出結(jié)果: undefined

第一個結(jié)果打印出了 "Hello World!",因為 this.helloWorld 正確地指向了對象的 name 屬性。而第二個結(jié)果是 undefined,因為 this 已經(jīng)失去了對對象屬性的引用。這是因為 this 的指向取決于調(diào)用它所在函數(shù)的對象。每個函數(shù)中都有一個 this 變量,但它指向的對象由調(diào)用它的對象確定。

在obj.printHelloWorld() 中,this 直接指向了 obj。 在 obj.printHelloWorldAfter1Sec()中,this 直接指向了 obj。 但是,在 setTimeout 的回調(diào)函數(shù)中,this 沒有指向任何對象,因為沒有對象調(diào)用它。默認(rèn)對象(通常是 window)被使用。name 在 window 上并不存在,所以返回了 undefined。

要正確使用 this,需要了解函數(shù)調(diào)用時它所綁定的對象。如果想在回調(diào)函數(shù)中訪問對象屬性,可以使用箭頭函數(shù)或者顯式地通過 bind() 方法綁定正確的 this 值,以避免出現(xiàn)錯誤。

如何修復(fù)這個問題?要保持 setTimeout 中的 this 引用,最好的方法是使用箭頭函數(shù)。與普通函數(shù)不同,箭頭函數(shù)不會創(chuàng)建自己的 this。

因此,下面的代碼將保持對 this 的引用:

const obj = {
  helloWorld: "Hello World!",
  printHelloWorld: function () {
    console.log(this.helloWorld);
  },
  printHelloWorldAfter1Sec: function () {
    setTimeout(() => {
      console.log(this.helloWorld);
    }, 1000);
  },
};

obj.printHelloWorld();
// 輸出結(jié)果: Hello World!

obj.printHelloWorldAfter1Sec();
// 輸出結(jié)果: Hello World!

除了使用箭頭函數(shù),還可以使用其他方法來解決這個問題。

  • 使用 bind() 方法:bind() 方法創(chuàng)建一個新的函數(shù),并指定其 this 值后返回。可以使用它將函數(shù)綁定到特定的對象上,確保 this 始終引用該對象。
  • 使用 call() 和 apply() 方法:這兩個方法允許指定一個特定的 this 值來調(diào)用函數(shù)。它們之間的區(qū)別在于,call() 方法接受一組值作為參數(shù),而 apply() 方法接受一個數(shù)組作為參數(shù)。
  • 使用 self 變量:這是在引入箭頭函數(shù)之前常用的一種方法。思路是將 this 的引用存儲在一個變量中,并在函數(shù)內(nèi)部使用該變量。需要注意的是,這種方法在嵌套函數(shù)中可能效果不佳。

總的來說,每種方法都有其優(yōu)缺點,選擇使用哪種方法取決于具體的使用場景。對于大多數(shù)情況,默認(rèn)推薦使用箭頭函數(shù)。

4.內(nèi)存使用

有時應(yīng)用的內(nèi)存使用會很糟糕,來看下面的例子:

const data = [
  { name: 'Frogi', type: Type.Frog },
  { name: 'Mark', type: Type.Human },
  { name: 'John', type: Type.Human },
  { name: 'Rexi', type: Type.Dog }
];

我們想要為每個實體添加一些屬性,具體取決于它的類型:

const mappedArr = data.map((entity) => {
  return {
    ...entity,
    walkingOnTwoLegs: entity.type === Type.Human
  }
});
// ...
const tooManyTimesMappedArr = mappedArr.map((entity) => {
  return {
    ...entity,
    greeting: entity.type === Type.Human ? 'hello' : 'none'
  }
});

console.log(tooManyTimesMappedArr);
// 輸出結(jié)果:
// [
//   { name: 'Frogi', type: 'frog', walkingOnTwoLegs: false, greeting: 'none' },
//   { name: 'Mark', type: 'human', walkingOnTwoLegs: true, greeting: 'hello' },
//   { name: 'John', type: 'human', walkingOnTwoLegs: true, greeting: 'hello' },
//   { name: 'Rexi', type: 'dog', walkingOnTwoLegs: false, greeting: 'none' }
// ]

可以看到,通過使用 map,可以進(jìn)行簡單的轉(zhuǎn)換并多次使用它。對于一個小數(shù)組來說,內(nèi)存消耗是微不足道的,但對于較大的數(shù)組來說,肯定會發(fā)現(xiàn)內(nèi)存的顯著影響。

那么,在這種情況下有哪些更好的解決方案呢?

首先,需要理解當(dāng)處理大數(shù)組時,會超出空間復(fù)雜度。然后,思考如何減少內(nèi)存消耗。在這個例子中,有幾個不錯的選擇:

  1. 鏈?zhǔn)绞褂?map 來避免多次克?。?/li>
const mappedArr = data
  .map((entity) => {
    return {
      ...entity,
      walkingOnTwoLegs: entity.type === Type.Human
    }
  })
  .map((entity) => {
    return {
      ...entity,
      greeting: entity.type === Type.Human ? 'hello' : 'none'
    }
  });

console.log(mappedArr);
// 輸出結(jié)果:
// [
//   { name: 'Frogi', type: 'frog', walkingOnTwoLegs: false, greeting: 'none' },
//   { name: 'Mark', type: 'human', walkingOnTwoLegs: true, greeting: 'hello' },
//   { name: 'John', type: 'human', walkingOnTwoLegs: true, greeting: 'hello' },
//   { name: 'Rexi', type: 'dog', walkingOnTwoLegs: false, greeting: 'none' }
// ]
  1. 更好的方法是減少 map 和克隆操作的數(shù)量:
const mappedArr = data.map((entity) => 
  entity.type === Type.Human ? {
    ...entity,
    walkingOnTwoLegs: true,
    greeting: 'hello'
  } : {
    ...entity,
    walkingOnTwoLegs: false,
    greeting: 'none'
  }
);

console.log(mappedArr);
// 輸出結(jié)果:
// [
//   { name: 'Frogi', type: 'frog', walkingOnTwoLegs: false, greeting: 'none' },
//   { name: 'Mark', type: 'human', walkingOnTwoLegs: true, greeting: 'hello' },
//   { name: 'John', type: 'human', walkingOnTwoLegs: true, greeting: 'hello' },
//   { name: 'Rexi', type: 'dog', walkingOnTwoLegs: false, greeting: 'none' }
// ]

5.使用 Map 或 Object 代替 switch-case

來看下面的例子:

function findCities(country) {
  switch (country) {
    case 'Russia':
      return ['Moscow', 'Saint Petersburg'];
    case 'Mexico':
      return ['Cancun', 'Mexico City'];
    case 'Germany':
      return ['Munich', 'Berlin'];
    default:
      return [];
  }
}

console.log(findCities(null));      // 輸出結(jié)果: []
console.log(findCities('Germany')); // 輸出結(jié)果: ['Munich', 'Berlin']

上面的代碼似乎沒有問題,不過可以使用對象字面量以更清晰的語法來實現(xiàn)相同的結(jié)果:

const citiesCountry = {
  Russia: ['Moscow', 'Saint Petersburg'],
  Mexico: ['Cancun', 'Mexico City'],
  Germany: ['Munich', 'Berlin']
};

function findCities(country) {
  return citiesCountry[country] ?? [];
}

console.log(findCities(null));      // 輸出結(jié)果: []
console.log(findCities('Germany')); // 輸出結(jié)果: ['Munich', 'Berlin']

Map 是 ES6 中引入的一種對象類型,它允許存儲鍵值對,也可以使用 Map 來實現(xiàn)相同的結(jié)果:

const citiesCountry = new Map()
  .set('Russia', ['Moscow', 'Saint Petersburg'])
  .set('Mexico', ['Cancun', 'Mexico City'])
  .set('Germany', ['Munich', 'Berlin']);

function findCities(country) {
  return citiesCountry.get(country) ?? [];
}

console.log(findCities(null));      // 輸出結(jié)果: []
console.log(findCities('Germany')); // 輸出結(jié)果: ['Munich', 'Berlin']

那我們是否應(yīng)該停止使用 switch 語句?不是的。在可能的情況下使用對象字面量或 Map 可以提高代碼水平,使其更加優(yōu)雅。

Map 和對象字面量之間的主要區(qū)別如下:

  • 鍵: 在 Map 中,鍵可以是任何數(shù)據(jù)類型(包括對象和原始值)。而在對象字面量中,鍵必須是字符串或符號。
  • 迭代: 在 Map 中,可以使用 for...of 循環(huán)或 forEach() 方法迭代。在對象字面量中,需要使用 Object.keys()、Object.values() 或 Object.entries() 來迭代。
  • 性能: 一般來說,在處理大型數(shù)據(jù)集或頻繁添加/刪除時,Map 的性能優(yōu)于對象字面量。對于小型數(shù)據(jù)集或不經(jīng)常操作的情況下,性能差異可以忽略不計。 選擇使用哪種數(shù)據(jù)結(jié)構(gòu)取決于具體的用例。
責(zé)任編輯:華軒 來源: 前端充電寶
相關(guān)推薦

2024-07-26 00:35:33

2023-06-28 00:02:40

2023-07-18 07:56:31

工具reduce業(yè)務(wù)

2020-12-14 08:30:02

JavaScript開發(fā)代碼

2022-05-10 09:33:50

Pandas技巧代碼

2021-09-22 23:17:09

Java開發(fā)數(shù)組

2020-07-02 08:27:47

Javascript

2022-11-07 16:25:07

JavaScript技巧

2020-06-24 07:44:12

Python數(shù)據(jù)技術(shù)

2023-12-19 13:31:00

CSS前端技巧

2024-02-26 08:20:00

CSS開發(fā)

2015-07-16 14:51:13

下載助手斷點續(xù)傳多任務(wù)

2020-09-29 08:14:46

JavaScript開發(fā)代碼

2022-12-19 15:23:51

JavaScrip開發(fā)語言

2023-05-30 15:11:16

JavaScrip開發(fā)功能

2023-11-26 17:54:07

JavaScript開發(fā)

2024-08-21 14:55:02

2024-06-03 10:35:41

2022-12-22 14:44:06

JavaScript技巧

2022-12-25 16:03:31

JavaScript技巧
點贊
收藏

51CTO技術(shù)棧公眾號