成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

一口氣看完,ES8,9,10,13,14,15中30多個(gè)最具變革性的JavaScript特性

開(kāi)發(fā) 前端
總的來(lái)說(shuō),ES15對(duì)JavaScript來(lái)說(shuō)是一個(gè)重大飛躍,包含了幾個(gè)對(duì)現(xiàn)代開(kāi)發(fā)至關(guān)重要的特性。幫助你以更簡(jiǎn)潔、更富表現(xiàn)力、更清晰的方式編寫(xiě)更干凈的代碼。

ES8包含了許多有價(jià)值的特性,徹底改變了我們編寫(xiě)JavaScript的方式。

代碼變得更簡(jiǎn)潔、更易編寫(xiě),并升級(jí)了新功能。

我們來(lái)看看這些特性,看看你是否錯(cuò)過(guò)了哪些。

1.尾隨逗號(hào)

在ES8之前,尾隨逗號(hào)會(huì)導(dǎo)致語(yǔ)法錯(cuò)誤!

? 之前:

const colors = [
    'red',
    'blue',
    'green',
    'yellow', // ? 不允許
];

const person = {
    name: 'Tari Ibaba',
    site: 'codingbeautydev.com' // ? 不行
};

但這引發(fā)了一些問(wèn)題,重新排列列表會(huì)帶來(lái)麻煩:

圖片圖片

我們還必須總是在最后一項(xiàng)添加逗號(hào)才能添加新項(xiàng) — 這會(huì)使git差異變得混亂:

圖片圖片

所以ES8修復(fù)了所有這些:

? 現(xiàn)在:

const colors = [
    'red',
    'blue',
    'green',
    'yellow', // ? yes
];

const person = {
    name: 'Tari Ibaba',
    site: 'codingbeautydev.com', // ? yes
};

它們帶來(lái)的好處也使得像Prettier這樣的工具在格式化后默認(rèn)添加它們:

圖片圖片

2.async/await

這就是async/await的起源!

不再需要煩人的then()嵌套:

? 之前:

wait().then(() => {
    console.log('WHERE ARE YOU?! ??');
});

function wait() {
    return new Promise((resolve) =>
        setTimeout(resolve, 10 * 1000)
    );
}

? 現(xiàn)在:

// ?? immediately invoked function expression (IIFE)
(async () => {
    await wait();
    console.log('WHERE ARE YOU?! ??');
})();

function wait() {
    return new Promise((resolve) =>
        setTimeout(resolve, 10 * 1000)
    );
}

區(qū)別很明顯:

? 之前:

function getSuggestion() {
    fetch('https://api.example/suggestion', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({}) // Pass the necessary payload here
    })
    .then((res) => {
        return res.json();
    })
    .then((data) => {
        const { suggestion } = data;
        console.log(suggestion);
    });
}

? 現(xiàn)在:

async function getSuggestion() {
    const res = await fetch('https://api.example/suggestion');
    const { suggestion } = await res.json();
    console.log(suggestion);
}

10行 → 3行。

使用async/await,我們終于可以為異步代碼使用原生的 try-catch:

? ES8之前:

startWorkout();

function startWorkout() {
    goToGym()
        .then((result) => {
            console.log(result);
        })
        .catch((err) => {
            console.log(err);
        });
}

function goToGym() {
    return new Promise((resolve, reject) => {
        if (Math.random() > 0.5) {
            reject(new Error("I'm tired today!??"));
        }
        resolve("Let's go!??♂?");
    });
}

? 現(xiàn)在:

startWorkout();

// ? async/await
async function startWorkout() {
    try {
        await goToGym();
    } catch (err) {
        console.log(err);
    }
}

function goToGym() {
    return new Promise((resolve, reject) => {
        if (Math.random() > 0.5) {
            reject(new Error("I'm tired today!??"));
        }
        resolve("Let's go!??♂?");
    });
}

3.強(qiáng)大的Object靜態(tài)方法

Object.values()

一個(gè)出色的靜態(tài)方法,可以將對(duì)象的所有值提取到一個(gè)數(shù)組中:

const person = {
    name: 'Tari Ibaba',
    site: 'codingbeautydev.com',
    color: '??blue',
};

const arr = Object.values(person);

// ['Tari Ibaba', 'codingbeautydev.com', '??blue']
console.log(arr);

非常適合數(shù)據(jù)可視化:

const fruits = [
    {
        name: 'Banana',
        pic: '??',
        color: 'yellow',
    },
    {
        name: 'Apple',
        pic: '??',
        color: 'red',
    },
];

const keys = Object.keys(fruits.at(0));
const header = keys.map((key) => `| ${key} |`).join('');
const rows = fruits
    .map((fruit) =>
        keys.map((key) => `| ${fruit[key]} |`).join('')
    ).join('\n');

console.log(header + '\n' + rows);

圖片圖片

Object.entries()

const person = {
    name: 'Tari Ibaba',
    site: 'codingbeautydev.com',
    color: '??blue',
};

const arr = Object.entries(person);

/*
[
  ['name', 'Tari Ibaba'],
  ['site', 'codingbeautydev.com'],
  ['color', '??blue']
]
*/

console.log(arr);

將對(duì)象中的每個(gè)鍵值對(duì)捆綁在一起,生成一個(gè)元組列表:

非常適合使用對(duì)象的鍵和值進(jìn)行數(shù)據(jù)轉(zhuǎn)換:

以ID為鍵的對(duì)象 → 對(duì)象列表:

? 之前:

const tasks = {
    1: {
        title: '???HIIT 30 minutes today',
        complete: false,
    },
    2: {
        name: 'Buy the backpack??',
        complete: true,
    },
};

