這45道面試可能被問到的JS判斷題!你能答對幾道?

語言: CN / TW / HK

小知識,大挑戰!本文正在參與“程序員必備小知識”創作活動。


前言

先想一想再看答案喲~

第1題

輸出是什麼?

```javascript function sayHi() { console.log(name) console.log(age) var name = 'Lydia' let age = 21 }

sayHi() ``` 1. Lydia 和 undefined 2. Lydia 和 ReferenceError 3. ReferenceError 和 21 4. undefined 和 ReferenceError

⏳ 點擊查看答案 > 答案:4 在函數內部,我們首先通過 `var` 關鍵字聲明瞭 `name` 變量。這意味着變量被提升了(內存空間在創建階段就被設置好了),直到程序運行到定義變量位置之前默認值都是 `undefined`。因為當我們打印 `name` 變量時還沒有執行到定義變量的位置,因此變量的值保持為 `undefined`。 通過 `let` 和 `const` 關鍵字聲明的變量也會提升,但是和 `var` 不同,它們**不會被初始化**。在我們聲明(初始化)之前是不能訪問它們的。這個行為被稱之為暫時性死區。當我們試圖在聲明之前訪問它們時,JavaScript 將會拋出一個 `ReferenceError` 錯誤。

第2題

下面那個選項將會返回 '6' ?

javascript function sumValues(x, y, z) { return x + y + z; } 1. sumValues([...1, 2, 3]) 2. sumValues([...[1, 2, 3]]) 3. sumValues(...[1, 2, 3]) 4. sumValues([1, 2, 3])

⏳ 點擊查看答案 > 答案:3 通過展開操作符 `...`,我們可以 _暫開_ 單個可迭代的元素。函數 `sumValues` function 接收三個參數: `x`, `y` 和 `z`。`...[1, 2, 3]` 的執行結果為 `1, 2, 3`,將會傳遞給函數 `sumValues`。

第3題

哪一個方法會返回 'Hello world!' ?

```javascript const myMap = new Map() const myFunc = () => 'greeting'

myMap.set(myFunc, 'Hello world!')

//1 myMap.get('greeting') //2 myMap.get(myFunc) //3 myMap.get(() => 'greeting') ``` 1. 1 2. 2 3. 2 and 3 4. All of them

⏳ 點擊查看答案 > 答案:2 當通過 `set` 方法添加一個鍵值對,一個傳遞給 `set`方法的參數將會是鍵名,第二個參數將會是值。在這個case裏,鍵名為 _函數_ `() => 'greeting'`,值為`'Hello world'`。 `myMap` 現在就是 `{ () => 'greeting' => 'Hello world!' }`。 1 是錯的,因為鍵名不是 `'greeting'` 而是 `() => 'greeting'`。 3 是錯的,因為我們給`get` 方法傳遞了一個新的函數。對象受 _引用_ 影響。函數也是對象,因此兩個函數嚴格上並不等價,儘管他們相同:他們有兩個不同的內存引用地址。

第4題

setInterval 方法的返回值是什麼?

javascript setInterval(() => console.log('Hi'), 1000) 1. 一個唯一的id 2. 該方法指定的毫秒數 3. 傳遞的函數 4. undefined

⏳ 點擊查看答案 > 答案:1 `setInterval` 返回一個唯一的 id。此 id 可被用於 `clearInterval` 函數來取消定時。

第5題

輸出什麼?

```javascript let randomValue = { name: "Lydia" } randomValue = 23

if (!typeof randomValue === "string") { console.log("It's not a string!") } else { console.log("Yay it's a string!") } ``` 1. It's not a string! 2. Yay it's a string! 3. TypeError 4. undefined

⏳ 點擊查看答案 > 答案:2 `if` 語句的條件判斷 `!typeof randomValue` 的值是否等於 `"string"`。 `!` 操作符將這個值轉化為一個布爾值。如果值是truthy的話,返回值會是 `false`,如果值是falsy,返回值會是 `true`。在這裏, `typeof randomValue` 的返回值是一個truthy值 `"number"`,意味着 `!typeof randomValue` 的值是一個布爾值 `false`。 `!typeof randomValue === "string"` 總是返回false,因為我們實際上是在執行 `false === "string"`。因為條件返回的是 `false`,所以 `else` 語句中的代碼塊會被運行,因此打印 `Yay it's a string!` 。

第6題

輸出什麼?

```javascript const createMember = ({ email, address = {}}) => { const validEmail = /.+\@.+..+/.test(email) if (!validEmail) throw new Error("Valid email pls")

return {
    email,
    address: address ? address : null
}

}

const member = createMember({ email: "[email protected]" }) console.log(member) ``` 1. { email: "[email protected]", address: null } 2. { email: "[email protected]" } 3. { email: "[email protected]", address: {} } 4. { email: "[email protected]", address: undefined }

⏳ 點擊查看答案 > 答案:3 `address` 的默認值是一個空對象 `{}`。當我們設置 `member` 變量為 `createMember` 函數返回的對象,我們沒有為address參數傳值,意味着address的值為默認的空對象 `{}`。一個空對象是一個truthy值,意味着 `address ? address : null` 條件會返回 `true`。address的值為空對象 `{}`。

第7題

method 的值選擇哪個時,會輸出 { name: "Lydia", age: 22 } ?

