AVt天堂网 手机版,亚洲va久久久噜噜噜久久4399,天天综合亚洲色在线精品,亚洲一级Av无码毛片久久精品

當前位置:首頁 > 科技  > 軟件

50 種 ES6 模塊,面試被問麻了

來源: 責編: 時間:2023-09-28 10:09:07 254觀看
導讀測驗 #1: 53%的答案正確// index.mjsimport { default } from './module.mjs';console.log(default);// module.mjsexport default 'bar';首先,讓我們記住各種導入和導出語法:如果檢查表中的 Import 語法,就會發現沒有與

85d28資訊網——每日最新資訊28at.com

測驗 #1: 53%的答案正確

// index.mjsimport { default } from './module.mjs';console.log(default);
// module.mjsexport default 'bar';

首先,讓我們記住各種導入和導出語法:85d28資訊網——每日最新資訊28at.com

85d28資訊網——每日最新資訊28at.com

85d28資訊網——每日最新資訊28at.com

如果檢查表中的 Import 語法,就會發現沒有與我們的代碼相匹配的語法:85d28資訊網——每日最新資訊28at.com

import { default } from ‘./module.mjs’;

因為禁止使用這種語法。測驗代碼會出現以下錯誤:85d28資訊網——每日最新資訊28at.com

SyntaxError: Unexpected reserved word85d28資訊網——每日最新資訊28at.com

在 import { default } from ‘./module.mjs’; 行中, default 是 export 的名稱,也是該作用域中的變量名稱,這是被禁止的,因為 default 是一個保留字。解決方法很簡單:85d28資訊網——每日最新資訊28at.com

import { default as foo } from ‘./module.mjs’;

現在, default 是導出的名稱, foo 是變量的名稱。換句話說,如果你想在默認導出中使用命名導入語法,就必須重命名它。就是這樣,非常簡單!85d28資訊網——每日最新資訊28at.com

測驗 #2:35% 的正確答案

// index.jsconsole.log('index.js');import { sum } from './helper.js';console.log(sum(1, 2));
// helper.jsconsole.log('helper.js');export const sum = (x, y) => x + y;

沒有多少開發人員知道的一個重要的細微差別是,導入是被提升的。也就是說,在引擎解析代碼時,導入就會被加載。所有依賴項都將在代碼運行前加載。85d28資訊網——每日最新資訊28at.com

因此,我們將按照以下順序查看日志:85d28資訊網——每日最新資訊28at.com

helper.js, index.js, 3

如果希望在導入聲明之前執行某些代碼,可考慮將其移至單獨的文件中:85d28資訊網——每日最新資訊28at.com

// new index.jsimport './logs.js';import { sum } from './helper.js';console.log(sum(1, 2));

logs.js

console.log('index.js');

現在我們有了預期的輸出結果:85d28資訊網——每日最新資訊28at.com

index.js, helper.js, 3

測驗 #3:42% 的正確答案

index.mjs

// index.mjsimport './module.mjs';import { num } from './counter.mjs';console.log('index num =', num);

module.mjs

// module.mjsimport { num } from './counter.mjs';console.log('module num =', num);

counter.mjs

// counter.mjsif (!globalThis.num) {  globalThis.num = 0;}export const num = ++globalThis.num;

Modules are singletons. 模塊是單例。85d28資訊網——每日最新資訊28at.com

無論從同一位置或不同位置導入模塊多少次,模塊都只會被執行和加載一次。換句話說,模塊實例只有一個。85d28資訊網——每日最新資訊28at.com

測驗 #4:34% 的正確答案

index.mjs

// index.mjsimport './module.mjs?param=5;'

module.mjs

// module.mjsconsole.log(import.meta.url);

這個問題如果沒有對ES6有比較深的理解,就不太好回答出來。85d28資訊網——每日最新資訊28at.com

根據 MDN:85d28資訊網——每日最新資訊28at.com

import.meta 對象為 JavaScript 模塊提供特定于上下文的元數據。它包含有關模塊的信息。85d28資訊網——每日最新資訊28at.com