const taskList = Object.keys(tasks).map((id) => ({
    id,
    ...tasks[id],
}));

console.log(taskList);

? 現(xiàn)在:

// ? 更簡(jiǎn)潔
const taskList = Object.entries(tasks).map(
    ([id, task]) => ({
        id,
        ...task,
    })
);

console.log(taskList);

圖片圖片

4.原生字符串填充

2016年3月22日,流行的NPM包left-pad被創(chuàng)建者作為一種抗議形式下架,導(dǎo)致數(shù)千個(gè)軟件項(xiàng)目崩潰。

這讓許多人擔(dān)心我們可能過(guò)度依賴外部模塊 — 即使是像字符串填充這樣簡(jiǎn)單的功能。

但幸運(yùn)的是,ES8為JavaScript帶來(lái)了原生的字符串填充功能,即padStart和padEnd字符串方法:

const name = 'tari';

console.log(name.padStart(9, ' '));    // '     tari'
console.log(name.padEnd(10, '??')); // 'tari????????'

我們不再需要依賴另一個(gè)第三方依賴。

5. Object.getOwnPropertyDescriptors()

名字聽(tīng)起來(lái)有點(diǎn)花哨,但很容易理解。

描述符是屬性的屬性 — 以下之一:

  • value
  • enumerable
  • get
  • set
  • configurable
  • enumerable
const person = {
  name: 'Tari Ibaba',
  color: '??color',
  age: 999,
  greet: () => console.log('Hey!'),
};

console.log(
  Object.getOwnPropertyDescriptors(person)
);

圖片圖片

最后的思考

總的來(lái)說(shuō),ES8對(duì)JavaScript來(lái)說(shuō)是一個(gè)重大飛躍,引入了幾個(gè)已成為現(xiàn)代開(kāi)發(fā)必不可少的特性。使你能夠編寫(xiě)更簡(jiǎn)潔、更富表現(xiàn)力和更清晰的代碼。

過(guò)去10年里,JavaScript取得了長(zhǎng)足進(jìn)步,每年都有全新的功能升級(jí)。

今天,我們來(lái)看看早期ES9中引入的5個(gè)最重要的特性,看看你是否錯(cuò)過(guò)了其中一些。

1. 異步生成器和迭代

異步生成器是ES9中一個(gè)強(qiáng)大的特性。

就像普通的生成器,但現(xiàn)在它可以在異步工作(如網(wǎng)絡(luò)請(qǐng)求)后彈出值:

function* asyncGenerator() {
  yield new Promise((resolve) =>
    setTimeout(() => resolve('done this ?'), 2000)
  );
  yield new Promise((resolve) =>
    setTimeout(() => resolve('done that ?'), 3000)
  );
}

當(dāng)我們調(diào)用.next()時(shí),我們會(huì)得到一個(gè)Promise:

const asyncGen = asyncGenerator();

asyncGen.next().value.then(console.log);
asyncGen.next().value.then(console.log);

這是一個(gè)強(qiáng)大的工具,可以在web應(yīng)用中以結(jié)構(gòu)化+可讀的方式流式傳輸數(shù)據(jù) — 看看這個(gè)為類似YouTube的視頻分享應(yīng)用緩沖和流式傳輸數(shù)據(jù)的函數(shù):

async function* streamVideo({ id }) {
  let endOfVideo = false;
  const downloadChunk = async (sizeInBytes) => {
    const response = await fetch(
      `api.example.com/videos/${id}`
    );
    const { chunk, done } = await response.json();
    if (done) endOfVideo = true;
    return chunk;
  };
  while (!endOfVideo) {
    const bufferSize = 500 * 1024 * 1024;
    yield await downloadChunk(bufferSize);
  }
}

現(xiàn)在要消費(fèi)這個(gè)生成器,我們將使用for await of — 異步迭代:

for await (const chunk of streamVideo({ id: 2341 })) {
  // process video chunk
}

我想知道實(shí)際的YouTube JavaScript代碼是否使用了這樣的生成器?

2.對(duì)象的剩余/展開(kāi)運(yùn)算符

毫無(wú)疑問(wèn),你在某處遇到過(guò)現(xiàn)代的展開(kāi)語(yǔ)法。

這是一種快速且不可變地克隆數(shù)組的天才方法:

const colors = ['??', '??', '??'];

console.log([...colors, '??']); 
// ['??', '??', '??', '??']

在ES6之前我們從未有過(guò)它,現(xiàn)在它無(wú)處不在。

Redux就是一個(gè)重要的例子:

export default function userState(state = initialUserState, action) {
  console.log(arr); 
  switch (action.type) {
    case ADD_ITEM:
      return {
        ...state,
        arr: [...state.arr, action.newItem]
      };
    default: 
      return state;
  }
}

從ES9開(kāi)始,它也適用于對(duì)象:

const info = {
  name: 'Coding Beauty',
  site: 'codingbeautydev.com',
};

console.log({ ...info, theme: '??' });

/* Output:
{
  name: 'Coding Beauty',
  site: 'codingbeautydev.com',
  theme: '??'
}
*/

覆蓋屬性:

const langs = {
  j: 'java',
  c: 'c++',
};

console.log({ ...langs, j: 'javascript' });

// Output: { j: 'javascript', c: 'c++' }

這使得它特別適合在默認(rèn)值的基礎(chǔ)上構(gòu)建,尤其是在制作公共實(shí)用程序時(shí)。

或者像我用Material UI定制默認(rèn)主題那樣:

圖片圖片

使用展開(kāi)語(yǔ)法,你甚至可以去掉不想在副本中出現(xiàn)的對(duì)象屬性。