```javascript const keys = ["name", "age"] const values = ["Lydia", 22]

const method = / ?? / Objectmethod // { name: "Lydia", age: 22 } ``` 1. entries 2. values 3. fromEntries 4. forEach

⏳ 點擊查看答案 > 答案:3 `fromEntries` 方法可以將二維數組轉換為對象。在每個子數組的第一個元素是key,在每個子數組的第二個元素是value。在這個例子中,我們映射了 `keys` 數組,它返回了一個數組,數組的第一個元素為keys數組當前索引的值,第二個元素為values數組當前索引的值。 這樣就創建了一個包含正確keys和values的子數組的數組,因此結果為`{ name: "Lydia", age: 22 }`。

第8題

輸出什麼?

```javascript const promise1 = Promise.resolve('First') const promise2 = Promise.resolve('Second') const promise3 = Promise.reject('Third') const promise4 = Promise.resolve('Fourth')

const runPromises = async () => { const res1 = await Promise.all([promise1, promise2]) const res2 = await Promise.all([promise3, promise4]) return [res1, res2] }

runPromises() .then(res => console.log(res)) .catch(err => console.log(err)) ``` 1. [['First', 'Second'], ['Fourth']] 2. [['First', 'Second'], ['Third', 'Fourth']] 3. [['First', 'Second']] 4. 'Third'

⏳ 點擊查看答案 > 答案:4 `Promise.all` 方法可以並行式運行promise。如果其中一個promise失敗了,`Promise.all` 方法會帶上被reject的promise的值_rejects_。在這個例子中, `promise3` 帶着 `"Third"` 值reject。我們在調用 `runPromises` 時在 `runPromises` 函數內部的 `catch` 方法去捕獲任意error從而捕獲到被reject的值。因為 `promise3` 帶着 `"Third"` 被reject,所以只有 `"Third"` 打印。

第9題

輸出什麼?

```javascript const user = { email: "[email protected]", updateEmail: email => { this.email = email } }

user.updateEmail("[email protected]") console.log(user.email) ``` 1. [email protected] 2. [email protected] 3. undefined 4. ReferenceError

⏳ 點擊查看答案 > 答案:1 `updateEmail` 函數是一個箭頭函數,它沒有和 `user` 對象綁定。這就意味着 `this` 關鍵字不會引用到 `user` 對象,但是會引用到全局對象。 `user` 對象內部的 `email` 的值不會更新。當打印 `user.email` 的時候, 原始值 `[email protected]` 被返回。

第10題

輸出什麼?

```javascript const animals = {}; let dog = { emoji: '🐶' } let cat = { emoji: '🐈' }

animals[dog] = { ...dog, name: "Mara" } animals[cat] = { ...cat, name: "Sara" }

console.log(animals[dog]) ``` 1. { emoji: "🐶", name: "Mara" } 2. { emoji: "🐈", name: "Sara" } 3. undefined 4. ReferenceError

⏳ 點擊查看答案 > 答案:2 對象的鍵會被轉換為字符串。 因為 `dog` 的值是一個對象, `animals[dog]` 實際上意味着我們創建了一個叫做 `"object Object"` 的屬性來代表新的對象。 `animals["object Object"]` 現在等於 `{ emoji: "🐶", name: "Mara"}`。 `cat` 也是一個對象,`animals[cat]` 實際上意味着我們在用新的cat的屬性覆蓋 `animals[``"``object Object``"``]` 的值。 打印 `animals[dog]`,實際上是`animals["object Object"]`,這是因為轉化`dog`對象為一個字符串結果 `"object Object"` ,所以返回 `{ emoji: "🐈", name: "Sara" }`。

第11題

輸出什麼?

```javascript const fruit = ['🍌', '🍊', '🍎']

fruit.slice(0, 1) fruit.splice(0, 1) fruit.unshift('🍇')

console.log(fruit) ``` 1. ['🍌', '🍊', '🍎'] 2. ['🍊', '🍎'] 3. ['🍇', '🍊', '🍎'] 4. ['🍇', '🍌', '🍊', '🍎']

⏳ 點擊查看答案 > 答案:3 首先,我們在fruit數組上調用 `slice` 方法。 slice方法不會修改原始數組,但是會返回從數組切片下來的值:香蕉emoji。 其次,我們在fruit數組上調用 `splice` 方法。 splice方法會修改原始數組,也就意味着fruit數組此時為 `['🍊', '🍎']`。 最後,我們在fruit數組上調用 `unshift` 方法,通過添加一個值的方式改變了原始數組,添加的是'🍇',它成為了數組的第一個元素。現在fruit數組的組成為 `['🍇', '🍊', '🍎']`。

第12題

輸出什麼?

```javascript const user = { email: "[email protected]", password: "12345" }

const updateUser = ({ email, password }) => { if (email) { Object.assign(user, { email }) }

if (password) {
    user.password = password
}

return user

}

const updatedUser = updateUser({ email: "[email protected]" })

console.log(updatedUser === user) ``` 1. false 2. true 3. TypeError 4. ReferenceError

⏳ 點擊查看答案 > 答案:2 `updateUser` 函數更新user的 `email` 和 `password` 屬性的值, 如果它們的值傳入函數, 函數返回的就是 `user` 對象。 `updateUser` 函數的返回值是 `user` 對象,意味着updatedUser的值與 `user` 指向的是同一個 `user` 對象。`updatedUser === user` 為 `true`.