它返回一個帶有 url 屬性的對象,url 屬性表示模塊的基本 URL。對于外部腳本,url 將是獲取腳本的 URL;對于內嵌腳本,url 將是包含腳本的文檔的基本 URL。85d28資訊網——每日最新資訊28at.com

請注意,這將包括查詢參數和/或哈希值(即,跟在 "?" 或 "#" 之后的部分)。85d28資訊網——每日最新資訊28at.com

測驗 #5:45% 的正確答案

index.js

import myCounter from './counter';myCounter += 1;console.log(myCounter);

counter.js

// counter.jslet counter = 5;export default counter;

另一個大多數開發者容易忽視的非常重要的點是,在導入模塊的作用域中,導入的變量表現得像常量。85d28資訊網——每日最新資訊28at.com

為了使代碼正常工作,我們可以導出一個對象,例如,并更改其屬性。85d28資訊網——每日最新資訊28at.com

測驗 #6:11%的正確答案

// index.mjsimport foo from './module.mjs';console.log(typeof foo);
// module.mjsfoo = 25;export default function foo() {}

首先,這:85d28資訊網——每日最新資訊28at.com

export default function foo() {}

等于:85d28資訊網——每日最新資訊28at.com

function foo() {}export { foo as default }

這也等于:85d28資訊網——每日最新資訊28at.com

function foo() {}export default foo

現在是時候回想起函數是如何被提升的,以及變量的初始化總是在函數/變量聲明之后進行。85d28資訊網——每日最新資訊28at.com

引擎處理完模塊代碼后,看起來是這樣的:85d28資訊網——每日最新資訊28at.com

function foo() {}foo = 25;export { foo as default }

因此,測驗結果就是 number 。85d28資訊網——每日最新資訊28at.com

測驗 #7:17%的正確答案

// index.mjsimport defaultFoo, { foo } from './module.mjs';setTimeout(() => {  console.log(foo);  console.log(defaultFoo);}, 2000);
// module.mjslet foo = 'bar';export { foo };export default foo;setTimeout(() => {  foo = 'baz';}, 1000);

在大多數情況下,導入的數據是實時的。也就是說,如果導出的值發生了變化,這種變化會反映在導入的變量上。85d28資訊網——每日最新資訊28at.com

但默認導出并非如此:85d28資訊網——每日最新資訊28at.com

export default foo;

使用這種語法時,導出的不是變量,而是變量值??梢韵襁@樣導出默認值,而無需使用變量:85d28資訊網——每日最新資訊28at.com

export default ‘hello’;export default 42;

如果查看測驗 #1 中使用導出語法的表格,就會發現 export default function () {} 與 export default foo ( Export of values ) 所處的列 ( Default export ) 不同。85d28資訊網——每日最新資訊28at.com

這是因為它們的行為方式不同,函數仍然作為活引用傳遞:85d28資訊網——每日最新資訊28at.com

// module.mjs  export { foo };  export default function foo() {};  setTimeout(() => {    foo = 'baz';  }, 1000);
// index.mjs  import defaultFoo, { foo } from './module.mjs';  setTimeout(() => {    console.log(foo); // baz    console.log(defaultFoo); //baz  }, 2000);

export { foo as default }; 位于 Named Export 列,與這兩列都不同。但對我們來說,唯一重要的是它不在 Export of values 列中。因此,這意味著當以這種方式導出數據時,它將與導入值進行實時綁定。85d28資訊網——每日最新資訊28at.com

測驗 #8: 40% 的正確答案

// index.mjsimport { shouldLoad } from './module1.mjs';let num = 0;if (shouldLoad) {  import { num } from './module2.mjs';}console.log(num);
// module1.mjsexport const shouldLoad = true;
//module2.mjsexport const num = 1;

import { num } from ‘./module2.mjs’; 行將會出錯,因為導入結構必須位于腳本的頂層:85d28資訊網——每日最新資訊28at.com