const colors = {
  yellow: '??',
  blue: '??',
  red: '??',
};

const { yellow, ...withoutYellow } = colors;

console.log(withoutYellow);

// Output: { blue: '??', red: '??' }

這就是如何以不可變的方式從對(duì)象中移除屬性。

3. String.raw

當(dāng)我使用String.raw時(shí),我是在說(shuō):只給我我給你的東西。不要處理任何東西。不要?jiǎng)幽切┺D(zhuǎn)義字符:

不再需要轉(zhuǎn)義反斜杠,我們不用寫(xiě):

const filePath = 'C:\\Code\\JavaScript\\tests\\index.js';

console.log(`The file path is ${filePath}`);

// Output: The file path is C:\Code\JavaScript\tests\index.js

而是寫(xiě):

const filePath = String.raw`C:\Code\JavaScript\tests\index.js`;

console.log(`The file path is ${filePath}`);

// Output: The file path is C:\Code\JavaScript\tests\index.js

非常適合編寫(xiě)帶有大量這些反斜杠的正則表達(dá)式:

像這樣但更糟:

從這個(gè)?:

const patternString = 'The (\\w+) is (\\d+)';
const pattern = new RegExp(patternString);

const message = 'The number is 100';

console.log(pattern.exec(message));
// ['The number is 100', 'number', '100']

到這個(gè)?:

const patternString = String.raw`The (\w+) is (\d+)`;
const pattern = new RegExp(patternString);

const message = 'The number is 100';

console.log(pattern.exec(message));
// ['The number is 100', 'number', '100']

所以"raw"意味著未處理的。

圖片圖片

這就是為什么我們有String.raw()但沒(méi)有String.cooked()。

4. 復(fù)雜的正則表達(dá)式特性

說(shuō)到正則表達(dá)式,ES9并沒(méi)有讓人失望。

它完全裝載了最先進(jìn)的正則表達(dá)式特性,用于高級(jí)字符串搜索和替換。

向后查找斷言

這是一個(gè)新特性,用于確保只有某個(gè)特定模式出現(xiàn)在你要搜索的內(nèi)容之前:

  • 正向后查找:白名單 ?<=pattern
  • 負(fù)向后查找:黑名單 ?<!pattern
const str = "It's just $5, and I have €20 and £50";

// Only match number sequence if $ comes first
const regexPos = /(?<=\$)\d+/g;

console.log(str.match(regexPos)); // ['5']

const regexNeg = /(?<!\$)\d+/g;

console.log(str.match(regexNeg)); // ['20', '50']

圖片圖片

命名捕獲組

捕獲組一直是正則表達(dá)式中最寶貴的特性之一,用于以復(fù)雜的方式轉(zhuǎn)換字符串。

const str = 'The cat sat on a map';

// $1 -> [a-z]
// $2 -> a
// $3 -> t

// () indicates group
str.replace(/([a-z])(a)(t)/g, '$1*$3');
// -> The c*t s*t on a map

通常,這些組按照它們?cè)谡齽t表達(dá)式中的相對(duì)位置命名:1, 2, 3...

但這使得理解和更改那些愚蠢的長(zhǎng)正則表達(dá)式變得更加困難。

所以ES9通過(guò)?<name>來(lái)命名捕獲組解決了這個(gè)問(wèn)題:

const str = 'The cat sat on a map';

// left & right
console.log(str.replace(/(?<left>[a-z])(a)(?<right>t)/g, '$<left>*$<right>'));

// -> The c*t s*t on a map

圖片圖片

你知道當(dāng)VS Code中出現(xiàn)錯(cuò)誤時(shí),你可以快速Alt + 點(diǎn)擊跳轉(zhuǎn)到錯(cuò)誤發(fā)生的確切位置嗎???

圖片圖片

VS Code使用捕獲組使文件名可點(diǎn)擊,從而實(shí)現(xiàn)這種快速導(dǎo)航。

我想它大概是這樣的:

// The stupidly long regex
const regex = /(?<path>[a-z]:[a-z].(?:?:\\/|(?:\\/?)))[\w \-]+):(?<line>\d+):(?<char>\d+)/gi;

// ? String.raw!
const filePoint = String.raw`C:\coding-beauty\coding-beauty-javascript\index.js:3:5`;

const extractor = /(?<path>[a-z]:[a-z].(?:?:\\/|(?:\\/?)))[\w \-]+):(?<line>\d+):(?<char>\d+)/i;
const [path, lineStr, charStr] = filePoint
  .match(regex)[0]
  .match(extractor)
  .slice(1, 4);

const line = Number(lineStr);

const char = Number(charStr);

console.log({ path, line, char });

// Replace all filePoint with <button> tag
// <button notallow="navigateWithButtonFilepointInnerText">filePoint</button>

5. Promise.finally

最后我們有了Promise.finally ??。

你知道finally總是會(huì)運(yùn)行一些代碼,無(wú)論是否有錯(cuò)誤嗎?

function startBodyBuilding() {
  if (Math.random() > 0.5) {
    throw new Error("I'm tired??");
  }
  console.log('Off to the gym ???♂???');
}

try {
  startBodyBuilding();
} catch {
  console.log('Stopped excuse??');
} finally {
  console.log("I'm going!??♂?");
}

所以Promise.finally就像那樣,但是用于異步任務(wù):

async function startBodyBuilding() {
  await think();
  if (Math.random() > 0.5) {
    throw new Error("I'm tired??");
  }
  console.log('Off to the gym ???♂???');
}

startBodyBuilding()
  .then(() => {
    console.log('Started ?');
  })
  .catch(() => {
    console.log('No excuses');
  })
  .finally(() => {
    console.log("I'm going!??♂?");
  });