第13題

輸出什麼?

```javascript class Calc { constructor() { this.count = 0 }

increase() {
    this.count ++
}

}

const calc = new Calc() new Calc().increase()

console.log(calc.count) ``` 1. 0 2. 1 3. undefined 4. ReferenceError

⏳ 點擊查看答案 > 答案:1 我們設置 `calc` 變量為 `Calc` 類的一個新實例。 然後,我們初始化一個 `Calc` 的新實例,而且調用了這個實例的 `increase` 方法。因為count屬性是在 `Calc` class的constructor內部的,所以count屬性不會在 `Calc` 的原型鏈上共享出去。這就意味着calc實例的count值不會被更新,count仍然是 `0`。

第14題

輸出是什麼?

```javascript function getFruit(fruits) { console.log(fruits?.[1]?.[1]) }

getFruit([['🍊', '🍌'], ['🍍']]) getFruit() getFruit([['🍍'], ['🍊', '🍌']]) ``` 1. null, undefined, 🍌 2. [], null, 🍌 3. [], [], 🍌 4. undefined, undefined, 🍌

⏳ 點擊查看答案 > 答案:4 `?` 允許我們去選擇性地訪問對象內部更深層的嵌套屬性。 我們嘗試打印 `fruits` 數組索引值為 `1` 的子數組內部的索引值為 `1` 的元素。 如果在 `fruits` 數組索引值 為 `1` 的位置不存在元素,會直接返回 `undefined`。 如果 `fruits` 數組在索引值為 `1` 的位置存在元素,但是子數組在索引值為 `1` 的位置不存在元素,也會返回 `undefined`。 首先,我們嘗試打印 `[['🍊', '🍌'], ['🍍']]` 的子數組 `['🍍']` 的第2個元素。這個子數組只包含一個元素,也就意味着在索引值為 `1` 的位置不存在元素,所以返回的是 `undefined` 。 其次,我們在沒有傳入任何參數調用了 `getFruits` 函數,也就意味着形參 `fruits` 的默認值為`undefined`。因為我們選擇性地鏈接了 `fruits` 在索引值為 `1` 的元素,因為在索引值為 `1` 的位置不存在元素,因此返回的是 `undefined` 。 最後,我們嘗試打印 `['🍍'], ['🍊', '🍌']` 的子數組 `['🍊', '🍌']` 的第2個元素。子數組索引值為 `1`的位置為 `🍌` ,因此它被打印出了。

第15題

輸出什麼?

```javascript let count = 0; const nums = [0, 1, 2, 3];

nums.forEach(num => { if (num) count += 1 })

console.log(count) ``` 1. 1 2. 2 3. 3 4. 4

⏳ 點擊查看答案 > 答案:3 在 `forEach` 循環內部的 `if` 會判斷 `num` 的值是truthy或者是falsy。因為 `nums` 數組的第一個數字是 `0`,一個falsy值, `if` 語句代碼塊不會被執行。`count` 僅僅在 `nums` 數組的其他3個數字 `1`,`2`,`3` 時加1。因為 `count` 執行了3次加 `1` 運算,所以 `count` 的值為 `3`。

第16題

向對象 person 添加什麼時,可以通過執行 [...person] 獲得類似 ["Lydia Hallie", 21] 的輸出?

```javascript const person = { name: "Lydia Hallie", age: 21 }

[...person] // ["Lydia Hallie", 21] ``` 1. 不需要,對象默認就是可迭代的 2. Symbol.iterator { for (let x in this) yield this[x] } 3. Symbol.iterator { for (let x in this) yield Object.values(this) } 4. *Symbol.iterator { for (let x in this) yield this }

⏳ 點擊查看答案 > 答案:3 對象默認並不是可迭代的。如果迭代規則被定義,則一個對象是可迭代的(An iterable is an iterable if the iterator protocol is present)。我們可以通過添加迭代器symbol `[Symbol.iterator]` 來定義迭代規則,其返回一個 generator 對象,比如説構建一個 generator 函數 `*[Symbol.iterator]() {}`。如果我們想要返回數組 `["Lydia Hallie", 21]`: `yield* Object.values(this)`,這個 generator 函數一定要 yield 對象 `person` 的`Object.values`。

第17題

哪一個選項會導致報錯?

```javascript const emojis = ["🎄", "🎅🏼", "🎁", "⭐"];

/ 1 / emojis.push("🦌"); / 2 / emojis.splice(0, 2); / 3 / emojis = [...emojis, "🥂"]; / 4 / emojis.length = 0; ``` 1. 1 2. 1 and 2 3. 3 and 4 4. 3

⏳ 點擊查看答案 > 答案:4 `const` 關鍵字意味着我們不能 _重定義_ 變量中的值,它 _僅可讀_。而然,值本身不可修改。數組 `emojis` 中的值可被修改,如 push 新的值, 拼接,又或者將數組的長度設置為0。

第18題

輸出什麼?

```javascript class Bird { constructor() { console.log("I'm a bird. 🦢"); } }

class Flamingo extends Bird { constructor() { console.log("I'm pink. 🌸"); super(); } }

const pet = new Flamingo(); ``` 1. I'm pink. 🌸 2. I'm pink. 🌸 I'm a bird. 🦢 3. I'm a bird. 🦢 I'm pink. 🌸 4. Nothing, we didn't call any method