SyntaxError: Unexpected token ‘{‘85d28資訊網——每日最新資訊28at.com

這是一個重要的限制,加上在文件路徑中使用變量的限制,使得 ES6 模塊成為靜態模塊。這意味著,與 Node.js 中使用的 Common.js 模塊不同,不必執行代碼就能找出模塊之間的所有依賴關系。85d28資訊網——每日最新資訊28at.com

在這個使用 Common.js 模塊的示例中,要確定將加載 a 或 b 模塊,需要運行以下代碼:85d28資訊網——每日最新資訊28at.com

let result;if (foo()) {    result = require('a');} else {    result = require('b');}

模塊的靜態特性有很多好處。以下是其中一些:85d28資訊網——每日最新資訊28at.com

  • 總是知道導入數據的確切結構。這有助于在執行代碼前發現錯別字。
  • 異步加載。這是因為模塊是靜態的,可以在執行模塊主體之前加載導入。
  • 支持循環依賴關系。我們將在下一次測驗中詳細探討這種可能性。
  • 高效捆綁。在此不多贅述,您可以在本文中自行了解 Rollup 捆綁程序如何有效地構建 ES6 模塊。

測驗 #9: 3% 的正確答案

// index.mjsimport { double, square } from './module.mjs';export function calculate(value) {  return value % 2 ? square(value) : double(value);}
// module.mjsimport { calculate } from './index.mjs';export function double(num) {  return num * 2;}export function square(num) {  return num * num;}console.log(calculate(3));

在上面的代碼中,我們可以看到循環依賴關系: index.mjs 從 module.mjs 導入 double 和 square 函數,而 module.mjs 從 index.mjs 導入 calculation 函數。85d28資訊網——每日最新資訊28at.com

這段代碼之所以能運行,是因為 ES6 模塊本質上非常支持循環依賴關系。例如,如果我們將這段代碼改寫為使用 Common.js 模塊,它將不再工作:85d28資訊網——每日最新資訊28at.com

// index.jsconst helpers = require('./module.js');function calculate(value) {  return value % 2 ? helpers.square(value) : helpers.double(value);}module.exports = {  calculate}
// module.jsconst actions = require('./index.js');function double(num) {  return num * 2;}function square(num) {  return num * num;}console.log(actions.calculate(3)); // TypeError: actions.calculate is not a functionmodule.exports = {  double,  square}
  • index.js 開始加載。
  • 加載在第一行中斷,以加載 module.js :const helpers = require(‘./module.js’)。
  • module.js 開始加載。
  • 在 console.log(actions.calculate(3)); 行中,由于 actions.calculate 未定義,代碼出錯。這是因為 Common.js 同步加載模塊。 index.js 尚未加載,其導出對象目前為空。

如果調用一個帶延遲的導入函數, index.js 模塊將有時間加載,代碼也將相應地工作:85d28資訊網——每日最新資訊28at.com

// module.jsconst actions = require('./index.js');function double(num) {  return num * 2;}function square(num) {  return num * num;}function someFunctionToCallLater() {  console.log(actions.calculate(3)); // Works}module.exports = {  double,  square}

從前面的測驗中了解到的,ES6 模塊支持循環依賴關系,因為它們是靜態的--模塊的依賴關系在代碼執行之前就已加載。85d28資訊網——每日最新資訊28at.com

使上述代碼工作的另一個因素是提升。當調用 calculate 函數時,我們還沒有進入定義該函數的行。85d28資訊網——每日最新資訊28at.com

下面是捆綁模塊后的代碼:85d28資訊網——每日最新資訊28at.com

function double(num) {  return num * 2;}function square(num) {  return num * num;}console.log(calculate(3));function calculate(value) {  return value % 2 ? square(value) : double(value);}

如果沒有變量提升,它將無法工作。85d28資訊網——每日最新資訊28at.com

如果我們將計算聲明函數改為函數表達式:85d28資訊網——每日最新資訊28at.com

export let calculate = function(value) {  return value % 2 ? square(value) : double(value);}

會出現以下錯誤:85d28資訊網——每日最新資訊28at.com

ReferenceError: Cannot access ‘calculate’ before initialization

測驗 #10: 31%的正確答案

// index.mjsimport { num } from './module.mjs';console.log(num);
export let num = 0;num = await new Promise((resolve) => {  setTimeout(() => resolve(1), 1000);});

頂層 await 是一個非常有用的特性,許多開發者都不了解,也許是因為它是在最近的 ECMAScript 2022 中才引入的。啊,真不錯!85d28資訊網——每日最新資訊28at.com

頂層 await 使模塊能夠像大型異步函數一樣運作:通過頂層 await,ECMAScript 模塊(ESM)可以等待資源,導致導入它們的其他模塊在開始評估其主體之前必須等待。85d28資訊網——每日最新資訊28at.com

模塊的標準行為是,在加載模塊導入的所有模塊并執行其代碼之前,模塊中的代碼不會被執行(參見測驗 #2)。事實上,隨著頂級等待的出現,一切都沒有改變。模塊中的代碼不會被執行,直到所有導入模塊中的代碼都被執行,只是現在這包括等待模塊中所有等待的承諾被解決。85d28資訊網——每日最新資訊28at.com

// index.jsconsole.log('index.js');import { num } from './module.js';console.log('num = ', num);
// module.jsexport let num = 5;console.log('module.js');await new Promise((resolve) => {  setTimeout(() => {    console.log('module.js: promise 1');    num = 10;    resolve();  }, 1000);});await new Promise((resolve) => {  setTimeout(() => {    console.log('module.js: promise 2');    num = 20;    resolve();  }, 2000);});

輸出:85d28資訊網——每日最新資訊28at.com

module.jsmodule.js: promise 1module.js: promise 2index.jsnum = 20

如果我們刪除 module.js 中第 5 行和第 13 行的等待,并在文件 index.js 中添加超時,就會像這樣:85d28資訊網——每日最新資訊28at.com

console.log('index.js');import { num } from './module.js';console.log('num = ', num);setTimeout(() => {  console.log('timeout num = ', num);}, 1000);setTimeout(() => {  console.log('timeout num = ', num);}, 2000);

輸出:85d28資訊網——每日最新資訊28at.com

module.jsindex.jsnum = 5module.js: promise 1timeout num = 10module.js: promise 2timeout num = 20

我們將在今后的測驗中再次使用頂級等待功能。85d28資訊網——每日最新資訊28at.com

測驗 #11: 16%的正確答案

//index.mjsimport { shouldLoad } from './module1.mjs';let num = 0;if (shouldLoad) {   ({ num } = import('./module2.mjs'));}console.log(num);
// module1.mjsexport const shouldLoad = true;
//module2.mjsexport const num = 1;

import() 調用(通常稱為動態導入)是一種類似函數的表達式,它允許異步動態加載 ECMAScript 模塊。它允許繞過導入聲明的語法限制,有條件或按需加載模塊。85d28資訊網——每日最新資訊28at.com

該功能在 ES2020 中引入。85d28資訊網——每日最新資訊28at.com

import(module) 返回一個 promise ,該承諾會履行到一個包含模塊所有輸出的對象。由于 import(module) 返回的是一個 promise,為了修正測驗代碼,我們必須在導入調用之前添加 await 關鍵字:85d28資訊網——每日最新資訊28at.com

if (shouldLoad) {   ({ num } = await import('./module2.mjs'));}

在這里,我們再次使用頂層 await,這讓我們想起了這一功能的酷炫之處。85d28資訊網——每日最新資訊28at.com

我敢肯定,你的應用程序至少有一次出錯崩潰了:85d28資訊網——每日最新資訊28at.com

SyntaxError: await is only valid in async functions

當試圖從全局作用域調用異步函數時,經常會出現這種情況。為了解決這個問題,我們必須躲避丑陋的代碼:85d28資訊網——每日最新資訊28at.com

(async () => {  await [someAsyncFunc]();})();

這不僅難看,而且在使用此模式異步加載模塊時可能會導致錯誤。例如85d28資訊網——每日最新資訊28at.com

// module1.mjslet num;(async () => { ({ num } = await import(‘./module2.mjs’));})();export { num };
// module2.mjsexport const num = 5;

導入 module1.mjs 時, num 的結果會是什么 - 來自 module2 或 undefined 的值?這取決于何時訪問變量:85d28資訊網——每日最新資訊28at.com

import { num } from './module1.mjs';console.log(num); // undefinedsetTimeout(() => console.log(num), 100); // 5

有了頂級 await ,只要您訪問從 module1 導入的 num ,它就永遠不會是 undefined :85d28資訊網——每日最新資訊28at.com

let { num } = await import('./module2.mjs');export { num };
import { num } from './module1.mjs';console.log(num); // 5

測驗 #12: 21% 的正確答案

// index.mjsconst module1 = await import('./module1.mjs');const module2 = await import('./module2.mjs');console.log(module1, module2);function multiply(num1, num2) { return num1 * num2; }console.log(multiply(module1, module2));
// module1.mjsexport default await new Promise((resolve) => resolve(1));
// module2.mjsexport default await new Promise((resolve) => resolve(2));

上述代碼會出錯:85d28資訊網——每日最新資訊28at.com

TypeError: Cannot convert object to primitive value85d28資訊網——每日最新資訊28at.com

同意,一個相當意外的錯誤措辭。讓我們來看看這個錯誤從何而來。85d28資訊網——每日最新資訊28at.com

在這段代碼中,我們使用了動態導入,這在前面的示例中已經介紹過。要理解這段代碼中的問題,我們需要仔細看看 import() 的返回值。85d28資訊網——每日最新資訊28at.com

變量 module1 和 module2 的值與我們的預期不同。 import() 返回一個 promise ,該promise  將實現一個與命名空間導入形狀相同的對象:85d28資訊網——每日最新資訊28at.com

import * as name from moduleName

default 輸出可作為名為 default 的鍵使用。85d28資訊網——每日最新資訊28at.com

因此,在變量 module1 和 module2 中分別有對象 { default: 1 } 和 { default: 2 } ,而不是值 1 和 2 。85d28資訊網——每日最新資訊28at.com

那么,為什么兩個對象相乘時會出現如此奇怪的錯誤,而不是我們習慣的 NaN 呢?85d28資訊網——每日最新資訊28at.com

這是因為返回的對象具有 null 原型。因此,它沒有用于將對象轉換為基元的 toString() 方法。如果這個對象有一個 Object 原型,我們就會在控制臺中看到 NaN 。85d28資訊網——每日最新資訊28at.com

要修復測驗代碼,我們需要做以下更改:85d28資訊網——每日最新資訊28at.com

console.log(pow(module1.default, module2.default));

或:85d28資訊網——每日最新資訊28at.com

const { default: module1 } = await import('./module1.mjs');const { default: module2 } = await import('./module2.mjs');

測驗 #13:17%的正確答案

// index.jsimport * as values from './intermediate.js';console.log(values.x);
// module1.jsexport const x = 1;
// module2.jsexport const x = 2;
// intermediate.jsexport * from './module1.js';export * from './module2.js';

export * from ‘module’ 語法會將 "模塊"文件中所有已命名的導出內容重新導出為當前文件中已命名的導出內容。如果存在多個同名導出,則不會重新導出其中任何一個。85d28資訊網——每日最新資訊28at.com

因此,運行這段代碼時,我們會在控制臺中看到 undefined 。只有 17% 的答題者回答正確,大多數答題者(59%)認為這段代碼會出錯。事實上,這種無聲的失敗似乎并不是嚴格模式的典型表現。(如果您知道這種行為的原因,請在評論中告訴我。85d28資訊網——每日最新資訊28at.com

順便提一下,如果在同樣的情況下顯式導入 x ,就會出現預期的錯誤:85d28資訊網——每日最新資訊28at.com

import { x } from ‘./intermediate.js’;
SyntaxError: The requested module ‘./intermediate.js’ contains conflicting star exports for name ‘x’

最后

沖~~~85d28資訊網——每日最新資訊28at.com

85d28資訊網——每日最新資訊28at.com

本文鏈接:http://www.tebozhan.com/showinfo-26-11885-0.html50 種 ES6 模塊,面試被問麻了

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 常用的限流方式-滑動窗口(計數器的改進版)

下一篇: Havoc遠控源碼剖析(協議篇)

標簽:
  • 熱門焦點
Top