Promise.finally()最大的優(yōu)點(diǎn)是當(dāng)你鏈接許多Promise時(shí):

它也能很好地與Promise鏈一起工作:

getFruitApiUrl().then((url) => {
  return fetch(url)
    .then((res) => res.json())
    .then((data) => {
      fruits.push(data);
    })
    .catch((err) => {
      console.error(err);
    })
    .finally(() => {
      console.log(fruits);
    });
});

這是由ES9帶來(lái)的。

最后的思考

ES9標(biāo)志著JavaScript的一個(gè)重大飛躍,引入了幾個(gè)對(duì)現(xiàn)代開(kāi)發(fā)至關(guān)重要的特性。使你能夠快速編寫(xiě)更清晰、更簡(jiǎn)潔、更富表現(xiàn)力的代碼。

JavaScript在過(guò)去10年里取得了長(zhǎng)足的進(jìn)步,每一年都有全新的功能升級(jí)。

還記得我們以前是這樣創(chuàng)建"類"的嗎?

function Person(name) {
  this.name = name;
}

Person.prototype.sayHello = function() {
  console.log("Hello, " + this.name);
};

是的,變化很大!

讓我們來(lái)看看ES10(2019年)中引入的7個(gè)最重要的特性,看看你是否錯(cuò)過(guò)了其中一些。

1. 即時(shí)模塊化:動(dòng)態(tài)import

ES10那年很棒,import現(xiàn)在可以像require()一樣作為函數(shù)使用。一個(gè)async函數(shù)。

將import保持在頂層不再是必須的;我們現(xiàn)在可以在編譯時(shí)輕松解析模塊的名稱。

為了高性能,可以選擇性地只在絕對(duì)需要時(shí)加載模塊...

if (user.is_admin) {
  const admin = await import('./admin.js');
  admin.setupDashboard();
}

基于用戶或變量輸入加載模塊...

const language = 'french';
const translations = await import(`./translations/${language}.js`);

它也非常適合使用不再支持require()的ES模塊:

2. 扁平化曲線

flat()和flatMap()提供了更清晰的方式來(lái)輕松扁平化多維數(shù)組。

消除了痛苦的數(shù)組循環(huán)扁平化代碼的需求:

圖片圖片

flatMap()相當(dāng)于調(diào)用map(),然后flat(1):

圖片圖片

3. 將數(shù)組轉(zhuǎn)換為對(duì)象

ES10還引入了Object.fromEntries()到JavaScript世界。

快速將鍵值對(duì)列表轉(zhuǎn)換為等效的鍵值對(duì)象:

const entries = [['name', 'John'], ['age', 30]];
const obj = Object.fromEntries(entries);
console.log(obj); // { name: 'John', age: 30 }

4. 精確清理你的字符串

trimStart()和trimEnd()。

在此之前,每個(gè)人都在使用NPM的trim - 愉快地給項(xiàng)目增加3.35KB...

即使現(xiàn)在:

npm i trim

然后Array trim()出現(xiàn)了,接著是trimStart()和trimEnd()。

const str = '   Hello, World!   ';
console.log(str.trimStart()); // 'Hello, World!   '
console.log(str.trimEnd());   // '   Hello, World!'

5. 捕獲錯(cuò)誤而不帶包袱

通過(guò)新的可選catch綁定,當(dāng)你對(duì)錯(cuò)誤參數(shù)無(wú)所作為時(shí),現(xiàn)在可以安全地省略catch塊的錯(cuò)誤參數(shù):

圖片圖片

6. 無(wú)驚喜排序

穩(wěn)定的數(shù)組排序。

以前,在對(duì)數(shù)組進(jìn)行排序時(shí),我們絕對(duì)無(wú)法保證相等元素的排列。

但在ES10之后的JS代碼中,我們100%確定react總是在vue之前,vue總是在angular之前。

圖片圖片

圖片圖片

7. 要么做大,要么回家:BigInt

BigInt的名稱揭示了它的目的:用于加載難以置信的巨大整數(shù)值:

圖片圖片

圖片圖片

因?yàn)槠胀ㄕ麛?shù)做不到:

圖片圖片

最后的思考

ES10為JavaScript標(biāo)志著一個(gè)重要的飛躍,引入了幾個(gè)對(duì)現(xiàn)代開(kāi)發(fā)至關(guān)重要的特性。

使用它們來(lái)編寫(xiě)更清晰、更簡(jiǎn)潔、更具表現(xiàn)力和清晰度的代碼。

ES13包含了許多有價(jià)值的特性,徹底改變了我們編寫(xiě)JavaScript的方式。

從異步升級(jí)到數(shù)組語(yǔ)法糖等等,讓我們來(lái)看看這些特性,看看你是否錯(cuò)過(guò)了其中一些。

1. 頂級(jí)await

在ES13之前,我們永遠(yuǎn)不能在全局作用域中使用await。

? 之前:

// X 語(yǔ)法錯(cuò)誤:await 只在異步函數(shù)中有效
await setTimeoutAsync(3000);

function setTimeoutAsync(timeout) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve('codingbeautydev.com');
    }, timeout);
  });
}

我們總是必須將其放在async函數(shù)中或創(chuàng)建一個(gè)async IIFE(立即執(zhí)行函數(shù)表達(dá)式):

// 異步立即執(zhí)行函數(shù)
(async () => {
  await setTimeoutAsync(3000);
})();

// 類似 C++
async function main() {
  await setTimeoutAsync(3000);
}

? ES13之后:

// ? 等待超時(shí) - 沒(méi)有拋出錯(cuò)誤
await setTimeoutAsync(3000);