⏳ 點擊查看答案 > 答案:2 我們創建了類 `Flamingo` 的實例 `pet`。當我們實例化這個實例,`Flamingo` 中的 `constructor` 被調用。首相,輸出 `"I'm pink. 🌸"`, 之後我們調用`super()`。`super()` 調用父類的構造函數,`Bird`。`Bird` 的構造函數被調用,並輸出 `"I'm a bird. 🦢"`。

第19題

輸出什麼?

```javascript const person = { name: "Lydia Hallie", hobbies: ["coding"] };

function addHobby(hobby, hobbies = person.hobbies) { hobbies.push(hobby); return hobbies; }

addHobby("running", []); addHobby("dancing"); addHobby("baking", person.hobbies);

console.log(person.hobbies); ``` 1. ["coding"] 2. ["coding", "dancing"] 3. ["coding", "dancing", "baking"] 4. ["coding", "running", "dancing", "baking"]

⏳ 點擊查看答案 > 答案:3 函數 `addHobby` 接受兩個參數,`hobby` 和有着對象 `person` 中數組 `hobbies` 默認值的 `hobbies`。 首相,我們調用函數 `addHobby`,並給 `hobby` 傳遞 `"running"` 以及給 `hobbies` 傳遞一個空數組。因為我們給 `hobbies` 傳遞了空數組,`"running"` 被添加到這個空數組。 然後,我們調用函數 `addHobby`,並給 `hobby` 傳遞 `"dancing"`。我們不向 `hobbies` 傳遞值,因此它獲取其默認值 —— 對象 `person` 的 屬性 `hobbies`。我們向數組 `person.hobbies` push `dancing`。 最後,我們調用函數 `addHobby`,並向 `hobby` 傳遞 值 `"bdaking"`,並且向 `hobbies` 傳遞 `person.hobbies`。我們向數組 `person.hobbies` push `dancing`。 pushing `dancing` 和 `baking` 之後,`person.hobbies` 的值為 `["coding", "dancing", "baking"]`

第20題

選擇哪一個?

```javascript const teams = [ { name: "Team 1", members: ["Paul", "Lisa"] }, { name: "Team 2", members: ["Laura", "Tim"] } ];

function* getMembers(members) { for (let i = 0; i < members.length; i++) { yield members[i]; } }

function* getTeams(teams) { for (let i = 0; i < teams.length; i++) { // ✨ SOMETHING IS MISSING HERE ✨ } }

const obj = getTeams(teams); obj.next(); // { value: "Paul", done: false } obj.next(); // { value: "Lisa", done: false } ``` 1. yield getMembers(teams[i].members) 2. yield* getMembers(teams[i].members) 3. return getMembers(teams[i].members) 4. return yield getMembers(teams[i].members)

⏳ 點擊查看答案 > 答案:2 為了遍歷 `teams` 數組中對象的屬性 `members` 中的每一項,我們需要將 `teams[i].members` 傳遞給 Generator 函數 `getMembers`。Generator 函數返回一個 generator 對象。為了遍歷這個 generator 對象中的每一項,我們需要使用 `yield*`. 如果我們沒有寫 `yield`,`return yield` 或者 `return`,整個 Generator 函數不會第一時間 return 當我們調用 `next` 方法.

第21題

輸出什麼?

```javascript class Counter { #number = 10

increment() { this.#number++ }

getNum() { return this.#number } }

const counter = new Counter() counter.increment()

console.log(counter.#number) ``` 1. 10 2. 11 3. undefined 4. SyntaxError

⏳ 點擊查看答案 > 答案:4 在 ES2020 中,通過 `#` 我們可以給 class 添加私有變量。在 class 的外部我們無法獲取該值。當我們嘗試輸出 `counter.#number`,語法錯誤被拋出:我們無法在 class `Counter` 外部獲取它!

第22題

輸出什麼?

```javascript const add = x => x + x;

function myFunc(num = 2, value = add(num)) { console.log(num, value); }

myFunc(); myFunc(3); ``` 1. 2 4 and 3 6 2. 2 NaN and 3 NaN 3. 2 Error and 3 6 4. 2 4 and 3 Error

⏳ 點擊查看答案 > 答案:1 首先我們不傳遞任何參數調用 `myFunc()`。因為我們沒有傳遞參數,`num` 和 `value` 獲取它們各自的默認值:num 為 `2`, 而 `value` 為函數 `add` 的返回值。對於函數 `add`,我們傳遞值為2的 `num` 作為參數。函數 `add` 返回 `4` 作為 `value` 的值。 然後,我們調用 `myFunc(3)` 並傳遞值 `3` 參數 `num` 的值。我們沒有給 `value` 傳遞值。因為我們沒有給參數 `value` 傳遞值,它獲取默認值:函數 `add` 的返回值。對於函數 `add`,我們傳遞值為3的 `num`給它。函數 `add` 返回 `6` 作為 `value` 的值。

第23題

以下哪一項會對對象 person 有副作用?

```javascript const person = { name: "Lydia Hallie", address: { street: "100 Main St" } };

Object.freeze(person); ``` 1. person.name = "Evan Bacon" 2. delete person.address 3. person.address.street = "101 Main St" 4. person.pet = { name: "Mara" }

⏳ 點擊查看答案 > 答案:3 使用方法 `Object.freeze` 對一個對象進行 _凍結_。不能對屬性進行添加,修改,刪除。 然而,它僅 對對象進行 _淺_ 凍結,意味着只有 對象中的 _直接_ 屬性被凍結。如果屬性是另一個 object,像案例中的 `address`,`address` 中的屬性沒有被凍結,仍然可以被修改。

第24題

以下哪一項會對對象 person 有副作用?

```javascript const person = { name: "Lydia Hallie" };

Object.seal(person); ``` 1. person.name = "Evan Bacon" 2. person.age = 21 3. delete person.name 4. Object.assign(person, { age: 21 })

⏳ 點擊查看答案 > 答案:1 使用 `Object.seal` 我們可以防止新屬性 _被添加_,或者存在屬性 _被移除_. 然而,你仍然可以對存在屬性進行更改。

第25題

輸出什麼?

```javascript const handler = { set: () => console.log("Added a new property!"), get: () => console.log("Accessed a property!") };

const person = new Proxy({}, handler);

person.name = "Lydia"; person.name; ``` 1. Added a new property! 2. Accessed a property! 3. Added a new property! Accessed a property! 4. 沒有任何輸出

⏳ 點擊查看答案 > 答案:3 使用 Proxy 對象,我們可以給一個對象添加自定義行為。在這個 case,我們傳遞一個包含以下屬性的對象 `handler` : `set` and `get`。每當我們 _設置_ 屬性值時 `set` 被調用,每當我們 _獲取_ 時 `get` 被調用。 第一個參數是一個空對象 `{}`,作為 `person` 的值。對於這個對象,自定義行為被定義在對象 `handler`。如果我們向對象 `person` 添加屬性,`set` 將被調用。如果我們獲取 `person` 的屬性, `get` 將被調用。 首先,我們向 proxy 對象(`person.name = "Lydia"`)添加一個屬性 `name`。`set` 被調用並輸出 `"Added a new property!"`。 然後,我們獲取 proxy 對象的一個屬性,對象 handler 的屬性 `get` 被調用。輸出 `"Accessed a property!"`。

第26題

怎樣能在 index.js 中調用 sum.js 中的 sum 方法?

```javascript // sum.js export default function sum(x) { return x + x; }

// index.js import * as sum from "./sum"; ``` 1. sum(4) 2. sum.sum(4) 3. sum.default(4) 4. 默認導出不用 * 來導入,只能具名導出

⏳ 點擊查看答案 > 答案:3 使用符號 `*`,我們引入文件中的所有值,包括默認和具名。如果我們有以下文件: ```javascript // info.js export const name = "Lydia"; export const age = 21; export default "I love JavaScript"; // index.js import * as info from "./info"; console.log(info); ``` 將會輸出以下內容: ```javascript { default: "I love JavaScript", name: "Lydia", age: 21 } ``` 以 `sum` 為例,相當於以下形式引入值 `sum`: ```javascript { default: function sum(x) { return x + x } } ``` 我們可以通過調用 `sum.default` 來調用該函數

第27題

輸出什麼?

```javascript const myPromise = Promise.resolve(Promise.resolve("Promise!"));

function funcOne() { myPromise.then(res => res).then(res => console.log(res)); setTimeout(() => console.log("Timeout!"), 0); console.log("Last line!"); }

async function funcTwo() { const res = await myPromise; console.log(await res); setTimeout(() => console.log("Timeout!"), 0); console.log("Last line!"); }

funcOne(); funcTwo(); ``` 1. Promise! Last line! Promise! Last line! Last line! Promise! 2. Last line! Timeout! Promise! Last line! Timeout! Promise! 3. Promise! Last line! Last line! Promise! Timeout! Timeout! 4. Last line! Promise! Promise! Last line! Timeout! Timeout!

⏳ 點擊查看答案 > 答案:4 首先,我們調用 `funcOne`。在函數 `funcOne` 的第一行,我們調用`myPromise` promise _異步操作_。當JS引擎在忙於執行 promise,它繼續執行函數 `funcOne`。下一行 _異步操作_ `setTimeout`,其回調函數被 Web API 調用。 (詳情請參考我關於event loop的文章.) promise 和 timeout 都是異步操作,函數繼續執行當JS引擎忙於執行promise 和 處理 `setTimeout` 的回調。相當於 `Last line!` 首先被輸出, 因為它不是異步操作。執行完 `funcOne` 的最後一行,promise 狀態轉變為 resolved,`Promise!` 被打印。然而,因為我們調用了 `funcTwo()`, 調用棧不為空,`setTimeout` 的回調仍不能入棧。 我們現在處於 `funcTwo`,先 _awaiting_ myPromise。通過 `await` 關鍵字, 我們暫停了函數的執行直到 promise 狀態變為 resolved (或 rejected)。然後,我們輸出 `res` 的 awaited 值(因為 promise 本身返回一個 promise)。 接着輸出 `Promise!`。 下一行就是 _異步操作_ `setTimeout`,其回調函數被 Web API 調用。 我們執行到函數 `funcTwo` 的最後一行,輸出 `Last line!`。現在,因為 `funcTwo` 出棧,調用棧為空。在事件隊列中等待的回調函數(`() => console.log("Timeout!")` from `funcOne`, and `() => console.log("Timeout!")` from `funcTwo`)以此入棧。第一個回調輸出 `Timeout!`,並出棧。然後,第二個回調輸出 `Timeout!`,並出棧。得到結果 `Last line! Promise! Promise! Last line! Timeout! Timeout!`