function setTimeoutAsync(timeout) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve('codingbeautydev.com');
    }, timeout);
  });
}

2. 類聲明升級(jí)

2.1 類字段聲明

在ES13之前,我們只能在構(gòu)造函數(shù)中聲明類字段: 與許多其他語(yǔ)言不同,我們不能在類的最外層作用域中聲明或定義它們。

? 之前:

? 現(xiàn)在有了ES13: 就像在TypeScript中一樣:

2.2 私有方法和字段

在ES13之前,創(chuàng)建私有方法是不可能的。 我們還必須使用丑陋的下劃線hack來(lái)表示私有性 — 但那只是一個(gè)指示。

? 之前:

class Person {
  _firstName = 'Tari';
  _lastName = 'Ibaba';

  get name() {
    return `${this._firstName} ${this._lastName}`;
  }
}

const person = new Person();
console.log(person.name); // Tari Ibaba

// 我們?nèi)匀豢梢栽L問(wèn)私有成員!
console.log(person._firstName); // Tari
console.log(person._lastName); // Ibaba

// 它們也可以被修改!
person._firstName = 'Lionel';
person._lastName = 'Messi';

console.log(person.name); // Lionel Messi

? ES13之后:

我們可以通過(guò)在字段前加上井號(hào)(#)來(lái)為類添加私有字段和成員:

如果你試圖從類外部訪問(wèn)它,你會(huì)得到一個(gè)語(yǔ)法錯(cuò)誤:

class Person {
  #firstName = 'Tari';
  #lastName = 'Ibaba';

  get name() {
    return `${this.#firstName} ${this.#lastName}`;
  }
}

const person = new Person();
console.log(person.name);

// 語(yǔ)法錯(cuò)誤:私有字段 '#firstName' 必須在封閉的類中聲明
console.log(person.#firstName);
console.log(person.#lastName);

我們可以從錯(cuò)誤消息中看到一些有趣的東西:

編譯器甚至不期望你從類外部嘗試訪問(wèn)私有字段 — 它假設(shè)你是在嘗試創(chuàng)建一個(gè)。

2.3 靜態(tài)類字段和靜態(tài)私有方法

靜態(tài)字段 — 類本身的屬性,而不是任何特定實(shí)例的屬性。

自ES13以來(lái),我們現(xiàn)在可以輕松地為任何類創(chuàng)建它們:

class Person {
  static #count = 0;
  static eyeCount = 2;

  static getCount() {
    // 使用 this 訪問(wèn)同級(jí)靜態(tài)成員
    return this.#count;
  }

  // 實(shí)例成員
  constructor() {
    // 使用 this.constructor 訪問(wèn)靜態(tài)成員
    this.constructor.#incrementCount();
  }

  static #incrementCount() {
    this.#count++;
  }
}

const person1 = new Person();
const person2 = new Person();
console.log(Person.getCount()); // 2

3. 數(shù)組升級(jí):新的at()方法

通常我們會(huì)使用方括號(hào)([])來(lái)訪問(wèn)數(shù)組的第N個(gè)元素。

const arr = ['a', 'b', 'c', 'd'];

console.log(arr[1]); // b

但從末尾訪問(wèn)第N個(gè)項(xiàng)目一直是一個(gè)痛點(diǎn) -- 我們必須使用arr.length - N進(jìn)行索引:

? ES13之前:

const arr = ['a', 'b', 'c', 'd'];

// 倒數(shù)第1個(gè)元素
console.log(arr[arr.length - 1]); // d

// 倒數(shù)第2個(gè)元素
console.log(arr[arr.length - 2]); // c

幸運(yùn)的是,ES13帶來(lái)了一個(gè)新的at()方法,解決了所有這些問(wèn)題:

const str = 'Coding Beauty';

console.log(str.at(-1)); // y 倒數(shù)第1個(gè)字符

console.log(str.at(-2)); // t 倒數(shù)第2個(gè)字符

4. 靜態(tài)類塊

隨著靜態(tài)字段的出現(xiàn),靜態(tài)塊也來(lái)了。 只在類創(chuàng)建時(shí)執(zhí)行一次代碼 — 就像C#和Java等OOP語(yǔ)言中的靜態(tài)構(gòu)造函數(shù)。 所以你可以在類中創(chuàng)建任意多個(gè)靜態(tài)塊 — 所有代碼都會(huì)按你定義的順序運(yùn)行:

class Vehicle {
  static defaultColor = 'blue';
}

class Car extends Vehicle {
  static colors = [];
  // ?? pushes red before green
  // ?? 先添加 red,然后添加 green
  static {
    this.colors.push(super.defaultColor, 'red');
  }
  static {
    this.colors.push('green');
  }
}

console.log(Car.colors); // ['blue', 'red', 'green']

5. 錯(cuò)誤報(bào)告升級(jí)

有時(shí)我們捕獲調(diào)用棧下方方法的錯(cuò)誤,只是為了將其重新拋出回調(diào)用棧上方。 但當(dāng)我們這樣做時(shí),我們會(huì)失去原始錯(cuò)誤中的關(guān)鍵信息:

try {
  userAction();
} catch (err) {
  // ? doesn't know fundamental cause of error
  // ? 不知道錯(cuò)誤的根本原因
  console.log(err);
}

function userAction() {
  try {
    apiCallThatCanThrow();
  } catch (err) {
    // ?? rethrow
    // ?? 重新拋出錯(cuò)誤
    throw new Error('New error message');
  }
}

function apiCallThatCanThrow() {
  console.log('fetching from codingbeautydev.com...');
  throw new Error('throwing for no reason');
}

這就是為什么ES13引入了一個(gè)新的cause屬性來(lái)保留這個(gè)重要信息并使調(diào)試更容易:

try {
  userAction();
} catch (err) {
  // ? now knows what caused the error
  // ? 現(xiàn)在知道了錯(cuò)誤的原因
  console.log(err);
  console.log(`Caused by: ${err.cause}`);
}

function userAction() {
  try {
    apiCallThatCanThrow();
  } catch (err) {
    // ? error cause
    // ? 錯(cuò)誤原因
    throw new Error('New error message', { cause: err });
  }
}

function apiCallThatCanThrow() {
  console.log('fetching from codingbeautydev.com...');
  throw new Error('throwing for no reason');
}

最后的思考

總的來(lái)說(shuō),ES13對(duì)JavaScript來(lái)說(shuō)是一個(gè)重大飛躍,它帶來(lái)了幾個(gè)已成為現(xiàn)代開(kāi)發(fā)必不可少的特性。 使你能夠編寫(xiě)更清晰、更簡(jiǎn)潔、更具表現(xiàn)力的代碼。

JavaScript在過(guò)去10年里取得了長(zhǎng)足的進(jìn)步,每年都有全新的功能升級(jí)。 讓我們來(lái)看看ES14(2023年)中引入的5個(gè)最重要的特性,看看你是否錯(cuò)過(guò)了其中一些。

1. toSorted()

甜美的語(yǔ)法糖。

ES14的toSorted()方法使得排序數(shù)組并返回一個(gè)副本而不改變?cè)瓟?shù)組變得更加容易。