第28題

輸出什麼?

```javascript class Counter { constructor() { this.count = 0; }

increment() {
    this.count++;
}

}

const counterOne = new Counter(); counterOne.increment(); counterOne.increment();

const counterTwo = counterOne; counterTwo.increment();

console.log(counterOne.count); ``` 1. 0 2. 1 3. 2 4. 3

⏳ 點擊查看答案 > 答案:4 `counterOne` 是類 `Counter` 的一個實例。類 Counter 包含一個`count` 屬性在它的構造函數裏, 和一個 `increment` 方法。首先,我們通過 `counterOne.increment()` 調用方法 `increment` 兩次。現在, `counterOne.count` 為 `2`. 然後,我們創建一個新的變量 `counterTwo` 並將 `counterOne` 的引用地址賦值給它。因為對象受引用地址的影響,我們剛剛創建了一個新的對象,其引用地址和 `counterOne` 的等價。因此它們指向同一塊內存地址,任何對其的副作用都會影響 `counterTwo`。現在 `counterTwo.count` 為 `2`。 我們調用 `counterTwo.increment()` 將 `count` 的值設為 `3`。然後,我們打印 `counterOne` 裏的count,結果為 `3`。

第29題

輸出什麼?

```javascript const emojis = ["🥑", ["✨", "✨", ["🍕", "🍕"]]];

console.log(emojis.flat(1)); ``` 1. ['🥑', ['✨', '✨', ['🍕', '🍕']]] 2. ['🥑', '✨', '✨', ['🍕', '🍕']] 3. ['🥑', ['✨', '✨', '🍕', '🍕']] 4. ['🥑', '✨', '✨', '🍕', '🍕']

⏳ 點擊查看答案 > 答案:2 通過方法 `flat`, 我們可以創建一個新的, 已被扁平化的數組。被扁平化的深度取決於我們傳遞的值。在這個case裏,我們傳遞了值 `1` (並不必要,這是默認值),相當於只有第一層的數組才會被連接。即這個 case 裏的 `['🥑']` and `['✨', '✨', ['🍕', '🍕']]`。連接這兩個數組得到結果 `['🥑', '✨', '✨', ['🍕', '🍕']]`.

第30題

輸出什麼?

```javascript const myPromise = Promise.resolve("Woah some cool data");

(async () => { try { console.log(await myPromise); } catch { throw new Error(Oops didn't work); } finally { console.log("Oh finally!"); } })(); ``` 1. Woah some cool data 2. Oh finally! 3. Woah some cool data Oh finally! 4. Oops didn't work Oh finally!

⏳ 點擊查看答案 > 答案:3 在 `try` 塊區,我們打印 `myPromise` 變量的 awaited 值: `"Woah some cool data"`。因為`try` 塊區沒有錯誤拋出,`catch` 塊區的代碼並不執行。`finally` 塊區的代碼 _總是_ 執行,`"Oh finally!"` 被輸出。

第31題

輸出什麼?

```javascript const randomValue = 21;

function getInfo() { console.log(typeof randomValue); const randomValue = "Lydia Hallie"; }

getInfo(); ``` 1. "number" 2. "string" 3. undefined 4. ReferenceError

⏳ 點擊查看答案 > 答案:4 通過 `const` 關鍵字聲明的變量在被初始化之前不可被引用:這被稱之為 _暫時性死區_。在函數 `getInfo` 中, 變量 `randomValue` 聲明在`getInfo` 的作用域的此法環境中。在想要對 `typeof randomValue` 進行log之前,變量 `randomValue` 仍未被初始化: 錯誤`ReferenceError` 被拋出! JS引擎並不會根據作用域鏈網上尋找該變量,因為我們已經在 `getInfo` 函數中聲明瞭 `randomValue` 變量。

第32題

輸出什麼?

```javascript const name = "Lydia Hallie"; const age = 21;

console.log(Number.isNaN(name)); console.log(Number.isNaN(age));

console.log(isNaN(name)); console.log(isNaN(age)); ``` 1. true false true false 2. true false false false 3. false false true false 4. false true false true

⏳ 點擊查看答案 > 答案:3 通過方法 `Number.isNaN`,你可以檢測你傳遞的值是否為 _數字值_ 並且是否等價於 `NaN`。`name` 不是一個數字值,因此 `Number.isNaN(name)` 返回 `false`。`age` 是一個數字值,但它不等價於 `NaN`,因此 `Number.isNaN(age)` 返回 `false`. 通過方法 `isNaN`, 你可以檢測你傳遞的值是否一個 number。`name` 不是一個 `number`,因此 `isNaN(name)` 返回 `true`. `age` 是一個 `number` 因此 `isNaN(age)` 返回 `false`.

第33題

輸出什麼?

```javascript const spookyItems = ["👻", "🎃", "🕸"]; ({ item: spookyItems[3] } = { item: "💀" });

console.log(spookyItems); ``` 1. ["👻", "🎃", "🕸"] 2. ["👻", "🎃", "🕸", "💀"] 3. ["👻", "🎃", "🕸", { item: "💀" }] 4. ["👻", "🎃", "🕸", "[object Object]"]

⏳ 點擊查看答案 > 答案:2 通過解構對象們,我們可以從右手邊的對象中拆出值,並且將拆出的值分配給左手邊對象同名的屬性。在這種情況下,我們將值 "💀" 分配給 `spookyItems[3]`。相當於我們正在篡改數組 `spookyItems`,我們給它添加了值 "💀"。當輸出 `spookyItems` 時,結果為 `["👻", "🎃", "🕸", "💀"]`。

第34題

輸出什麼?

```javascript function getFine(speed, amount) { const formattedSpeed = new Intl.NumberFormat({ 'en-US', { style: 'unit', unit: 'mile-per-hour' } }).format(speed)

const formattedAmount = new Intl.NumberFormat({ 'en-US', { style: 'currency', currency: 'USD' } }).format(amount)

return The driver drove ${formattedSpeed} and has to pay ${formattedAmount} }

console.log(getFine(130, 300)) ``` 1. The driver drove 130 and has to pay 300 2. The driver drove 130 mph and has to pay \$300.00 3. The driver drove undefined and has to pay undefined 4. The driver drove 130.00 and has to pay 300.00

⏳ 點擊查看答案 > 答案:2 通過方法 `Intl.NumberFormat`,我們可以格式化任意區域的數字值。我們對數字值 `130` 進行 `mile-per-hour` 作為 `unit` 的 `en-US` 區域 格式化,結果為 `130 mph`。對數字值 `300` 進行 `USD` 作為 `currentcy` 的 `en-US` 區域格式化,結果為 `$300.00`.

第35題

輸出什麼?

```javascript const myFunc = ({ x, y, z }) => { console.log(x, y, z); };

myFunc(1, 2, 3); ``` 1. 1 2 3 2. {1: 1} {2: 2} {3: 3} 3. { 1: undefined } undefined undefined 4. undefined undefined undefined

⏳ 點擊查看答案 > 答案:4 `myFunc` 期望接收一個包含 `x`, `y` 和 `z` 屬性的對象作為它的參數。因為我們僅僅傳遞三個單獨的數字值 (1, 2, 3) 而不是一個含有 `x`, `y` 和 `z` 屬性的對象 ({x: 1, y: 2, z: 3}), `x`, `y` 和 `z` 有着各自的默認值 `undefined`.

第36題

輸出什麼?

```javascript async function* range(start, end) { for (let i = start; i <= end; i++) { yield Promise.resolve(i); } }

(async () => { const gen = range(1, 3); for await (const item of gen) { console.log(item); } })(); ``` 1. Promise {1} Promise {2} Promise {3} 2. Promise {} Promise {} Promise {} 3. 1 2 3 4. undefined undefined undefined

⏳ 點擊查看答案 > 答案:3 我們給 函數range 傳遞: `Promise{1}`, `Promise{2}`, `Promise{3}`,Generator 函數 `range` 返回一個全是 async object promise 數組。我們將 async object 賦值給變量 `gen`,之後我們使用`for await ... of` 進行循環遍歷。我們將返回的 Promise 實例賦值給 `item`: 第一個返回 `Promise{1}`, 第二個返回 `Promise{2}`,之後是 `Promise{3}`。因為我們正 _awaiting_ `item` 的值,resolved 狀態的 promsie,promise數組的resolved _值_ 以此為: `1`,`2`,`3`.

第37題

輸出什麼?

```javascript const add = x => y => z => { console.log(x, y, z); return x + y + z; };

add(4)(5)(6); ``` 1. 4 5 6 2. 6 5 4 3. 4 function function 4. undefined undefined 6

⏳ 點擊查看答案 > 答案:1 函數 `add` 是一個返回 返回箭頭函數的箭頭函數 的箭頭函數(still with me?)。第一個函數接收一個值為 `4` 的參數 `x`。我們調用第二個函數,它接收一個值為 `5` 的參數 `y`。然後我們調用第三個函數,它接收一個值為 `6` 的參數 `z`。當我們嘗試在最後一個箭頭函數中獲取 `x`, `y` 和 `z` 的值,JS 引擎根據作用域鏈去找 `x` 和 `y` 的值。得到 `4` `5` `6`.

第38題

輸出什麼?

```javascript const name = "Lydia Hallie";

console.log(!typeof name === "object"); console.log(!typeof name === "string"); ``` 1. false true 2. true false 3. false false 4. true true

⏳ 點擊查看答案 > 答案:3 `typeof name` 返回 `"string"`。字符串 `"string"` 是一個 truthy 的值,因此 `!typeof name` 返回一個布爾值 `false`。 `false === "object"` 和 `false === "string"` 都返回 `false`。 (如果我們想檢測一個值的類型,我們應該用 `!==` 而不是 `!typeof`)

第39題

輸出什麼?