以前我們這樣做:

const numbers = [3, 1, 4, 1, 5];
const sorted = [...numbers].sort((a, b) => a - b);
console.log(sorted); // [1, 1, 3, 4, 5]
console.log(numbers); // [3, 1, 4, 1, 5]

現(xiàn)在我們可以這樣做?:

const numbers = [3, 1, 4, 1, 5];
const sorted = numbers.toSorted((a, b) => a - b);
console.log(sorted); // [1, 1, 3, 4, 5]
console.log(numbers); // [3, 1, 4, 1, 5]

toSorted()接受一個(gè)回調(diào)函數(shù)來(lái)控制排序行為 - 升序或降序,按字母順序或數(shù)字順序。就像sort()一樣。

2. toReversed()

另一個(gè)新的數(shù)組方法,用于促進(jìn)不可變性和函數(shù)式編程。

以前 — 使用reverse() ?:

const numbers = [1, 2, 3, 4, 5];
const reversed = numbers.reverse();
console.log(reversed); // [5, 4, 3, 2, 1]
console.log(numbers); // [5, 4, 3, 2, 1]

現(xiàn)在 — 使用toReversed() ?:

const numbers = [1, 2, 3, 4, 5];
const reversed = numbers.toReversed();
console.log(reversed); // [5, 4, 3, 2, 1]
console.log(numbers); // [1, 2, 3, 4, 5]

我發(fā)現(xiàn)這些不可變方法非常棒,可以不斷地鏈?zhǔn)秸{(diào)用方法,而不用擔(dān)心原始變量:

const result = numbers.toReversed().toSorted((a, b) => a - b);

3. toSpliced()

函數(shù)式編程愛(ài)好者無(wú)疑會(huì)對(duì)所有這些新的數(shù)組方法感到高興。 這是.splice()的不可變版本:

const items = [1, 2, 3, 4, 5];
const newItems = items.toSpliced(2, 1, 6, 7);
console.log(newItems); // [1, 2, 6, 7, 4, 5]
console.log(items); // [1, 2, 3, 4, 5]

4. 從末尾開(kāi)始查找數(shù)組

從第一項(xiàng)開(kāi)始搜索并不總是理想的:

圖片圖片

你可以很容易地看到,對(duì)我們的巨大列表從末尾而不是開(kāi)始搜索會(huì)快得多。

圖片圖片

有時(shí)你必須從末尾搜索才能讓你的程序工作。

比如我們想在一個(gè)數(shù)字列表中找到最后一個(gè)偶數(shù),find和findIndex會(huì)非常不準(zhǔn)確。 調(diào)用reverse()也不行,即使它會(huì)很慢:

const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const lastEven = numbers.reverse().find(n => n % 2 === 0);
console.log(lastEven); // 10(不正確)

所以在這種情況下,findLast()和findLastIndex()方法就派上用場(chǎng)了。

const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const lastEven = numbers.findLast(n => n % 2 === 0);
console.log(lastEven); // 10(正確)

這段代碼更短、更易讀。最重要的是,它產(chǎn)生了正確的結(jié)果。

5. 數(shù)組的with()方法

with()是我們快速更改數(shù)組元素而不進(jìn)行任何突變的方法。

以前的常規(guī)方式:

const arr = [1, 2, 3, 4, 5];
const newArr = [...arr];
newArr[2] = 6;
console.log(newArr); // [1, 2, 6, 4, 5]
console.log(arr); // [1, 2, 3, 4, 5]

ES14現(xiàn)在讓我們這樣做:

const arr = [1, 2, 3, 4, 5];
const newArr = arr.with(2, 6);
console.log(newArr); // [1, 2, 6, 4, 5]
console.log(arr); // [1, 2, 3, 4, 5]

最后的思考

還有其他特性,但ES14主要是關(guān)于更容易的函數(shù)式編程和內(nèi)置的不可變性。 隨著React的興起,我們看到聲明式JavaScript爆炸式地流行起來(lái);很自然地,更多的這些特性會(huì)被烘焙到語(yǔ)言中,成為甜美的語(yǔ)法糖。

2024年:又是一個(gè)帶來(lái)全新JS特性升級(jí)的不可思議的年份,ES15推出。

從復(fù)雜的異步特性到語(yǔ)法糖數(shù)組和現(xiàn)代正則表達(dá)式,JavaScript編碼現(xiàn)在比以往任何時(shí)候都更簡(jiǎn)單、更快捷。

1.原生數(shù)組分組終于到來(lái)

Object.groupBy():

const fruits = [  { name: 'pineapple??', color: '??' },  { name: 'apple??', color: '??' },  { name: 'banana??', color: '??' },  { name: 'strawberry??', color: '??' },];const groupedByColor = Object.groupBy(  fruits,  (fruit, index) => fruit.color);// 原生 group by 示例console.log(groupedByColor);

圖片圖片

字面意思就是讓恐龍級(jí)的 Lodash 庫(kù)失去了最后的存在理由 - 再也不需要了!

圖片圖片

我原本期待一個(gè)新的實(shí)例方法,比如Array.prototype.groupBy,但不知什么原因他們把它做成了靜態(tài)方法。

然后我們還有Map.groupBy來(lái)用對(duì)象鍵進(jìn)行分組:

const array = [1, 2, 3, 4, 5];const odd = { odd: true };const even = { even: true };Map.groupBy(array, (num, index) => {  return num % 2 === 0 ? even : odd;});// => Map { {odd: true}: [1, 3, 5], {even: true}: [2, 4] }

不過(guò)幾乎沒(méi)人會(huì)這樣對(duì)數(shù)組分組,所以可能不會(huì)那么受歡迎。

2.從外部解決promise - 現(xiàn)代方式

使用Promise.withResolvers()。

從外部解決promises是很普遍的需求,在此之前我們不得不使用Deferred類來(lái)實(shí)現(xiàn):

class Deferred {  constructor() {    this.promise = new Promise((resolve, reject) => {      this.resolve = resolve;      this.reject = reject;    });  }}const deferred = new Deferred();deferred.resolve();

或者從NPM安裝 - 又多了一個(gè)依賴!

圖片圖片

但現(xiàn)在有了ES15的Promise.withResolvers():

const { promise, resolve, reject } = Promise.withResolvers();

看看我如何用它來(lái)快速地將事件流promise化 - await一個(gè)observable:

// data-fetcher.jsconst { promise, resolve, reject } = Promise.withResolvers();function startListening() {    eventStream.on('data', (data) => {        resolve(data);    });}async function getData() {    return await promise;}// client.jsconst { startListening, getData } = require('./data-fetcher.js');startListening();// ? 監(jiān)聽(tīng)單個(gè)流事件const data = await getData();

3. Buffer性能升級(jí)

Buffers是用來(lái)存儲(chǔ)應(yīng)用程序生成的臨時(shí)數(shù)據(jù)的小型數(shù)據(jù)存儲(chǔ)。

它們使得在管道的各個(gè)階段之間傳輸和處理數(shù)據(jù)變得非常容易。

像這樣的管道:

  • 文件處理: 輸入文件 → buffer → 處理 → 新buffer → 輸出文件
  • 視頻流: 網(wǎng)絡(luò)響應(yīng) → buffer → 顯示視頻幀
  • 餐廳隊(duì)列: 接待顧客 → 隊(duì)列/buffer → 服務(wù)顧客
const fs = require('fs');const { Transform } = require('stream');const inputFile = 'input.txt';const outputFile = 'output.txt';const inputStream = fs.createReadStream(inputFile, 'utf-8');const transformStream = new Transform({    transform(chunk) {        // ? 從緩沖區(qū)轉(zhuǎn)換塊    },});const outputStream = fs.createWriteStream(outputFile);// ? 開(kāi)始管道inputStream.pipe(transformStream).pipe(outputStream);

使用 buffers,每個(gè)階段可以以不同的速度獨(dú)立處理數(shù)據(jù)。

但是當(dāng)通過(guò)管道移動(dòng)的數(shù)據(jù)超過(guò)buffer容量時(shí)會(huì)發(fā)生什么?

以前我們必須將當(dāng)前所有數(shù)據(jù)的buffer復(fù)制到一個(gè)更大的buffer中。

這對(duì)性能來(lái)說(shuō)很糟糕,尤其是當(dāng)管道中將有大量數(shù)據(jù)時(shí)。

ES15為我們提供了解決這個(gè)問(wèn)題的方案:可調(diào)整大小的數(shù)組buffers。

const resizableBuffer = new ArrayBuffer(1024, {    maxByteLength: 1024 ** 2,});// ? 調(diào)整大小到 2048 字節(jié)resizableBuffer.resize(1024 * 2);

4.異步升級(jí)

Atomics.waitAsync(): ES2024中另一個(gè)強(qiáng)大的異步編碼特性:

它是當(dāng)2個(gè)代理共享一個(gè)buffer時(shí)...

代理1"睡眠"并等待代理2完成任務(wù)。

當(dāng)代理2完成時(shí),它使用共享buffer作為通道進(jìn)行通知。

const sharedBuffer = new SharedArrayBuffer(4096);const bufferLocation = new Int32Array(sharedBuffer);// 初始化緩沖區(qū)位置的初始值bufferLocation[37] = 0x1330;async function doStuff() {    // ? agent 1:在共享緩沖區(qū)位置等待直到通知    Atomics.waitAsync(bufferLocation, 37, 0x1330).then(        (r) => { /* 處理到達(dá) */ }    );}function asyncTask() {    // ? agent 2:在共享緩沖區(qū)位置通知    const bufferLocation = new Int32Array(sharedBuffer);    Atomics.notify(bufferLocation, 37);}

如果你認(rèn)為這類似于普通的async/await,你絕對(duì)是對(duì)的。

但最大的區(qū)別是:這2個(gè)代理可以存在于完全不同的代碼上下文中 - 它們只需要訪問(wèn)相同的buffer。

而且:多個(gè)代理可以在不同時(shí)間訪問(wèn)或等待共享buffer - 其中任何一個(gè)都可以通知"喚醒"所有其他代理。

這就像P2P網(wǎng)絡(luò);而async/await更像是客戶端-服務(wù)器請(qǐng)求-響應(yīng)模式。

const sharedBuffer = new SharedArrayBuffer(4096);const bufferLocation = new Int32Array(sharedBuffer);bufferLocation[37] = 0x1330;// ? 從 postMessage() 接收到的共享緩沖區(qū)const code = `var ia = null;onmessage = function (ev) {    if (!ia) {        postMessage("Aux worker is running");        ia = new Int32Array(ev.data);    }    postMessage("Aux worker is sleeping for a little bit");    setTimeout(function () { postMessage("Aux worker is waking"); Atomics.notify(ia, 37); }, 1000);};`;async function doStuff() {    // ? agent 1:存在于 Worker 上下文中    const worker = new Worker(        'data:application/javascript,' + encodeURIComponent(code)    );    worker.onmessage = (event) => {        // 記錄事件    };    worker.postMessage(sharedBuffer);    Atomics.waitAsync(bufferLocation, 37, 0x1330).then(        (r) => { /* 處理到達(dá) */ }    );}function asyncTask() {    // ? agent 2:在共享緩沖區(qū)位置通知    const bufferLocation = new Int32Array(sharedBuffer);    Atomics.notify(bufferLocation, 37);}

5.正則表達(dá)式v標(biāo)志和集合操作

這是一個(gè)全新的特性,使正則表達(dá)式更加清晰和直觀。

使用表達(dá)式模式查找和操作復(fù)雜字符串 - 在集合操作的幫助下:

// A 和 B 是字符類,如 [a-z]// 差異:匹配 A 但不匹配 B[A--B]// 交集:同時(shí)匹配 A 和 B[A&&B]// 嵌套字符類[A--[0-9]]

匹配不斷增加的Unicode字符集,如:

  • 表情符號(hào): ??, ??, ??, ??, 等
  • 重音字母: é, à, ?, ?, 等
  • 符號(hào)和非拉丁字符: ?, ?, €, £, μ, ¥, 等

所以這里我們使用Unicode正則表達(dá)式和v標(biāo)志來(lái)匹配所有希臘字母:

const regex = /[\p{Script_Extensinotallow=Greek}&&\p{Letter}]/v;

最后的想法

總的來(lái)說(shuō),ES15對(duì)JavaScript來(lái)說(shuō)是一個(gè)重大飛躍,包含了幾個(gè)對(duì)現(xiàn)代開(kāi)發(fā)至關(guān)重要的特性。幫助你以更簡(jiǎn)潔、更富表現(xiàn)力、更清晰的方式編寫(xiě)更干凈的代碼。

責(zé)任編輯:武曉燕 來(lái)源: 大遷世界
相關(guān)推薦

2023-12-18 23:09:25

開(kāi)源優(yōu)化引擎

2024-07-30 08:40:00

2024-01-29 00:29:49

通信技術(shù)行業(yè)

2024-08-12 08:36:28

2024-07-25 08:37:48

2021-06-08 22:43:07

IPC方式Qt

2024-08-01 08:38:59

2020-03-31 08:12:25

Kafka架構(gòu)數(shù)據(jù)庫(kù)

2021-03-29 12:22:25

微信iOS蘋(píng)果

2024-06-14 10:22:55

2025-03-04 10:03:47

2021-12-06 08:30:49

SpringSpring Bean面試題

2025-05-14 01:55:00

FCMCPAI

2024-08-16 09:14:53

2020-04-14 13:32:56

@Transacti失效場(chǎng)景

2020-10-21 06:39:21

CPU寄存器架構(gòu)

2020-09-24 09:08:04

分布式系統(tǒng)架構(gòu)

2020-10-22 12:30:33

MySQL

2022-05-24 11:50:46

延時(shí)消息分布式

2021-05-18 09:03:16

Gomapslice
點(diǎn)贊
收藏

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

主站蜘蛛池模板: 国产精品久久久久久中文字 | 粉嫩一区二区三区四区公司1 | 99re在线视频 | 久久99精品久久久久久国产越南 | 成人av免费网站 | 欧美精品一区二区三区蜜桃视频 | av网站在线免费观看 | 日本三级视频 | 九九av| 欧美精品一区在线 | 亚洲精品日韩视频 | 色狠狠桃花综合 | 亚洲午夜av久久乱码 | 欧美二区三区 | 95国产精品 | 精品国产乱码久久久久久丨区2区 | 国产第一区二区 | 亚洲+变态+欧美+另类+精品 | 粉嫩在线| 国产高清在线 | 五月天婷婷综合 | 日韩免费高清视频 | 久久久精品国产 | 中文字幕视频在线 | 狠狠av| 亚洲国产成人精品女人久久久 | 国产伦精品一区二区三区高清 | 久久久久国产一区二区三区 | 国产精品99久久久久久久久 | 久久久精品一区二区三区 | www.国产精品 | 国产精品一区一区 | 中文字幕不卡 | 欧美日韩一区二区三区不卡视频 | 五月综合久久 | 啪啪毛片| 性一区 | www日日日 | 欧美a在线看 | 日韩一级一区 | 一级做a爰片久久毛片 |