```javascript const config = { languages: [], set language(lang) { return this.languages.push(lang); } };

console.log(config.language); ``` 1. function language(lang) { this.languages.push(lang } 2. 0 3. [] 4. undefined

⏳ 點擊查看答案 > 答案:4 方法 `language` 是一個 `setter`。Setters 並不保存一個實際值,它們的使命在於 _修改_ 屬性。當調用方法 `setter`, 返回 `undefined`。

第40題

輸出什麼?

```javascript const groceries = ["banana", "apple", "peanuts"];

if (groceries.indexOf("banana")) { console.log("We have to buy bananas!"); } else { console.log(We don't have to buy bananas!); } ``` 1. We have to buy bananas! 2. We don't have to buy bananas 3. undefined 4. 1

⏳ 點擊查看答案 > 答案:2 我們傳遞了一個狀態 `groceries.indexOf("banana")` 給if條件語句。`groceries.indexOf("banana")` 返回 `0`, 一個 falsy 的值。因為if條件語句的狀態為 falsy,`else` 塊區內的代碼執行,並且 `We don't have to buy bananas!` 被輸出.

第41題

輸出什麼?

``javascript const person = { firstName: "Lydia", lastName: "Hallie", pet: { name: "Mara", breed: "Dutch Tulip Hound" }, getFullName() { return${this.firstName} ${this.lastName}`; } };

console.log(person.pet?.name); console.log(person.pet?.family?.name); console.log(person.getFullName?.()); console.log(member.getLastName?.()); ``` 1. undefined undefined undefined undefined 2. Mara undefined Lydia Hallie undefined 3. Mara null Lydia Hallie null 4. null ReferenceError null ReferenceError

⏳ 點擊查看答案 > 答案:2 通過 ES10 或 TS3.7+[可選鏈操作符 `?.`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/%E5%8F%AF%E9%80%89%E9%93%BE),我們不再需要顯式檢測更深層的嵌套值是否有效。如果我們嘗試獲取 `undefined` 或 `null` 的值 (_nullish_),表達將會短路並返回 `undefined`. `person.pet?.name`: `person` 有一個名為 `pet` 的屬性: `person.pet` 不是 nullish。它有個名為 `name` 的屬性,並返回字符串 `Mara`。 `person.pet?.family?.name`: `person` 有一個名為 `pet` 的屬性: `person.pet` 不是 nullish. `pet` _並沒有_ 一個名為 `family` 的屬性, `person.pet.family` 是 nullish。表達式返回 `undefined`。 `person.getFullName?.()`: `person` 有一個名為 `getFullName` 的屬性: `person.getFullName()` 不是 nullish 並可以被調用,返回字符串 `Lydia Hallie`。 `member.getLastName?.()`: `member` is not defined: `member.getLastName()` is nullish. The expression returns `undefined`.

第42題

輸出什麼?

```javascript let num = 1; const list = ["🥳", "🤠", "🥰", "🤪"];

console.log(list[(num += 1)]); ``` 1. 🤠 2. 🥰 3. SyntaxError 4. ReferenceError

⏳ 點擊查看答案 > 答案:2 通過 `+=` 操作符,我們對值 `num` 進行加 `1` 操作。 `num` 有初始值 `1`,因此 `1 + 1` 的執行結果為 `2`。數組 `list` 的第二項為 🥰,`console.log(list[2])` 輸出 🥰.

第43題

輸出什麼?

```javascript const person = { name: "Lydia", age: 21 }

const changeAge = (x = { ...person }) => x.age += 1 const changeAgeAndName = (x = { ...person }) => { x.age += 1 x.name = "Sarah" }

changeAge(person) changeAgeAndName()

console.log(person) ``` 1. {name: "Sarah", age: 22} 2. {name: "Sarah", age: 23} 3. {name: "Lydia", age: 22} 4. {name: "Lydia", age: 23}

⏳ 點擊查看答案 > 答案:3 函數 `changeAge` 和函數 `changeAgeAndName` 有着不同的參數,定義一個 _新_ 生成的對象 `{ ...person }`。這個對象有着所有 `person` 對象 中 k/v 值的副本。 首項, 我們調用 `changeAge` 函數並傳遞 `person` 對象作為它的參數。這個函數對 `age` 屬性進行加一操作。`person` 現在是 `{ name: "Lydia", age: 22 }`。 然後,我們調用函數 `changeAgeAndName` ,然而我們沒有傳遞參數。取而代之,`x` 的值等價 _new_ 生成的對象: `{ ...person }`。因為它是一個新生成的對象,它並不會對對象 `person` 造成任何副作用。`person` 仍然等價於 `{ name: "Lydia", age: 22 }`。

第44題

將會發生什麼?

```javascript let config = { alert: setInterval(() => { console.log('Alert!') }, 1000) }

config = null ``` 1. setInterval 的回調不會被調用 2. setInterval 的回調被調用一次 3. setInterval 的回調仍然會被每秒鐘調用 4. 我們從沒調用過 config.alert(), config 為 null

⏳ 點擊查看答案 > 答案:3 一般情況下當我們將對象賦值為 `null`, 那些對象會被進行 _垃圾回收(garbage collected)_ 因為已經沒有對這些對象的引用了。然而,`setInterval`的參數是一個箭頭函數(所以上下文綁定到對象 `config` 了),回調函數仍然保留着對 `config`的引用。只要存在引用,對象就不會被垃圾回收。因為沒有被垃圾回收,`setInterval` 的回調每1000ms (1s)會被調用一次。

第45題

輸出什麼?

javascript console.log(`${(x => x)('I love')} to program`) 1. I love to program 2. undefined to program 3. ${(x => x)('I love') to program 4. TypeError

⏳ 點擊查看答案 > 答案:1 帶有模板字面量的表達式首先被執行。相當於字符串會包含表達式,這個立即執行函數 `(x => x)('I love')` 返回的值. 我們向箭頭函數 `x => x` 傳遞 `'I love'` 作為參數。`x` 等價於返回的 `'I love'`。這就是結果 `I love to program`。

結語

這篇文章來自一個試驗...也想驗證一些東西,侵刪~