【轉載】JavaScript進階問題列表

https://github.com/lydiahallie/javascript-questions/blob/master/zh-CN/README-zh_CN.md

fork了一篇js選擇題,很多題都感覺醍醐灌頂,覺得講的特別好,上邊是原文鏈接

JavaScript 進階問題列表

我在我的 Instagram 上每天都會發布 JavaScript 的多選問題,並且同時也會在這個倉庫中發佈。

從基礎到進階,測試你有多瞭解 JavaScript,刷新你的知識,或者幫助你的 coding 面試!
💪 🚀 我每週都會在這個倉庫下更新新的問題。

答案在問題下方的摺疊部分,點擊即可展開問題。祝你好運 ❤️


1. 輸出是什麼?
function sayHi() {
  console.log(name)
  console.log(age)
  var name = 'Lydia'
  let age = 21
}

sayHi()
  • A: Lydiaundefined
  • B: LydiaReferenceError
  • C: ReferenceError21
  • D: undefinedReferenceError
答案

#### 答案: D 在函數內部,我們首先通過 `var` 關鍵字聲明瞭 `name` 變量。這意味着變量被提升了(內存空間在創建階段就被設置好了),直到程序運行到定義變量位置之前默認值都是 `undefined`。因爲當我們打印 `name` 變量時還沒有執行到定義變量的位置,因此變量的值保持爲 `undefined`。

通過 letconst 關鍵字聲明的變量也會提升,但是和 var 不同,它們不會被初始化。在我們聲明(初始化)之前是不能訪問它們的。這個行爲被稱之爲暫時性死區。當我們試圖在聲明之前訪問它們時,JavaScript 將會拋出一個 ReferenceError 錯誤。


2. 輸出是什麼?
for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 1)
}

for (let i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 1)
}
  • A: 0 1 20 1 2
  • B: 0 1 23 3 3
  • C: 3 3 30 1 2
答案

答案: C

由於 JavaScript 的事件循環,setTimeout 回調會在遍歷結束後才執行。因爲在第一個遍歷中遍歷 i 是通過 var 關鍵字聲明的,所以這個值是全局作用域下的。在遍歷過程中,我們通過一元操作符 ++ 來每次遞增 i 的值。當 setTimeout 回調執行的時候,i 的值等於 3。

在第二個遍歷中,遍歷 i 是通過 let 關鍵字聲明的:通過 letconst 關鍵字聲明的變量是擁有塊級作用域(指的是任何在 {} 中的內容)。在每次的遍歷過程中,i 都有一個新值,並且每個值都在循環內的作用域中。


3. 輸出是什麼?
const shape = {
  radius: 10,
  diameter() {
    return this.radius * 2
  },
  perimeter: () => 2 * Math.PI * this.radius
}

shape.diameter()
shape.perimeter()
  • A: 20 and 62.83185307179586
  • B: 20 and NaN
  • C: 20 and 63
  • D: NaN and 63
答案

答案: B

注意 diameter 的值是一個常規函數,但是 perimeter 的值是一個箭頭函數。

對於箭頭函數,this 關鍵字指向的是它當前周圍作用域(簡單來說是包含箭頭函數的常規函數,如果沒有常規函數的話就是全局對象),這個行爲和常規函數不同。這意味着當我們調用 perimeter 時,this 不是指向 shape 對象,而是它的周圍作用域(在例子中是 window)。

window 中沒有 radius 這個屬性,因此返回 undefined


4. 輸出是什麼?
+true;
!"Lydia";
  • A: 1 and false
  • B: false and NaN
  • C: false and false
答案

答案: A

一元操作符加號嘗試將 bool 轉爲 number。true 轉換爲 number 的話爲 1false0

字符串 'Lydia' 是一個真值,真值取反那麼就返回 false


5. 哪一個是正確的?
const bird = {
  size: 'small'
}

const mouse = {
  name: 'Mickey',
  small: true
}
  • A: mouse.bird.size是無效的
  • B: mouse[bird.size]是無效的
  • C: mouse[bird["size"]]是無效的
  • D: 以上三個選項都是有效的
答案

答案: A

在 JavaScript 中,所有對象的 keys 都是字符串(除非對象是 Symbol)。儘管我們可能不會定義它們爲字符串,但它們在底層總會被轉換爲字符串。

當我們使用括號語法時([]),JavaScript 會解釋(或者 unboxes)語句。它首先看到第一個開始括號 [ 並繼續前進直到找到結束括號 ]。只有這樣,它纔會計算語句的值。

mouse[bird.size]:首先計算 bird.size,這會得到 smallmouse["small"] 返回 true

然後使用點語法的話,上面這一切都不會發生。mouse 沒有 bird 這個 key,這也就意味着 mouse.birdundefined。然後當我們使用點語法 mouse.bird.size 時,因爲 mouse.birdundefined,這也就變成了 undefined.size。這個行爲是無效的,並且會拋出一個錯誤類似 Cannot read property "size" of undefined


6. 輸出是什麼?
let c = { greeting: 'Hey!' }
let d

d = c
c.greeting = 'Hello'
console.log(d.greeting)
  • A: Hello
  • B: undefined
  • C: ReferenceError
  • D: TypeError
答案

答案: A

在 JavaScript 中,當設置兩個對象彼此相等時,它們會通過引用進行交互。

首先,變量 c 的值是一個對象。接下來,我們給 d 分配了一個和 c 對象相同的引用。

因此當我們改變其中一個對象時,其實是改變了所有的對象。


7. 輸出是什麼?
let a = 3
let b = new Number(3)
let c = 3

console.log(a == b)
console.log(a === b)
console.log(b === c)
  • A: true false true
  • B: false false true
  • C: true false false
  • D: false true true
答案

答案: C

new Number() 是一個內建的函數構造器。雖然它看着像是一個 number,但它實際上並不是一個真實的 number:它有一堆額外的功能並且它是一個對象。

當我們使用 == 操作符時,它只會檢查兩者是否擁有相同的。因爲它們的值都是 3,因此返回 true

然後,當我們使用 === 操作符時,兩者的值以及類型都應該是相同的。new Number() 是一個對象而不是 number,因此返回 false


8. 輸出是什麼?
class Chameleon {
  static colorChange(newColor) {
    this.newColor = newColor
    return this.newColor
  }

  constructor({ newColor = 'green' } = {}) {
    this.newColor = newColor
  }
}

const freddie = new Chameleon({ newColor: 'purple' })
freddie.colorChange('orange')
  • A: orange
  • B: purple
  • C: green
  • D: TypeError
答案

答案: D

colorChange 是一個靜態方法。靜態方法被設計爲只能被創建它們的構造器使用(也就是 Chameleon),並且不能傳遞給實例。因爲 freddie 是一個實例,靜態方法不能被實例使用,因此拋出了 TypeError 錯誤。


9. 輸出是什麼?
let greeting
greetign = {} // Typo!
console.log(greetign)
  • A: {}
  • B: ReferenceError: greetign is not defined
  • C: undefined
答案

答案: A

代碼打印出了一個對象,這是因爲我們在全局對象上創建了一個空對象!當我們將 greeting 寫錯成 greetign 時,JS 解釋器實際在上瀏覽器中將它視爲 global.greetign = {} (或者 window.greetign = {})。

爲了避免這個爲題,我們可以使用 `“use strict”。這能確保當你聲明變量時必須賦值。


10. 當我們這麼做時,會發生什麼?
function bark() {
  console.log('Woof!')
}

bark.animal = 'dog'
  • A: 正常運行!
  • B: SyntaxError. 你不能通過這種方式給函數增加屬性。
  • C: undefined
  • D: ReferenceError
答案

答案: A

這在 JavaScript 中是可以的,因爲函數是對象!(除了基本類型之外其他都是對象)

函數是一個特殊的對象。你寫的這個代碼其實不是一個實際的函數。函數是一個擁有屬性的對象,並且屬性也可被調用。


11. 輸出是什麼?
function Person(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
}

const member = new Person("Lydia", "Hallie");
Person.getFullName = function () {
  return `${this.firstName} ${this.lastName}`;
}

console.log(member.getFullName());
  • A: TypeError
  • B: SyntaxError
  • C: Lydia Hallie
  • D: undefined undefined
答案

答案: A

你不能像常規對象那樣,給構造函數添加屬性。如果你想一次性給所有實例添加特性,你應該使用原型。因此本例中,使用如下方式:

Person.prototype.getFullName = function () {
  return `${this.firstName} ${this.lastName}`;
}

這纔會使 member.getFullName() 起作用。爲什麼這麼做有益的?假設我們將這個方法添加到構造函數本身裏。也許不是每個 Person 實例都需要這個方法。這將浪費大量內存空間,因爲它們仍然具有該屬性,這將佔用每個實例的內存空間。相反,如果我們只將它添加到原型中,那麼它只存在於內存中的一個位置,但是所有實例都可以訪問它!


12. 輸出是什麼?
function Person(firstName, lastName) {
  this.firstName = firstName
  this.lastName = lastName
}

const lydia = new Person('Lydia', 'Hallie')
const sarah = Person('Sarah', 'Smith')

console.log(lydia)
console.log(sarah)
  • A: Person {firstName: "Lydia", lastName: "Hallie"} and undefined
  • B: Person {firstName: "Lydia", lastName: "Hallie"} and Person {firstName: "Sarah", lastName: "Smith"}
  • C: Person {firstName: "Lydia", lastName: "Hallie"} and {}
  • D:Person {firstName: "Lydia", lastName: "Hallie"} and ReferenceError
答案

答案: A

對於 sarah,我們沒有使用 new 關鍵字。當使用 new 時,this 引用我們創建的空對象。當未使用 new 時,this 引用的是全局對象(global object)。

我們說 this.firstName 等於 "Sarah",並且 this.lastName 等於 "Smith"。實際上我們做的是,定義了 global.firstName = 'Sarah'global.lastName = 'Smith'。而 sarah 本身是 undefined


13. 事件傳播的三個階段是什麼?
  • A: Target > Capturing > Bubbling
  • B: Bubbling > Target > Capturing
  • C: Target > Bubbling > Capturing
  • D: Capturing > Target > Bubbling
答案

答案: D

捕獲(capturing)階段中,事件從祖先元素向下傳播到目標元素。當事件達到目標(target)元素後,冒泡(bubbling)纔開始。


14. 所有對象都有原型。
  • A: 對
  • B: 錯
答案

答案: B

除了基本對象(base object),所有對象都有原型。基本對象可以訪問一些方法和屬性,比如 .toString。這就是爲什麼你可以使用內置的 JavaScript 方法!所有這些方法在原型上都是可用的。雖然 JavaScript 不能直接在對象上找到這些方法,但 JavaScript 會沿着原型鏈找到它們,以便於你使用。


15. 輸出是什麼?
function sum(a, b) {
  return a + b
}

sum(1, '2')
  • A: NaN
  • B: TypeError
  • C: "12"
  • D: 3
答案

答案: C

JavaScript 是一種動態類型語言:我們不指定某些變量的類型。值可以在你不知道的情況下自動轉換成另一種類型,這種類型稱爲隱式類型轉換(implicit type coercion)。Coercion 是指將一種類型轉換爲另一種類型。

在本例中,JavaScript 將數字 1 轉換爲字符串,以便函數有意義並返回一個值。在數字類型(1)和字符串類型('2')相加時,該數字被視爲字符串。我們可以連接字符串,比如 "Hello" + "World",這裏發生的是 "1" + "2",它返回 "12"


16. 輸出是什麼?
let number = 0
console.log(number++)
console.log(++number)
console.log(number)
  • A: 1 1 2
  • B: 1 2 2
  • C: 0 2 2
  • D: 0 1 2
答案

答案: C

一元後自增運算符 ++

  1. 返回值(返回 0
  2. 值自增(number 現在是 1

一元前自增運算符 ++

  1. 值自增(number 現在是 2
  2. 返回值(返回 2

結果是 0 2 2.


17. 輸出是什麼?
function getPersonInfo(one, two, three) {
  console.log(one)
  console.log(two)
  console.log(three)
}

const person = 'Lydia'
const age = 21

getPersonInfo`${person} is ${age} years old`
  • A: "Lydia" 21 ["", " is ", " years old"]
  • B: ["", " is ", " years old"] "Lydia" 21
  • C: "Lydia" ["", " is ", " years old"] 21
答案

答案: B

如果使用標記模板字面量,第一個參數的值總是包含字符串的數組。其餘的參數獲取的是傳遞的表達式的值!


18. 輸出是什麼?
function checkAge(data) {
  if (data === { age: 18 }) {
    console.log('You are an adult!')
  } else if (data == { age: 18 }) {
    console.log('You are still an adult.')
  } else {
    console.log(`Hmm.. You don't have an age I guess`)
  }
}

checkAge({ age: 18 })
  • A: You are an adult!
  • B: You are still an adult.
  • C: Hmm.. You don't have an age I guess
答案

答案: C

在測試相等性時,基本類型通過它們的值(value)進行比較,而對象通過它們的引用(reference)進行比較。JavaScript 檢查對象是否具有對內存中相同位置的引用。

題目中我們正在比較的兩個對象不是同一個引用:作爲參數傳遞的對象引用的內存位置,與用於判斷相等的對象所引用的內存位置並不同。

這也是 { age: 18 } === { age: 18 }{ age: 18 } == { age: 18 } 都返回 false 的原因。


19. 輸出是什麼?
function getAge(...args) {
  console.log(typeof args)
}

getAge(21)
  • A: "number"
  • B: "array"
  • C: "object"
  • D: "NaN"
答案

答案: C

擴展運算符(...args)會返回實參組成的數組。而數組是對象,因此 typeof args 返回 "object"


20. 輸出是什麼?
function getAge() {
  'use strict'
  age = 21
  console.log(age)
}

getAge()
  • A: 21
  • B: undefined
  • C: ReferenceError
  • D: TypeError
答案

答案: C

使用 "use strict",你可以確保不會意外地聲明全局變量。我們從來沒有聲明變量 age,因爲我們使用 "use strict",它將拋出一個引用錯誤。如果我們不使用 "use strict",它就會工作,因爲屬性 age 會被添加到全局對象中了。


21. 輸出是什麼?
const sum = eval('10*10+5')
  • A: 105
  • B: "105"
  • C: TypeError
  • D: "10*10+5"
答案

答案: A

代碼以字符串形式傳遞進來,eval 對其求值。如果它是一個表達式,就像本例中那樣,它對表達式求值。表達式是 10 * 10 + 5。這將返回數字 105


22. cool_secret 可訪問多長時間?
sessionStorage.setItem('cool_secret', 123)
  • A: 永遠,數據不會丟失。
  • B: 當用戶關掉標籤頁時。
  • C: 當用戶關掉整個瀏覽器,而不只是關掉標籤頁。
  • D: 當用戶關閉電腦時。
答案

答案: B

關閉 tab 標籤頁 後,sessionStorage 存儲的數據纔會刪除。

如果使用 localStorage,那麼數據將永遠在那裏,除非調用了 localStorage.clear()


23. 輸出是什麼?
var num = 8
var num = 10

console.log(num)
  • A: 8
  • B: 10
  • C: SyntaxError
  • D: ReferenceError
答案

答案: B

使用 var 關鍵字,你可以用相同的名稱聲明多個變量。然後變量將保存最新的值。

你不能使用 letconst 來實現這一點,因爲它們是塊作用域的。


24. 輸出是什麼?
const obj = { 1: 'a', 2: 'b', 3: 'c' }
const set = new Set([1, 2, 3, 4, 5])

obj.hasOwnProperty('1')
obj.hasOwnProperty(1)
set.has('1')
set.has(1)
  • A: false true false true
  • B: false true true true
  • C: true true false true
  • D: true true true true
答案

答案: C

所有對象的鍵(不包括 Symbol)在底層都是字符串,即使你自己沒有將其作爲字符串輸入。這就是爲什麼 obj.hasOwnProperty('1') 也返回 true

對於集合,它不是這樣工作的。在我們的集合中沒有 '1'set.has('1') 返回 false。它有數字類型爲 1set.has(1) 返回 true


25. 輸出是什麼?
const obj = { a: 'one', b: 'two', a: 'three' }
console.log(obj)
  • A: { a: "one", b: "two" }
  • B: { b: "two", a: "three" }
  • C: { a: "three", b: "two" }
  • D: SyntaxError
答案

答案: C

如果你有兩個名稱相同的鍵,則鍵會被替換掉。它仍然位於第一個鍵出現的位置,但是值是最後出現那個鍵的值。


26. JavaScript 全局執行上下文爲你做了兩件事:全局對象和 this 關鍵字。
  • A: 對
  • B: 錯
  • C: 看情況
答案

答案: A

基本執行上下文是全局執行上下文:它是代碼中隨處可訪問的內容。


27. 輸出是什麼?
for (let i = 1; i < 5; i++) {
  if (i === 3) continue
  console.log(i)
}
  • A: 1 2
  • B: 1 2 3
  • C: 1 2 4
  • D: 1 3 4
答案

答案: C

如果某個條件返回 true,則 continue 語句跳過本次迭代。


28. 輸出是什麼?
String.prototype.giveLydiaPizza = () => {
  return 'Just give Lydia pizza already!'
}

const name = 'Lydia'

name.giveLydiaPizza()
  • A: "Just give Lydia pizza already!"
  • B: TypeError: not a function
  • C: SyntaxError
  • D: undefined
答案

答案: A

String 是內置的構造函數,我們可以向它添加屬性。我只是在它的原型中添加了一個方法。基本類型字符串被自動轉換爲字符串對象,由字符串原型函數生成。因此,所有 string(string 對象)都可以訪問該方法!


29. 輸出是什麼?
const a = {}
const b = { key: 'b' }
const c = { key: 'c' }

a[b] = 123
a[c] = 456

console.log(a[b])
  • A: 123
  • B: 456
  • C: undefined
  • D: ReferenceError
答案

答案: B

對象的鍵被自動轉換爲字符串。我們試圖將一個對象 b 設置爲對象 a 的鍵,且相應的值爲 123

然而,當字符串化一個對象時,它會變成 "[object Object]"。因此這裏說的是,a["[object Object]"] = 123。然後,我們再一次做了同樣的事情,c 是另外一個對象,這裏也有隱式字符串化,於是,a["[object Object]"] = 456

然後,我們打印 a[b],也就是 a["[object Object]"]。之前剛設置爲 456,因此返回的是 456


30. 輸出是什麼?
const foo = () => console.log('First')
const bar = () => setTimeout(() => console.log('Second'))
const baz = () => console.log('Third')

bar()
foo()
baz()
  • A: First Second Third
  • B: First Third Second
  • C: Second First Third
  • D: Second Third First
答案

答案: B

我們有一個 setTimeout 函數,並首先調用它。然而,它是最後打印日誌的。

這是因爲在瀏覽器中,我們不僅有運行時引擎,還有一個叫做 WebAPI 的東西。WebAPI 提供了 setTimeout 函數,也包含其他的,例如 DOM。

callback 推送到 WebAPI 後,setTimeout 函數本身(但不是回調!)將從棧中彈出。

現在,foo 被調用,打印 "First"

foo 從棧中彈出,baz 被調用. 打印 "Third"

WebAPI 不能隨時向棧內添加內容。相反,它將回調函數推到名爲 queue 的地方。

這就是事件循環開始工作的地方。一個事件循環查看棧和任務隊列。如果棧是空的,它接受隊列上的第一個元素並將其推入棧。

bar 被調用,打印 "Second",然後它被棧彈出。


31. 當點擊按鈕時,event.target是什麼?
<div onclick="console.log('first div')">
  <div onclick="console.log('second div')">
    <button onclick="console.log('button')">
      Click!
    </button>
  </div>
</div>
  • A: Outer div
  • B: Inner div
  • C: button
  • D: 一個包含所有嵌套元素的數組。
答案

答案: C

導致事件的最深嵌套的元素是事件的 target。你可以通過 event.stopPropagation 來停止冒泡。


32. 當您單擊該段落時,日誌輸出是什麼?
<div onclick="console.log('div')">
  <p onclick="console.log('p')">
    Click here!
  </p>
</div>
  • A: p div
  • B: div p
  • C: p
  • D: div
答案

答案: A

如果我們點擊 p,我們會看到兩個日誌:pdiv。在事件傳播期間,有三個階段:捕獲、目標和冒泡。默認情況下,事件處理程序在冒泡階段執行(除非將 useCapture 設置爲 true)。它從嵌套最深的元素向外傳播。


33. 輸出是什麼?
const person = { name: 'Lydia' }

function sayHi(age) {
  console.log(`${this.name} is ${age}`)
}

sayHi.call(person, 21)
sayHi.bind(person, 21)
  • A: undefined is 21 Lydia is 21
  • B: function function
  • C: Lydia is 21 Lydia is 21
  • D: Lydia is 21 function
答案

答案: D

使用這兩種方法,我們都可以傳遞我們希望 this 關鍵字引用的對象。但是,.call立即執行的。

.bind 返回函數的副本,但帶有綁定上下文!它不是立即執行的。


34. 輸出是什麼?
function sayHi() {
  return (() => 0)()
}

typeof sayHi()
  • A: "object"
  • B: "number"
  • C: "function"
  • D: "undefined"
答案

答案: B

sayHi 方法返回的是立即執行函數(IIFE)的返回值.此立即執行函數的返回值是 0, 類型是 number

參考:只有7種內置類型:nullundefinedbooleannumberstringobjectsymbolfunction 不是一種類型,函數是對象,它的類型是object


35. 下面哪些值是 falsy?
0
new Number(0)
('')
(' ')
new Boolean(false)
undefined
  • A: 0, '', undefined
  • B: 0, new Number(0), '', new Boolean(false), undefined
  • C: 0, '', new Boolean(false), undefined
  • D: All of them are falsy
答案

答案: A

只有 6 種 falsy 值:

  • undefined
  • null
  • NaN
  • 0
  • '' (empty string)
  • false

Function 構造函數, 比如 new Numbernew Boolean,是 truthy


36. 輸出是什麼?
console.log(typeof typeof 1)
  • A: "number"
  • B: "string"
  • C: "object"
  • D: "undefined"
答案

答案: B

typeof 1 返回 "number"
typeof "number" 返回 "string"


37. 輸出是什麼?
const numbers = [1, 2, 3]
numbers[10] = 11
console.log(numbers)
  • A: [1, 2, 3, 7 x null, 11]
  • B: [1, 2, 3, 11]
  • C: [1, 2, 3, 7 x empty, 11]
  • D: SyntaxError
答案

答案: C

當你爲數組設置超過數組長度的值的時候, JavaScript 會創建名爲 “empty slots” 的東西。它們的值實際上是 undefined。你會看到以下場景:

[1, 2, 3, 7 x empty, 11]

這取決於你的運行環境(每個瀏覽器,以及 node 環境,都有可能不同)


38. 輸出是什麼?
(() => {
  let x, y
  try {
    throw new Error()
  } catch (x) {
    (x = 1), (y = 2)
    console.log(x)
  }
  console.log(x)
  console.log(y)
})()
  • A: 1 undefined 2
  • B: undefined undefined undefined
  • C: 1 1 2
  • D: 1 undefined undefined
答案

答案: A

catch 代碼塊接收參數 x。當我們傳遞參數時,這與之前定義的變量 x 不同 。這個 x 是屬於 catch 塊級作用域的。

然後,我們將塊級作用域中的變量賦值爲 1,同時也設置了變量 y 的值。現在,我們打印塊級作用域中的變量 x,值爲 1

catch 塊之外的變量 x 的值仍爲 undefinedy 的值爲 2。當我們在 catch 塊之外執行 console.log(x) 時,返回 undefinedy 返回 2


39. JavaScript 中的一切都是?
  • A: 基本類型與對象
  • B: 函數與對象
  • C: 只有對象
  • D: 數字與對象

答案

答案: A

JavaScript 只有基本類型和對象。

基本類型包括 boolean, null, undefined, bigint, number, string, symbol


40. 輸出是什麼?
[[0, 1], [2, 3]].reduce(
  (acc, cur) => {
    return acc.concat(cur)
  },
  [1, 2]
)
  • A: [0, 1, 2, 3, 1, 2]
  • B: [6, 1, 2]
  • C: [1, 2, 0, 1, 2, 3]
  • D: [1, 2, 6]
答案

答案: C

[1, 2]是初始值。初始值將會作爲首次調用時第一個參數 acc 的值。在第一次執行時, acc 的值是 [1, 2]cur 的值是 [0, 1]。合併它們,結果爲 [1, 2, 0, 1]
第二次執行, acc 的值是 [1, 2, 0, 1]cur 的值是 [2, 3]。合併它們,最終結果爲 [1, 2, 0, 1, 2, 3]


41. 輸出是什麼?
!!null
!!''
!!1
  • A: false true false
  • B: false false true
  • C: false true true
  • D: true true false
答案

答案: B

nullfalsy!null 的值是 true!true 的值是 false

""falsy!"" 的值是 true!true 的值是 false

1truthy!1 的值是 false!false 的值是 true


42. setInterval 方法的返回值是什麼?
setInterval(() => console.log('Hi'), 1000)
  • A: 一個唯一的id
  • B: 該方法指定的毫秒數
  • C: 傳遞的函數
  • D: undefined
答案

答案: A

setInterval 返回一個唯一的 id。此 id 可被用於 clearInterval 函數來取消定時。


43. 輸出是什麼?
[...'Lydia']
  • A: ["L", "y", "d", "i", "a"]
  • B: ["Lydia"]
  • C: [[], "Lydia"]
  • D: [["L", "y", "d", "i", "a"]]
答案

答案: A

string 類型是可迭代的。擴展運算符將迭代的每個字符映射成一個元素。


44. 輸出是什麼?
function* generator(i) {
  yield i;
  yield i * 2;
}

const gen = generator(10);

console.log(gen.next().value);
console.log(gen.next().value);
  • A: [0, 10], [10, 20]
  • B: 20, 20
  • C: 10, 20
  • D: 0, 10 and 10, 20
答案

答案: C

一般的函數在執行之後是不能中途停下的。但是,生成器函數卻可以中途“停下”,之後可以再從停下的地方繼續。當生成器遇到yield關鍵字的時候,會生成yield後面的值。注意,生成器在這種情況下不 返回 (return )值,而是 生成 (yield)值。

首先,我們用10作爲參數i來初始化生成器函數。然後使用next()方法一步步執行生成器。第一次執行生成器的時候,i的值爲10,遇到第一個yield關鍵字,它要生成i的值。此時,生成器“暫停”,生成了10

然後,我們再執行next()方法。生成器會從剛纔暫停的地方繼續,這個時候i還是10。於是我們走到了第二個yield關鍵字處,這時候需要生成的值是i*2i10,那麼此時生成的值便是20。所以這道題的最終結果是10,20

45. 返回值是什麼?
const firstPromise = new Promise((res, rej) => {
  setTimeout(res, 500, "one");
});

const secondPromise = new Promise((res, rej) => {
  setTimeout(res, 100, "two");
});

Promise.race([firstPromise, secondPromise]).then(res => console.log(res));
  • A: "one"
  • B: "two"
  • C: "two" "one"
  • D: "one" "two"
答案

答案: B

當我們向Promise.race方法中傳入多個Promise時,會進行 優先 解析。在這個例子中,我們用setTimeoutfirstPromisesecondPromise分別設定了500ms和100ms的定時器。這意味着secondPromise會首先解析出字符串two。那麼此時res參數即爲two,是爲輸出結果。


46. 輸出是什麼?
let person = { name: "Lydia" };
const members = [person];
person = null;

console.log(members);
  • A: null
  • B: [null]
  • C: [{}]
  • D: [{ name: "Lydia" }]
答案

答案: D

首先我們聲明瞭一個擁有name屬性的對象 person

然後我們又聲明瞭一個變量members. 將首個元素賦值爲變量person。 當設置兩個對象彼此相等時,它們會通過 引用 進行交互。但是當你將引用從一個變量分配至另一個變量時,其實只是執行了一個 複製 操作。(注意一點,他們的引用 並不相同!)

接下來我們讓person等於null

我們沒有修改數組第一個元素的值,而只是修改了變量person的值,因爲元素(複製而來)的引用與person不同。members的第一個元素仍然保持着對原始對象的引用。當我們輸出members數組時,第一個元素會將引用的對象打印出來。


47. 輸出是什麼?
const person = {
  name: "Lydia",
  age: 21
};

for (const item in person) {
  console.log(item);
}
  • A: { name: "Lydia" }, { age: 21 }
  • B: "name", "age"
  • C: "Lydia", 21
  • D: ["name", "Lydia"], ["age", 21]
答案

答案: B

for-in循環中,我們可以通過對象的key來進行迭代,也就是這裏的nameage。在底層,對象的key都是字符串(如果他們不是Symbol的話)。在每次循環中,我們將item設定爲當前遍歷到的key.所以一開始,itemname,之後 item輸出的則是age


48. 輸出是什麼?
console.log(3 + 4 + "5");
  • A: "345"
  • B: "75"
  • C: 12
  • D: "12"
答案

答案: B

當所有運算符的 優先級 相同時,計算表達式需要確定運算符的結合順序,即從右到左還是從左往右。在這個例子中,我們只有一類運算符+,對於加法來說,結合順序就是從左到右。

3 + 4首先計算,得到數字7.

由於類型的強制轉換,7 + '5'的結果是"75". JavaScript將7轉換成了字符串,可以參考問題15.我們可以用+號把兩個字符串連接起來。 "7" + "5" 就得到了"75".


49. num的值是什麼?
const num = parseInt("7*6", 10);
  • A: 42
  • B: "42"
  • C: 7
  • D: NaN
答案

答案: C

只返回了字符串中第一個字母. 設定了 進制 後 (也就是第二個參數,指定需要解析的數字是什麼進制: 十進制、十六機制、八進制、二進制等等……),parseInt 檢查字符串中的字符是否合法. 一旦遇到一個在指定進制中不合法的字符後,立即停止解析並且忽略後面所有的字符。

*就是不合法的數字字符。所以只解析到"7",並將其解析爲十進制的7. num的值即爲7.


50. 輸出是什麼?
[1, 2, 3].map(num => {
  if (typeof num === "number") return;
  return num * 2;
});
  • A: []
  • B: [null, null, null]
  • C: [undefined, undefined, undefined]
  • D: [ 3 x empty ]
答案

答案: C

對數組進行映射的時候,num就是當前循環到的元素. 在這個例子中,所有的映射都是number類型,所以if中的判斷typeof num === "number"結果都是true.map函數創建了新數組並且將函數的返回值插入數組。

但是,沒有任何值返回。當函數沒有返回任何值時,即默認返回undefined.對數組中的每一個元素來說,函數塊都得到了這個返回值,所以結果中每一個元素都是undefined.


51. 輸出的是什麼?
function getInfo(member, year) {
  member.name = "Lydia";
  year = "1998";
}

const person = { name: "Sarah" };
const birthYear = "1997";

getInfo(person, birthYear);

console.log(person, birthYear);
  • A: { name: "Lydia" }, "1997"
  • B: { name: "Sarah" }, "1998"
  • C: { name: "Lydia" }, "1998"
  • D: { name: "Sarah" }, "1997"
答案

答案: A

普通參數都是 傳遞的,而對象則不同,是 引用 傳遞。所以說,birthYear是值傳遞,因爲他是個字符串而不是對象。當我們對參數進行值傳遞時,會創建一份該值的 複製 。(可以參考問題46)

變量birthYear有一個對"1997"的引用,而傳入的參數也有一個對"1997"的引用,但二者的引用並不相同。當我們通過給 year賦值"1998"來更新year的值的時候我們只是更新了year(的引用)。此時birthYear仍然是"1997".

person是個對象。參數member引用與之 相同的 對象。當我們修改member所引用對象的屬性時,person的相應屬性也被修改了,因爲他們引用了相同的對象. personname屬性也變成了 "Lydia".


52. 輸出是什麼?
function greeting() {
  throw "Hello world!";
}

function sayHi() {
  try {
    const data = greeting();
    console.log("It worked!", data);
  } catch (e) {
    console.log("Oh no an error:", e);
  }
}

sayHi();
  • A: "It worked! Hello world!"
  • B: "Oh no an error: undefined
  • C: SyntaxError: can only throw Error objects
  • D: "Oh no an error: Hello world!
答案

答案: D

通過throw語句,我麼可以創建自定義錯誤。 而通過它,我們可以拋出異常。異常可以是一個字符串, 一個 數字, 一個 布爾類型 或者是一個 對象。在本例中,我們的異常是字符串'Hello world'.

通過 catch語句,我們可以設定當try語句塊中拋出異常後應該做什麼處理。在本例中拋出的異常是字符串'Hello world'. e就是這個字符串,因此被輸出。最終結果就是'Oh an error: Hello world'.


53. 輸出是什麼?
function Car() {
  this.make = "Lamborghini";
  return { make: "Maserati" };
}

const myCar = new Car();
console.log(myCar.make);
  • A: "Lamborghini"
  • B: "Maserati"
  • C: ReferenceError
  • D: TypeError
答案

答案: B

返回屬性的時候,屬性的值等於 返回的 值,而不是構造函數中設定的值。我們返回了字符串 "Maserati",所以 myCar.make等於"Maserati".


54. 輸出是什麼?
(() => {
  let x = (y = 10);
})();

console.log(typeof x);
console.log(typeof y);
  • A: "undefined", "number"
  • B: "number", "number"
  • C: "object", "number"
  • D: "number", "undefined"
答案

答案: A

let x = y = 10; 是下面這個表達式的縮寫:

y = 10;
let x = y;

我們設定y等於10時,我們實際上增加了一個屬性y給全局對象(瀏覽器裏的window, Nodejs裏的global)。在瀏覽器中, window.y等於10.

然後我們聲明瞭變量x等於y,也是10.但變量是使用 let聲明的,它只作用於 塊級作用域, 僅在聲明它的塊中有效;就是案例中的立即調用表達式(IIFE)。使用typeof操作符時, 操作值 x沒有被定義:因爲我們在x聲明塊的外部,無法調用它。這就意味着x未定義。未分配或是未聲明的變量類型爲"undefined". console.log(typeof x)返回"undefined".

而我們創建了全局變量y,並且設定y等於10.這個值在我們的代碼各處都訪問的到。 y已經被定義了,而且有一個"number"類型的值。 console.log(typeof y)返回"number".


55. 輸出是什麼?
class Dog {
  constructor(name) {
    this.name = name;
  }
}

Dog.prototype.bark = function() {
  console.log(`Woof I am ${this.name}`);
};

const pet = new Dog("Mara");

pet.bark();

delete Dog.prototype.bark;

pet.bark();
  • A: "Woof I am Mara", TypeError
  • B: "Woof I am Mara","Woof I am Mara"
  • C: "Woof I am Mara", undefined
  • D: TypeError, TypeError
答案

答案: A

我們可以用delete關鍵字刪除對象的屬性,對原型也是適用的。刪除了原型的屬性後,該屬性在原型鏈上就不可用了。在本例中,函數bark在執行了delete Dog.prototype.bark後不可用, 然而後面的代碼還在調用它。

當我們嘗試調用一個不存在的函數時TypeError異常會被拋出。在本例中就是 TypeError: pet.bark is not a function,因爲pet.barkundefined.


56. 輸出是什麼?
const set = new Set([1, 1, 2, 3, 4]);

console.log(set);
  • A: [1, 1, 2, 3, 4]
  • B: [1, 2, 3, 4]
  • C: {1, 1, 2, 3, 4}
  • D: {1, 2, 3, 4}
答案

答案: D

Set對象是獨一無二的值的集合:也就是說同一個值在其中僅出現一次。

我們傳入了數組[1, 1, 2, 3, 4],他有一個重複值1.以爲一個集合裏不能有兩個重複的值,其中一個就被移除了。所以結果是 {1, 2, 3, 4}.


57. 輸出是什麼?
// counter.js
let counter = 10;
export default counter;
// index.js
import myCounter from "./counter";

myCounter += 1;

console.log(myCounter);
  • A: 10
  • B: 11
  • C: Error
  • D: NaN
答案

答案: C

引入的模塊是 只讀 的: 你不能修改引入的模塊。只有導出他們的模塊才能修改其值。

當我們給myCounter增加一個值的時候會拋出一個異常: myCounter是隻讀的,不能被修改。


58. 輸出是什麼?
const name = "Lydia";
age = 21;

console.log(delete name);
console.log(delete age);
  • A: false, true
  • B: "Lydia", 21
  • C: true, true
  • D: undefined, undefined
答案

答案: A

delete操作符返回一個布爾值: true指刪除成功,否則返回false. 但是通過 var, constlet 關鍵字聲明的變量無法用 delete 操作符來刪除。

name變量由const關鍵字聲明,所以刪除不成功:返回 false. 而我們設定age等於21時,我們實際上添加了一個名爲age的屬性給全局對象。對象中的屬性是可以刪除的,全局對象也是如此,所以delete age返回true.


59. 輸出是什麼?
const numbers = [1, 2, 3, 4, 5];
const [y] = numbers;

console.log(y);
  • A: [[1, 2, 3, 4, 5]]
  • B: [1, 2, 3, 4, 5]
  • C: 1
  • D: [1]
答案

答案: C

我們可以通過解構賦值來解析來自對象的數組或屬性的值,比如說:

[a, b] = [1, 2];

a的值現在是1b的值現在是2.而在題目中,我們是這麼做的:

[y] = [1, 2, 3, 4, 5];

也就是說,y等於數組的第一個值就是數字1.我們輸出y, 返回1.


60. 輸出是什麼?
const user = { name: "Lydia", age: 21 };
const admin = { admin: true, ...user };

console.log(admin);
  • A: { admin: true, user: { name: "Lydia", age: 21 } }
  • B: { admin: true, name: "Lydia", age: 21 }
  • C: { admin: true, user: ["Lydia", 21] }
  • D: { admin: true }
答案

答案: B

擴展運算符...爲對象的組合提供了可能。你可以複製對象中的鍵值對,然後把它們加到另一個對象裏去。在本例中,我們複製了user對象鍵值對,然後把它們加入到admin對象中。admin對象就擁有了這些鍵值對,所以結果爲{ admin: true, name: "Lydia", age: 21 }.


61. 輸出是什麼?
const person = { name: "Lydia" };

Object.defineProperty(person, "age", { value: 21 });

console.log(person);
console.log(Object.keys(person));
  • A: { name: "Lydia", age: 21 }, ["name", "age"]
  • B: { name: "Lydia", age: 21 }, ["name"]
  • C: { name: "Lydia"}, ["name", "age"]
  • D: { name: "Lydia"}, ["age"]
答案

答案: B

通過defineProperty方法,我們可以給對象添加一個新屬性,或者修改已經存在的屬性。而我們使用defineProperty方法給對象添加了一個屬性之後,屬性默認爲 不可枚舉(not enumerable). Object.keys方法僅返回對象中 可枚舉(enumerable) 的屬性,因此只剩下了"name".

defineProperty方法添加的屬性默認不可變。你可以通過writable, configurableenumerable屬性來改變這一行爲。這樣的話, 相比於自己添加的屬性,defineProperty方法添加的屬性有了更多的控制權。


62. 輸出是什麼?
const settings = {
  username: "lydiahallie",
  level: 19,
  health: 90
};

const data = JSON.stringify(settings, ["level", "health"]);
console.log(data);
  • A: "{"level":19, "health":90}"
  • B: "{"username": "lydiahallie"}"
  • C: "["level", "health"]"
  • D: "{"username": "lydiahallie", "level":19, "health":90}"
答案

答案: A

JSON.stringify的第二個參數是 替代者(replacer). 替代者(replacer)可以是個函數或數組,用以控制哪些值如何被轉換爲字符串。

如果替代者(replacer)是個 數組 ,那麼就只有包含在數組中的屬性將會被轉化爲字符串。在本例中,只有名爲"level""health" 的屬性被包括進來, "username"則被排除在外。 data 就等於 "{"level":19, "health":90}".

而如果替代者(replacer)是個 函數,這個函數將被對象的每個屬性都調用一遍。
函數返回的值會成爲這個屬性的值,最終體現在轉化後的JSON字符串中(譯者注:Chrome下,經過實驗,如果所有屬性均返回同一個值的時候有異常,會直接將返回值作爲結果輸出而不會輸出JSON字符串),而如果返回值爲undefined,則該屬性會被排除在外。


63. 輸出是什麼?
let num = 10;

const increaseNumber = () => num++;
const increasePassedNumber = number => number++;

const num1 = increaseNumber();
const num2 = increasePassedNumber(num1);

console.log(num1);
console.log(num2);
  • A: 10, 10
  • B: 10, 11
  • C: 11, 11
  • D: 11, 12
答案

答案: A

一元操作符 ++ 先返回 操作值, 再累加 操作值。num1的值是10, 因爲increaseNumber函數首先返回num的值,也就是10,隨後再進行 num的累加。

num210因爲我們將 num1傳入increasePassedNumber. number等於10num1的值。同樣道理,++ 先返回 操作值, 再累加 操作值。) number10,所以num2也是10.


64. 輸出什麼?
const value = { number: 10 };

const multiply = (x = { ...value }) => {
  console.log(x.number *= 2);
};

multiply();
multiply();
multiply(value);
multiply(value);
  • A: 20, 40, 80, 160
  • B: 20, 40, 20, 40
  • C: 20, 20, 20, 40
  • D: NaN, NaN, 20, 40
答案

答案: C

在ES6中,我們可以使用默認值初始化參數。如果沒有給函數傳參,或者傳的參值爲 "undefined" ,那麼參數的值將是默認值。上述例子中,我們將 value 對象進行了解構並傳到一個新對象中,因此 x 的默認值爲 {number:10}

默認參數在調用時纔會進行計算,每次調用函數時,都會創建一個新的對象。我們前兩次調用 multiply 函數且不傳遞值,那麼每一次 x 的默認值都爲 {number:10} ,因此打印出該數字的乘積值爲20

第三次調用 multiply 時,我們傳遞了一個參數,即對象value*=運算符實際上是x.number = x.number * 2的簡寫,我們修改了x.number的值,並打印出值20

第四次,我們再次傳遞value對象。 x.number之前被修改爲20,所以x.number * = 2打印爲40


65. 輸出什麼?
[1, 2, 3, 4].reduce((x, y) => console.log(x, y));
  • A: 1 2 and 3 3 and 6 4
  • B: 1 2 and 2 3 and 3 4
  • C: 1 undefined and 2 undefined and 3 undefined and 4 undefined
  • D: 1 2 and undefined 3 and undefined 4
答案

答案: D

reducer 函數接收4個參數:

  1. Accumulator (acc) (累計器)
  2. Current Value (cur) (當前值)
  3. Current Index (idx) (當前索引)
  4. Source Array (src) (源數組)

reducer 函數的返回值將會分配給累計器,該返回值在數組的每個迭代中被記住,並最後成爲最終的單個結果值。

reducer 函數還有一個可選參數initialValue, 該參數將作爲第一次調用回調函數時的第一個參數的值。如果沒有提供initialValue,則將使用數組中的第一個元素。

在上述例子,reduce方法接收的第一個參數(Accumulator)是x, 第二個參數(Current Value)是y

在第一次調用時,累加器x1,當前值“y”2,打印出累加器和當前值:12

例子中我們的回調函數沒有返回任何值,只是打印累加器的值和當前值。如果函數沒有返回值,則默認返回undefined。 在下一次調用時,累加器爲undefined,當前值爲“3”, 因此undefined3被打印出。

在第四次調用時,回調函數依然沒有返回值。 累加器再次爲 undefined ,當前值爲“4”。 undefined4被打印出。


66. 使用哪個構造函數可以成功繼承Dog類?
class Dog {
  constructor(name) {
    this.name = name;
  }
};

class Labrador extends Dog {
  // 1 
  constructor(name, size) {
    this.size = size;
  }
  // 2
  constructor(name, size) {
    super(name);
    this.size = size;
  }
  // 3
  constructor(size) {
    super(name);
    this.size = size;
  }
  // 4 
  constructor(name, size) {
    this.name = name;
    this.size = size;
  }

};
  • A: 1
  • B: 2
  • C: 3
  • D: 4
答案

答案: B

在子類中,在調用super之前不能訪問到this關鍵字。 如果這樣做,它將拋出一個ReferenceError:1和4將引發一個引用錯誤。

使用super關鍵字,需要用給定的參數來調用父類的構造函數。 父類的構造函數接收name參數,因此我們需要將name傳遞給super

Labrador類接收兩個參數,name參數是由於它繼承了Dogsize作爲Labrador類的額外屬性,它們都需要傳遞給Labrador的構造函數,因此使用構造函數2正確完成。


67. 輸出什麼?
// index.js
console.log('running index.js');
import { sum } from './sum.js';
console.log(sum(1, 2));

// sum.js
console.log('running sum.js');
export const sum = (a, b) => a + b;
  • A: running index.js, running sum.js, 3
  • B: running sum.js, running index.js, 3
  • C: running sum.js, 3, running index.js
  • D: running index.js, undefined, running sum.js
答案

答案: B

import命令是編譯階段執行的,在代碼運行之前。因此這意味着被導入的模塊會先運行,而導入模塊的文件會後執行。

這是CommonJS中require()import之間的區別。使用require(),您可以在運行代碼時根據需要加載依賴項。 如果我們使用require而不是importrunning index.jsrunning sum.js3會被依次打印。


68. 輸出什麼?
console.log(Number(2) === Number(2))
console.log(Boolean(false) === Boolean(false))
console.log(Symbol('foo') === Symbol('foo'))
  • A: true, true, false
  • B: false, true, false
  • C: true, false, true
  • D: true, true, true
答案

答案: A

每個Symbol都是完全唯一的。傳遞給Symbol的參數只是給Symbol的一個描述。 Symbol的值不依賴於傳遞的參數。 當我們測試相等時,我們創建了兩個全新的符號:第一個Symbol('foo'),第二個Symbol('foo'), 這兩個值是唯一的,彼此不相等,因此返回false


69. 輸出什麼?
const name = "Lydia Hallie"
console.log(name.padStart(13))
console.log(name.padStart(2))
  • A: "Lydia Hallie", "Lydia Hallie"
  • B: " Lydia Hallie", " Lydia Hallie" ("[13x whitespace]Lydia Hallie", "[2x whitespace]Lydia Hallie")
  • C: " Lydia Hallie", "Lydia Hallie" ("[1x whitespace]Lydia Hallie", "Lydia Hallie")
  • D: "Lydia Hallie", "Lyd"
答案

答案: C

使用padStart方法,我們可以在字符串的開頭添加填充。傳遞給此方法的參數是字符串的總長度(包含填充)。字符串Lydia Hallie的長度爲12, 因此name.padStart(13)在字符串的開頭只會插入1(13 - 12 = 1)個空格。

如果傳遞給padStart方法的參數小於字符串的長度,則不會添加填充。


70. 輸出什麼?
console.log("🥑" + "💻");
  • A: "🥑💻"
  • B: 257548
  • C: A string containing their code points
  • D: Error
答案

答案: A

使用+運算符,您可以連接字符串。 上述情況,我們將字符串“🥑”與字符串”💻“連接起來,產生”🥑💻“


71. 如何能打印出console.log語句後註釋掉的值?
function* startGame() {
  const 答案 = yield "Do you love JavaScript?";
  if (答案 !== "Yes") {
    return "Oh wow... Guess we're gone here";
  }
  return "JavaScript loves you back ❤️";
}

const game = startGame();
console.log(/* 1 */); // Do you love JavaScript?
console.log(/* 2 */); // JavaScript loves you back ❤️
  • A: game.next("Yes").value and game.next().value
  • B: game.next.value("Yes") and game.next.value()
  • C: game.next().value and game.next("Yes").value
  • D: game.next.value() and game.next.value("Yes")
答案

答案: C

generator函數在遇到yield關鍵字時會“暫停”其執行。 首先,我們需要讓函數產生字符串Do you love JavaScript?,這可以通過調用game.next().value來完成。上述函數的第一行就有一個yield關鍵字,那麼運行立即停止了,yield表達式本身沒有返回值,或者說總是返回undefined, 這意味着此時變量 答案undefined

next方法可以帶一個參數,該參數會被當作上一個 yield 表達式的返回值。當我們調用game.next("Yes").value時,先前的 yield 的返回值將被替換爲傳遞給next()函數的參數"Yes"。此時變量 答案 被賦值爲 "Yes"if語句返回false,所以JavaScript loves you back ❤️被打印。


72. 輸出什麼?
console.log(String.raw`Hello\nworld`);
  • A: Hello world!
  • B: Hello
         world
  • C: Hello\nworld
  • D: Hello\n
         world
答案

答案: C

String.raw函數是用來獲取一個模板字符串的原始字符串的,它返回一個字符串,其中忽略了轉義符(\n\v\t等)。但反斜槓可能造成問題,因爲你可能會遇到下面這種類似情況:

const path = `C:\Documents\Projects\table.html`
String.raw`${path}`

這將導致:

"C:DocumentsProjects able.html"

直接使用String.raw

String.raw`C:\Documents\Projects\table.html`

它會忽略轉義字符並打印:C:\Documents\Projects\table.html

上述情況,字符串是Hello\nworld被打印出。


73. 輸出什麼?
async function getData() {
  return await Promise.resolve("I made it!");
}

const data = getData();
console.log(data);
  • A: "I made it!"
  • B: Promise {<resolved>: "I made it!"}
  • C: Promise {<pending>}
  • D: undefined
答案

答案: C

異步函數始終返回一個promise。await仍然需要等待promise的解決:當我們調用getData()並將其賦值給data,此時datagetData方法返回的一個掛起的promise,該promise並沒有解決。

如果我們想要訪問已解決的值"I made it!",可以在data上使用.then()方法:

data.then(res => console.log(res))

這樣將打印 "I made it!"


74. 輸出什麼?
function addToList(item, list) {
  return list.push(item);
}

const result = addToList("apple", ["banana"]);
console.log(result);
  • A: ['apple', 'banana']
  • B: 2
  • C: true
  • D: undefined
答案

答案: B

push()方法返回新數組的長度。一開始,數組包含一個元素(字符串"banana"),長度爲1。 在數組中添加字符串"apple"後,長度變爲2,並將從addToList函數返回。

push方法修改原始數組,如果你想從函數返回數組而不是數組長度,那麼應該在push item之後返回list


75. 輸出什麼?
const box = { x: 10, y: 20 };

Object.freeze(box);

const shape = box;
shape.x = 100;
console.log(shape)
  • A: { x: 100, y: 20 }
  • B: { x: 10, y: 20 }
  • C: { x: 100 }
  • D: ReferenceError
答案

答案: B

Object.freeze使得無法添加、刪除或修改對象的屬性(除非屬性的值是另一個對象)。

當我們創建變量shape並將其設置爲等於凍結對象box時,shape指向的也是凍結對象。你可以使用Object.isFrozen檢查一個對象是否被凍結,上述情況,Object.isFrozen(shape)將返回true

由於shape被凍結,並且x的值不是對象,所以我們不能修改屬性xx仍然等於10{x:10,y:20}被打印。

注意,上述例子我們對屬性x進行修改,可能會導致拋出TypeError異常(最常見但不僅限於嚴格模式下時)。


76. 輸出什麼?
const { name: myName } = { name: "Lydia" };

console.log(name);
  • A: "Lydia"
  • B: "myName"
  • C: undefined
  • D: ReferenceError
答案

答案: D

當我們從右側的對象解構屬性name時,我們將其值Lydia分配給名爲myName的變量。

使用{name:myName},我們是在告訴JavaScript我們要創建一個名爲myName的新變量,並且其值是右側對象的name屬性的值。

當我們嘗試打印name,一個未定義的變量時,就會引發ReferenceError


77. 以下是個純函數麼?
function sum(a, b) {
  return a + b;
}
  • A: Yes
  • B: No
答案

答案: A

純函數一種若輸入參數相同,則永遠會得到相同輸出的函數。

sum函數總是返回相同的結果。 如果我們傳遞12,它將總是返回3而沒有副作用。 如果我們傳遞510,它將總是返回15,依此類推,這是純函數的定義。


78. 輸出什麼?
const add = () => {
  const cache = {};
  return num => {
    if (num in cache) {
      return `From cache! ${cache[num]}`;
    } else {
      const result = num + 10;
      cache[num] = result;
      return `Calculated! ${result}`;
    }
  };
};

const addFunction = add();
console.log(addFunction(10));
console.log(addFunction(10));
console.log(addFunction(5 * 2));
  • A: Calculated! 20 Calculated! 20 Calculated! 20
  • B: Calculated! 20 From cache! 20 Calculated! 20
  • C: Calculated! 20 From cache! 20 From cache! 20
  • D: Calculated! 20 From cache! 20 Error
答案

答案: C

add函數是一個記憶函數。 通過記憶化,我們可以緩存函數的結果,以加快其執行速度。上述情況,我們創建一個cache對象,用於存儲先前返回過的值。

如果我們使用相同的參數多次調用addFunction函數,它首先檢查緩存中是否已有該值,如果有,則返回緩存值,這將節省執行時間。如果沒有,那麼它將計算該值,並存儲在緩存中。

我們用相同的值三次調用了addFunction函數:

在第一次調用,num等於10時函數的值尚未緩存,if語句num in cache返回false,else塊的代碼被執行:Calculated! 20,並且其結果被添加到緩存對象,cache現在看起來像{10:20}

第二次,cache對象包含10的返回值。 if語句 num in cache 返回trueFrom cache! 20被打印。

第三次,我們將5 * 2(值爲10)傳遞給函數。 cache對象包含10的返回值。 if語句 num in cache 返回trueFrom cache! 20被打印。


79. 輸出什麼?
const myLifeSummedUp = ["☕", "💻", "🍷", "🍫"]

for (let item in myLifeSummedUp) {
  console.log(item)
}

for (let item of myLifeSummedUp) {
  console.log(item)
}
  • A: 0 1 2 3 and "☕" "💻" "🍷" "🍫"
  • B: "☕" "💻" "🍷" "🍫" and "☕" "💻" "🍷" "🍫"
  • C: "☕" "💻" "🍷" "🍫" and 0 1 2 3
  • D: 0 1 2 3 and {0: "☕", 1: "💻", 2: "🍷", 3: "🍫"}
答案

答案: A

通過for-in循環,我們可以遍歷一個對象自有的繼承的可枚舉的非Symbol的屬性。 在數組中,可枚舉屬性是數組元素的“鍵”, 即它們的索引。 類似於下面這個對象:

{0: "☕", 1: "💻", 2: "🍷", 3: "🍫"}

其中鍵則是可枚舉屬性,因此 0123被記錄。

通過for-of循環,我們可以迭代可迭代對象(包括 ArrayMapSetStringarguments等)。當我們迭代數組時,在每次迭代中,不同屬性的值將被分配給變量item, 因此“☕”“💻”“🍷”“🍫”被打印。


80. 輸出什麼?
const list = [1 + 2, 1 * 2, 1 / 2]
console.log(list)
  • A: ["1 + 2", "1 * 2", "1 / 2"]
  • B: ["12", 2, 0.5]
  • C: [3, 2, 0.5]
  • D: [1, 1, 1]
答案

答案: C

數組元素可以包含任何值。 數字,字符串,布爾值,對象,數組,nullundeifned, 以及其他表達式,如日期,函數和計算。

元素將等於返回的值。 1 + 2返回31 * 2返回’2,'1 / 2返回0.5


81. 輸出什麼?
function sayHi(name) {
  return `Hi there, ${name}`
}

console.log(sayHi())
  • A: Hi there,
  • B: Hi there, undefined
  • C: Hi there, null
  • D: ReferenceError
答案

答案: B

默認情況下,如果不給函數傳參,參數的值將爲undefined。 上述情況,我們沒有給參數name傳值。 name等於undefined,並被打印。

在ES6中,我們可以使用默認參數覆蓋此默認的undefined值。 例如:

function sayHi(name =“Lydia”){...}

在這種情況下,如果我們沒有傳遞值或者如果我們傳遞undefinedname總是等於字符串Lydia


82. 輸出什麼?
var status = "😎"

setTimeout(() => {
  const status = "😍"

  const data = {
    status: "🥑",
    getStatus() {
      return this.status
    }
  }

  console.log(data.getStatus())
  console.log(data.getStatus.call(this))
}, 0)
  • A: "🥑" and "😍"
  • B: "🥑" and "😎"
  • C: "😍" and "😎"
  • D: "😎" and "😎"
答案

答案: B

this關鍵字的指向取決於使用它的位置。 在函數中,比如getStatusthis指向的是調用它的對象,上述例子中data對象調用了getStatus,因此this指向的就是data對象。 當我們打印this.status時,data對象的status屬性被打印,即"🥑"

使用call方法,可以更改this指向的對象。data.getStatus.call(this)是將this的指向由data對象更改爲全局對象。在全局對象上,有一個名爲status的變量,其值爲”😎“。 因此打印this.status時,會打印“😎”


83. 輸出什麼?
const person = {
  name: "Lydia",
  age: 21
}

let city = person.city
city = "Amsterdam"

console.log(person)
  • A: { name: "Lydia", age: 21 }
  • B: { name: "Lydia", age: 21, city: "Amsterdam" }
  • C: { name: "Lydia", age: 21, city: undefined }
  • D: "Amsterdam"
答案

答案: A

我們將變量city設置爲等於person對象上名爲city的屬性的值。 這個對象上沒有名爲city的屬性,因此變量city的值爲undefined

請注意,我們沒有引用person對象本身,只是將變量city設置爲等於person對象上city屬性的當前值。

然後,我們將city設置爲等於字符串“Amsterdam”。 這不會更改person對象:沒有對該對象的引用。

因此打印person對象時,會返回未修改的對象。


84. 輸出什麼?
function checkAge(age) {
  if (age < 18) {
    const message = "Sorry, you're too young."
  } else {
    const message = "Yay! You're old enough!"
  }

  return message
}

console.log(checkAge(21))
  • A: "Sorry, you're too young."
  • B: "Yay! You're old enough!"
  • C: ReferenceError
  • D: undefined
答案

答案: C

constlet聲明的變量是具有塊級作用域的,塊是大括號({})之間的任何東西, 即上述情況if / else語句的花括號。 由於塊級作用域,我們無法在聲明的塊之外引用變量,因此拋出ReferenceError


85. 什麼樣的信息將被打印?
fetch('https://www.website.com/api/user/1')
  .then(res => res.json())
  .then(res => console.log(res))
  • A: fetch方法的結果
  • B: 第二次調用fetch方法的結果
  • C: 前一個.then()中回調方法返回的結果
  • D: 總是undefined
答案

答案: C

第二個.thenres的值等於前一個.then中的回調函數返回的值。 你可以像這樣繼續鏈接.then,將值傳遞給下一個處理程序。


86. 哪個選項是將hasName設置爲true的方法,前提是不能將true作爲參數傳遞?
function getName(name) {
  const hasName = //
}
  • A: !!name
  • B: name
  • C: new Boolean(name)
  • D: name.length
答案

答案: A

使用邏輯非運算符!,將返回一個布爾值,使用!! name,我們可以確定name的值是真的還是假的。 如果name是真實的,那麼!name返回false!false返回true

通過將hasName設置爲name,可以將hasName設置爲等於傳遞給getName函數的值,而不是布爾值true

new Boolean(true)返回一個對象包裝器,而不是布爾值本身。

name.length返回傳遞的參數的長度,而不是布爾值true

87. 輸出什麼?
console.log("I want pizza"[0])
  • A: """
  • B: "I"
  • C: SyntaxError
  • D: undefined
答案

答案: B

可以使用方括號表示法獲取字符串中特定索引的字符,字符串中的第一個字符具有索引0,依此類推。 在這種情況下,我們想要得到索引爲0的元素,字符'I'被記錄。

請注意,IE7及更低版本不支持此方法。 在這種情況下,應該使用.charAt()


88. 輸出什麼?
function sum(num1, num2 = num1) {
  console.log(num1 + num2)
}

sum(10)
  • A: NaN
  • B: 20
  • C: ReferenceError
  • D: undefined
答案

答案: B

您可以將默認參數的值設置爲函數的另一個參數,只要另一個參數定義在其之前即可。 我們將值10傳遞給sum函數。 如果sum函數只接收1個參數,則意味着沒有傳遞num2的值,這種情況下,num1的值等於傳遞的值10num2的默認值是num1的值,即10num1 + num2返回20

如果您嘗試將默認參數的值設置爲後面定義的參數,則可能導致參數的值尚未初始化,從而引發錯誤。比如:

function test(m = n, n = 2) {
	console.log(m, n)
}
test() // Uncaught ReferenceError: Cannot access 'n' before initialization
test(3) // 3 2
test(3, 4) // 3 4

89. 輸出什麼?
// module.js 
export default () => "Hello world"
export const name = "Lydia"

// index.js 
import * as data from "./module"

console.log(data)
  • A: { default: function default(), name: "Lydia" }
  • B: { default: function default() }
  • C: { default: "Hello world", name: "Lydia" }
  • D: Global object of module.js
答案

答案: A

使用import * as name語法,我們將module.js文件中所有export導入到index.js文件中,並且創建了一個名爲data的新對象。 在module.js文件中,有兩個導出:默認導出和命名導出。 默認導出是一個返回字符串“Hello World”的函數,命名導出是一個名爲name的變量,其值爲字符串“Lydia”

data對象具有默認導出的default屬性,其他屬性具有指定exports的名稱及其對應的值。


90. 輸出什麼?
class Person {
  constructor(name) {
    this.name = name
  }
}

const member = new Person("John")
console.log(typeof member)
  • A: "class"
  • B: "function"
  • C: "object"
  • D: "string"
答案

答案: C

類是構造函數的語法糖,如果用構造函數的方式來重寫Person類則將是:

function Person() {
  this.name = name
}

通過new來調用構造函數,將會生成構造函數Person的實例,對實例執行typeof關鍵字將返回"object",上述情況打印出"object"


91. 輸出什麼?
let newList = [1, 2, 3].push(4)

console.log(newList.push(5))
  • A: [1, 2, 3, 4, 5]
  • B: [1, 2, 3, 5]
  • C: [1, 2, 3, 4]
  • D: Error
答案

答案: D

.push方法返回數組的長度,而不是數組本身! 通過將newList設置爲[1,2,3].push(4),實際上newList等於數組的新長度:4

然後,嘗試在newList上使用.push方法。 由於newList是數值4,拋出TypeError。


92. 輸出什麼?
function giveLydiaPizza() {
  return "Here is pizza!"
}

const giveLydiaChocolate = () => "Here's chocolate... now go hit the gym already."

console.log(giveLydiaPizza.prototype)
console.log(giveLydiaChocolate.prototype)
  • A: { constructor: ...} { constructor: ...}
  • B: {} { constructor: ...}
  • C: { constructor: ...} {}
  • D: { constructor: ...} undefined
答案

答案: D

常規函數,例如giveLydiaPizza函數,有一個prototype屬性,它是一個帶有constructor屬性的對象(原型對象)。 然而,箭頭函數,例如giveLydiaChocolate函數,沒有這個prototype屬性。 嘗試使用giveLydiaChocolate.prototype訪問prototype屬性時會返回undefined


93. 輸出什麼?
const person = {
  name: "Lydia",
  age: 21
}

for (const [x, y] of Object.entries(person)) {
  console.log(x, y)
}
  • A: name Lydia and age 21
  • B: ["name", "Lydia"] and ["age", 21]
  • C: ["name", "age"] and undefined
  • D: Error
答案

答案: A

Object.entries()方法返回一個給定對象自身可枚舉屬性的鍵值對數組,上述情況返回一個二維數組,數組每個元素是一個包含鍵和值的數組:

[['name','Lydia'],['age',21]]

使用for-of循環,我們可以迭代數組中的每個元素,上述情況是子數組。 我們可以使用const [x,y]for-of循環中解構子數組。 x等於子數組中的第一個元素,y等於子數組中的第二個元素。

第一個子陣列是[“name”,“Lydia”],其中x等於name,而y等於Lydia
第二個子陣列是[“age”,21],其中x等於age,而y等於21


94. 輸出什麼?
function getItems(fruitList, ...args, favoriteFruit) {
  return [...fruitList, ...args, favoriteFruit]
}

getItems(["banana", "apple"], "pear", "orange")
  • A: ["banana", "apple", "pear", "orange"]
  • B: [["banana", "apple"], "pear", "orange"]
  • C: ["banana", "apple", ["pear"], "orange"]
  • D: SyntaxError
答案

答案: D

... args是剩餘參數,剩餘參數的值是一個包含所有剩餘參數的數組,並且只能作爲最後一個參數。上述示例中,剩餘參數是第二個參數,這是不可能的,並會拋出語法錯誤。

function getItems(fruitList, favoriteFruit, ...args) {
  return [...fruitList, ...args, favoriteFruit]
}

getItems(["banana", "apple"], "pear", "orange")

上述例子是有效的,將會返回數組:[ 'banana', 'apple', 'orange', 'pear' ]


95. 輸出什麼?
function nums(a, b) {
  if
  (a > b)
  console.log('a is bigger')
  else 
  console.log('b is bigger')
  return 
  a + b
}

console.log(nums(4, 2))
console.log(nums(1, 2))
  • A: a is bigger, 6 and b is bigger, 3
  • B: a is bigger, undefined and b is bigger, undefined
  • C: undefined and undefined
  • D: SyntaxError
答案

答案: B

在JavaScript中,我們不必顯式地編寫分號(;),但是JavaScript引擎仍然在語句之後自動添加分號。這稱爲自動分號插入。例如,一個語句可以是變量,或者像throwreturnbreak這樣的關鍵字。

在這裏,我們在新的一行上寫了一個return語句和另一個值a + b。然而,由於它是一個新行,引擎並不知道它實際上是我們想要返回的值。相反,它會在return後面自動添加分號。你可以這樣看:

  return;
  a + b

這意味着永遠不會到達a + b,因爲函數在return關鍵字之後停止運行。如果沒有返回值,就像這裏,函數返回undefined。注意,在if/else語句之後沒有自動插入!


96. 輸出什麼?
class Person {
  constructor() {
    this.name = "Lydia"
  }
}

Person = class AnotherPerson {
  constructor() {
    this.name = "Sarah"
  }
}

const member = new Person()
console.log(member.name)
  • A: "Lydia"
  • B: "Sarah"
  • C: Error: cannot redeclare Person
  • D: SyntaxError
答案

答案: B

我們可以將類設置爲等於其他類/函數構造函數。 在這種情況下,我們將Person設置爲AnotherPerson。 這個構造函數的名字是Sarah,所以新的Person實例member上的name屬性是Sarah


97. 輸出什麼?
const info = {
  [Symbol('a')]: 'b'
}

console.log(info)
console.log(Object.keys(info))
  • A: {Symbol('a'): 'b'} and ["{Symbol('a')"]
  • B: {} and []
  • C: { a: "b" } and ["a"]
  • D: {Symbol('a'): 'b'} and []
答案

答案: D

Symbol類型是不可枚舉的。Object.keys方法返回對象上的所有可枚舉的鍵屬性。Symbol類型是不可見的,並返回一個空數組。 記錄整個對象時,所有屬性都是可見的,甚至是不可枚舉的屬性。

這是Symbol的衆多特性之一:除了表示完全唯一的值(防止對象意外名稱衝突,例如當使用2個想要向同一對象添加屬性的庫時),您還可以隱藏這種方式對象的屬性(儘管不完全。你仍然可以使用Object.getOwnPropertySymbols()方法訪問 Symbol


98. 輸出什麼?
const getList = ([x, ...y]) => [x, y]
const getUser = user => { name: user.name, age: user.age }

const list = [1, 2, 3, 4]
const user = { name: "Lydia", age: 21 }

console.log(getList(list))
console.log(getUser(user))
  • A: [1, [2, 3, 4]] and undefined
  • B: [1, [2, 3, 4]] and { name: "Lydia", age: 21 }
  • C: [1, 2, 3, 4] and { name: "Lydia", age: 21 }
  • D: Error and { name: "Lydia", age: 21 }
答案

答案: A

getList函數接收一個數組作爲其參數。 在getList函數的括號之間,我們立即解構這個數組。 您可以將其視爲:

[x, ...y] = [1, 2, 3, 4]

使用剩餘的參數... y,我們將所有剩餘參數放在一個數組中。 在這種情況下,其餘的參數是234y的值是一個數組,包含所有其餘參數。 在這種情況下,x的值等於1,所以當我們打印[x,y]時,會打印[1,[2,3,4]]

getUser函數接收一個對象。對於箭頭函數,如果只返回一個值,我們不必編寫花括號。但是,如果您想從一個箭頭函數返回一個對象,您必須在圓括號之間編寫它,否則不會返回任何值!下面的函數將返回一個對象:

const getUser = user => ({ name: user.name, age: user.age })

由於在這種情況下不返回任何值,因此該函數返回undefined


99. 輸出什麼?
const name = "Lydia"

console.log(name())
  • A: SyntaxError
  • B: ReferenceError
  • C: TypeError
  • D: undefined
答案

答案: C

變量name保存字符串的值,該字符串不是函數,因此無法調用。

當值不是預期類型時,會拋出TypeErrors。 JavaScript期望name是一個函數,因爲我們試圖調用它。 但它是一個字符串,因此拋出TypeErrorname is not a function

當你編寫了一些非有效的JavaScript時,會拋出語法錯誤,例如當你把return這個詞寫成retrun時。
當JavaScript無法找到您嘗試訪問的值的引用時,拋出ReferenceErrors


100. 輸出什麼?
// 🎉✨ This is my 100th question! ✨🎉

const output = `${[] && 'Im'}possible!
You should${'' && `n't`} see a therapist after so much JavaScript lol`
  • A: possible! You should see a therapist after so much JavaScript lol
  • B: Impossible! You should see a therapist after so much JavaScript lol
  • C: possible! You shouldn't see a therapist after so much JavaScript lol
  • D: Impossible! You shouldn't see a therapist after so much JavaScript lol
答案

答案: B

[]是一個真值。 使用&&運算符,如果左側值是真值,則返回右側值。 在這種情況下,左側值[]是一個真值,所以返回Im

""是一個假值。 如果左側值是假的,則不返回任何內容。 n't不會被退回。


101.輸出什麼?
const one = (false || {} || null)
const two = (null || false || "")
const three = ([] || 0 || true)

console.log(one, two, three)
  • A: false null []
  • B: null "" true
  • C: {} "" []
  • D: null null true
答案

答案: C

使用||運算符,我們可以返回第一個真值。 如果所有值都是假值,則返回最後一個值。

(false || {} || null):空對象{}是一個真值。 這是第一個(也是唯一的)真值,它將被返回。one等於{}

(null || false ||“”):所有值都是假值。 這意味着返回傳遞的值""two等於""

([] || 0 ||“”):空數組[]是一個真值。 這是第一個返回的真值。 three等於[]


102. 依次輸出什麼?
const myPromise = () => Promise.resolve('I have resolved!')

function firstFunction() {
  myPromise().then(res => console.log(res))
  console.log('second')
}

async function secondFunction() {
  console.log(await myPromise())
  console.log('second')
}

firstFunction()
secondFunction()
  • A: I have resolved!, second and I have resolved!, second
  • B: second, I have resolved! and second, I have resolved!
  • C: I have resolved!, second and second, I have resolved!
  • D: second, I have resolved! and I have resolved!, second
答案

答案: D

有了promise,我們通常會說:當我想要調用某個方法,但是由於它可能需要一段時間,因此暫時將它放在一邊。只有當某個值被resolved/rejected,並且執行棧爲空時才使用這個值。

我們可以在async函數中通過.thenawait關鍵字獲得該值。 儘管我們可以通過.thenawait獲得promise的價值,但是它們的工作方式有所不同。

firstFunction中,當運行到myPromise方法時我們將其放在一邊,即promise進入微任務隊列,其他後面的代碼(console.log('second'))照常運行,因此second被打印出,firstFunction方法到此執行完畢,執行棧中宏任務隊列被清空,此時開始執行微任務隊列中的任務,I have resolved被打印出。

secondFunction方法中,我們通過await關鍵字,暫停了後面代碼的執行,直到異步函數的值被解析纔開始後面代碼的執行。這意味着,它會等着直到 myPromise 以值I have resolved被解決之後,下一行second纔開始執行。


103. 輸出什麼?
const set = new Set()

set.add(1)
set.add("Lydia")
set.add({ name: "Lydia" })

for (let item of set) {
  console.log(item + 2)
}
  • A: 3, NaN, NaN
  • B: 3, 7, NaN
  • C: 3, Lydia2, [Object object]2
  • D: "12", Lydia2, [Object object]2
答案

答案: C

“+”運算符不僅用於添加數值,還可以使用它來連接字符串。 每當JavaScript引擎發現一個或多個值不是數字時,就會將數字強制爲字符串。

第一個是數字1。 1 + 2返回數字3。

但是,第二個是字符串“Lydia”。 “Lydia”是一個字符串,2是一個數字:2被強制轉換爲字符串。 “Lydia”和“2”被連接起來,產生字符串“Lydia2”。

{name:“ Lydia”}是一個對象。 數字和對象都不是字符串,因此將二者都字符串化。 每當我們對常規對象進行字符串化時,它就會變成[Object object]。 與“2”串聯的“ [Object object]”成爲“[Object object]2”。


104. 結果是什麼?
Promise.resolve(5)
  • A: 5
  • B: Promise {<pending>: 5}
  • C: Promise {<resolved>: 5}
  • D: Error
答案

答案: C

我們可以將我們想要的任何類型的值傳遞Promise.resolve,無論是否promise。 該方法本身返回帶有已解析值的Promise。 如果您傳遞常規函數,它將是具有常規值的已解決promise。 如果你通過了promise,它將是一個已經resolved的且帶有傳的值的promise。

上述情況,我們傳了數字5,因此返回一個resolved狀態的promise,resolve值爲5

105. 輸出什麼?
function compareMembers(person1, person2 = person) {
  if (person1 !== person2) {
    console.log("Not the same!")
  } else {
    console.log("They are the same!")
  }
}

const person = { name: "Lydia" }

compareMembers(person)
  • A: Not the same!
  • B: They are the same!
  • C: ReferenceError
  • D: SyntaxError
答案

答案: B

對象通過引用傳遞。 當我們檢查對象的嚴格相等性(===)時,我們正在比較它們的引用。

我們將“person2”的默認值設置爲“person”對象,並將“person”對象作爲“person1”的值傳遞。

這意味着兩個值都引用內存中的同一位置,因此它們是相等的。

運行“ else”語句中的代碼塊,並記錄They are the same!


106. 輸出什麼?
const colorConfig = {
  red: true,
  blue: false,
  green: true,
  black: true,
  yellow: false,
}

const colors = ["pink", "red", "blue"]

console.log(colorConfig.colors[1])
  • A: true
  • B: false
  • C: undefined
  • D: TypeError
答案

答案: D

在JavaScript中,我們有兩種訪問對象屬性的方法:括號表示法或點表示法。 在此示例中,我們使用點表示法(colorConfig.colors)代替括號表示法(colorConfig [“ colors”])。

使用點表示法,JavaScript會嘗試使用該確切名稱在對象上查找屬性。 在此示例中,JavaScript嘗試在colorconfig對象上找到名爲colors的屬性。 沒有名爲“colors”的屬性,因此返回“undefined”。
然後,我們嘗試使用[1]訪問第一個元素的值。 我們無法對未定義的值執行此操作,因此會拋出Cannot read property '1' of undefined

JavaScript解釋(或取消裝箱)語句。 當我們使用方括號表示法時,它會看到第一個左方括號[並一直進行下去,直到找到右方括號]。 只有這樣,它纔會評估該語句。 如果我們使用了colorConfig [colors [1]],它將返回colorConfig對象上red屬性的值。


107. 輸出什麼?
console.log('❤️' === '❤️')
  • A: true
  • B: false
答案

答案: A

在內部,表情符號是unicode。 heat表情符號的unicode是“ U + 2764 U + FE0F”。 對於相同的表情符號,它們總是相同的,因此我們將兩個相等的字符串相互比較,這將返回true。


108. 哪些方法修改了原數組?
const emojis = ['✨', '🥑', '😍']

emojis.map(x => x + '✨')
emojis.filter(x => x !== '🥑')
emojis.find(x => x !== '🥑')
emojis.reduce((acc, cur) => acc + '✨')
emojis.slice(1, 2, '✨') 
emojis.splice(1, 2, '✨')
  • A: All of them
  • B: map reduce slice splice
  • C: map slice splice
  • D: splice
答案

答案: D

使用splice方法,我們通過刪除,替換或添加元素來修改原始數組。 在這種情況下,我們從索引1中刪除了2個元素(我們刪除了'🥑''😍'),同時添加了✨emoji表情。

mapfilterslice返回一個新數組,find返回一個元素,而reduce返回一個減小的值。


109. 輸出什麼?
const food = ['🍕', '🍫', '🥑', '🍔']
const info = { favoriteFood: food[0] }

info.favoriteFood = '🍝'

console.log(food)
  • A: ['🍕', '🍫', '🥑', '🍔']
  • B: ['🍝', '🍫', '🥑', '🍔']
  • C: ['🍝', '🍕', '🍫', '🥑', '🍔']
  • D: ReferenceError
答案

答案: A

我們將info對象上的favoriteFood屬性的值設置爲披薩表情符號“🍕”的字符串。字符串是原始數據類型。在JavaScript中,原始數據類型通過值起作用

在這種情況下,我們將info對象上的favoriteFood屬性的值設置爲等於food數組中的第一個元素的值,字符串爲披薩表情符號('🍕' )。字符串是原始數據類型,並且通過值進行交互,我們更改info對象上favoriteFood屬性的值。 food數組沒有改變,因爲favoriteFood的值只是該數組中第一個元素的值的複製,並且與該元素上的元素沒有相同的內存引用食物[0]。當我們記錄食物時,它仍然是原始數組['🍕','🍫','🥑','🍔']


110. 這個函數幹了什麼?
JSON.parse()
  • A: Parses JSON to a JavaScript value
  • B: Parses a JavaScript object to JSON
  • C: Parses any JavaScript value to JSON
  • D: Parses JSON to a JavaScript object only
答案

答案: A

使用JSON.parse()方法,我們可以將JSON字符串解析爲JavaScript值。

// 將數字字符串化爲有效的JSON,然後將JSON字符串解析爲JavaScript值:
const jsonNumber = JSON.stringify(4) // '4'
JSON.parse(jsonNumber) // 4

// 將數組值字符串化爲有效的JSON,然後將JSON字符串解析爲JavaScript值:
const jsonArray = JSON.stringify([1, 2, 3]) // '[1, 2, 3]'
JSON.parse(jsonArray) // [1, 2, 3]

// 將對象字符串化爲有效的JSON,然後將JSON字符串解析爲JavaScript值:
const jsonArray = JSON.stringify({ name: "Lydia" }) // '{"name":"Lydia"}'
JSON.parse(jsonArray) // { name: 'Lydia' }

111. 輸出什麼?
let name = 'Lydia'

function getName() {
  console.log(name)
  let name = 'Sarah'
}

getName()
  • A: Lydia
  • B: Sarah
  • C: undefined
  • D: ReferenceError
答案

答案: D

每個函數都有其自己的執行上下文。 getName函數首先在其自身的上下文(範圍)內查找,以查看其是否包含我們嘗試訪問的變量name。 上述情況,getName函數包含其自己的name變量:我們用let關鍵字和Sarah的值聲明變量name

帶有let關鍵字(和const)的變量被提升,但是與var不同,它不會被***初始化***。 在我們聲明(初始化)它們之前,無法訪問它們。 這稱爲“暫時性死區”。 當我們嘗試在聲明變量之前訪問變量時,JavaScript會拋出ReferenceError: Cannot access 'name' before initialization

如果我們不在getName函數中聲明name變量,則javascript引擎會查看原型練。會找到其外部作用域有一個名爲name的變量,其值爲Lydia。 在這種情況下,它將打印Lydia

let name = 'Lydia'

function getName() {
  console.log(name)
}

getName() // Lydia

112. 輸出什麼?
function* generatorOne() {
  yield ['a', 'b', 'c'];
}

function* generatorTwo() {
  yield* ['a', 'b', 'c'];
}

const one = generatorOne()
const two = generatorTwo()

console.log(one.next().value)
console.log(two.next().value)
  • A: a and a
  • B: a and undefined
  • C: ['a', 'b', 'c'] and a
  • D: a and ['a', 'b', 'c']
答案

答案: C

通過 yield 關鍵字, 我們在 Generator 函數裏執行yield表達式. 通過 yield* 關鍵字, 我們可以在一個Generator 函數裏面執行(yield表達式)另一個 Generator 函數, 或可遍歷的對象 (如數組).

在函數 generatorOne 中, 我們通過 yield 關鍵字 yield 了一個完整的數組 ['a', 'b', 'c']。函數one通過next方法返回的對象的value 屬性的值 (one.next().value) 等價於數組 ['a', 'b', 'c'].

console.log(one.next().value) // ['a', 'b', 'c']
console.log(one.next().value) // undefined

在函數 generatorTwo 中, 我們使用 yield* 關鍵字。就相當於函數two第一個yield的值, 等價於在迭代器中第一個 yield 的值。數組['a', 'b', 'c']就是這個迭代器. 第一個 yield 的值就是 a, 所以我們第一次調用 two.next().value時, 就返回a

console.log(two.next().value) // 'a'
console.log(two.next().value) // 'b'
console.log(two.next().value) // 'c'
console.log(two.next().value) // undefined

113. 輸出什麼?
console.log(`${(x => x)('I love')} to program`)
  • A: I love to program
  • B: undefined to program
  • C: ${(x => x)('I love') to program
  • D: TypeError
答案

答案: A

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


114. 將會發生什麼?
let config = {
  alert: setInterval(() => {
    console.log('Alert!')
  }, 1000)
}

config = null
  • A: setInterval 的回調不會被調用
  • B: setInterval 的回調被調用一次
  • C: setInterval 的回調仍然會被每秒鐘調用
  • D: 我們從沒調用過 config.alert(), config 爲 null
答案

答案: C

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


115. 哪一個方法會返回 'Hello world!'
const myMap = new Map()
const myFunc = () => 'greeting'

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

//1
myMap.get('greeting')
//2
myMap.get(myFunc)
//3
myMap.get(() => 'greeting')
  • A: 1
  • B: 2
  • C: 2 and 3
  • D: All of them
答案

答案: B

當通過 set 方法添加一個鍵值對,一個傳遞給 set方法的參數將會是鍵名,第二個參數將會是值。在這個case裏,鍵名爲 函數 () => 'greeting',值爲'Hello world'myMap 現在就是 { () => 'greeting' => 'Hello world!' }

1 是錯的,因爲鍵名不是 'greeting' 而是 () => 'greeting'
3 是錯的,因爲我們給get 方法傳遞了一個新的函數。對象受 引用 影響。函數也是對象,因此兩個函數嚴格上並不等價,儘管他們相同:他們有兩個不同的內存引用地址。


116. 輸出什麼?
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)
  • A: {name: "Sarah", age: 22}
  • B: {name: "Sarah", age: 23}
  • C: {name: "Lydia", age: 22}
  • D: {name: "Lydia", age: 23}
答案

答案: C

函數 changeAge 和函數 changeAgeAndName 有着不同的參數,定義一個 生成的對象 { ...person }。這個對象有着所有 person 對象 中 k/v 值的副本。

首項, 我們調用 changeAge 函數並傳遞 person 對象作爲它的參數。這個函數對 age 屬性進行加一操作。person 現在是 { name: "Lydia", age: 22 }

然後,我們調用函數 changeAgeAndName ,然而我們沒有傳遞參數。取而代之,x 的值等價 new 生成的對象: { ...person }。因爲它是一個新生成的對象,它並不會對對象 person 造成任何副作用。person 仍然等價於 { name: "Lydia", age: 22 }


117. 下面那個選項將會返回 6?
function sumValues(x, y, z) {
	return x + y + z;
}
  • A: sumValues([...1, 2, 3])
  • B: sumValues([...[1, 2, 3]])
  • C: sumValues(...[1, 2, 3])
  • D: sumValues([1, 2, 3])
答案

答案: C

通過展開操作符 ...,我們可以 暫開 單個可迭代的元素。函數 sumValues function 接收三個參數: x, yz...[1, 2, 3] 的執行結果爲 1, 2, 3,將會傳遞給函數 sumValues


118. 輸出什麼?
let num = 1;
const list = ["🥳", "🤠", "🥰", "🤪"];

console.log(list[(num += 1)]);
  • A: 🤠
  • B: 🥰
  • C: SyntaxError
  • D: ReferenceError
答案

答案: B

通過 += 操作符,我們對值 num 進行加 1 操作。 num 有初始值 1,因此 1 + 1 的執行結果爲 2。數組 list 的第二項爲 🥰,console.log(list[2]) 輸出 🥰.


119. 輸出什麼?
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?.());
  • A: undefined undefined undefined undefined
  • B: Mara undefined Lydia Hallie undefined
  • C: Mara null Lydia Hallie null
  • D: null ReferenceError null ReferenceError
答案

答案: B

通過 ES10 或 TS3.7+可選鏈操作符 ?.,我們不再需要顯式檢測更深層的嵌套值是否有效。如果我們嘗試獲取 undefinednull 的值 (nullish),表達將會短路並返回 undefined.

person.pet?.nameperson 有一個名爲 pet 的屬性: person.pet 不是 nullish。它有個名爲 name 的屬性,並返回字符串 Mara
person.pet?.family?.nameperson 有一個名爲 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.


120. 輸出什麼?
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!`);
}
  • A: We have to buy bananas!
  • B: We don’t have to buy bananas
  • C: undefined
  • D: 1
答案

答案: B

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


121. 輸出什麼?
const config = {
	languages: [],
	set language(lang) {
		return this.languages.push(lang);
	}
};

console.log(config.language);
  • A: function language(lang) { this.languages.push(lang }
  • B: 0
  • C: []
  • D: undefined
答案

答案: D

方法 language 是一個 setter。Setters 並不保存一個實際值,它們的使命在於 修改 屬性。當調用方法 setter, 返回 undefined


122. 輸出什麼?
const name = "Lydia Hallie";

console.log(!typeof name === "object");
console.log(!typeof name === "string");
  • A: false true
  • B: true false
  • C: false false
  • D: true true
答案

答案: C

typeof name 返回 "string"。字符串 "string" 是一個 truthy 的值,因此 !typeof name 返回一個布爾值 falsefalse === "object"false === "string" 都返回 false

(如果我們想檢測一個值的類型,我們應該用 !== 而不是 !typeof


123. 輸出什麼?
const add = x => y => z => {
	console.log(x, y, z);
	return x + y + z;
};

add(4)(5)(6);
  • A: 4 5 6
  • B: 6 5 4
  • C: 4 function function
  • D: undefined undefined 6
答案

答案: A

函數 add 是一個返回 返回箭頭函數的箭頭函數 的箭頭函數(still with me?)。第一個函數接收一個值爲 4 的參數 x。我們調用第二個函數,它接收一個值爲 5 的參數 y。然後我們調用第三個函數,它接收一個值爲 6 的參數 z。當我們嘗試在最後一個箭頭函數中獲取 x, yz 的值,JS 引擎根據作用域鏈去找 xy 的值。得到 4 5 6.


124. 輸出什麼?
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);
	}
})();
  • A: Promise {1} Promise {2} Promise {3}
  • B: Promise {<pending>} Promise {<pending>} Promise {<pending>}
  • C: 1 2 3
  • D: undefined undefined undefined
答案

答案: C

我們給 函數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 以此爲: 123.


125. 輸出什麼?
const myFunc = ({ x, y, z }) => {
	console.log(x, y, z);
};

myFunc(1, 2, 3);
  • A: 1 2 3
  • B: {1: 1} {2: 2} {3: 3}
  • C: { 1: undefined } undefined undefined
  • D: undefined undefined undefined
答案

答案: D

myFunc 期望接收一個包含 x, yz 屬性的對象作爲它的參數。因爲我們僅僅傳遞三個單獨的數字值 (1, 2, 3) 而不是一個含有 x, yz 屬性的對象 ({x: 1, y: 2, z: 3}), x, yz 有着各自的默認值 undefined.


126. 輸出什麼?
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))
  • A: The driver drove 130 and has to pay 300
  • B: The driver drove 130 mph and has to pay $300.00
  • C: The driver drove undefined and has to pay undefined
  • D: The driver drove 130.00 and has to pay 300.00
答案

答案: B

通過方法 Intl.NumberFormat,我們可以格式化任意區域的數字值。我們對數字值 130 進行 mile-per-hour 作爲 uniten-US 區域 格式化,結果爲 130 mph。對數字值 300 進行 USD 作爲 currentcyen-US 區域格式化,結果爲 $300.00.


127. 輸出什麼?
const spookyItems = ["👻", "🎃", "🕸"];
({ item: spookyItems[3] } = { item: "💀" });

console.log(spookyItems);
  • A: ["👻", "🎃", "🕸"]
  • B: ["👻", "🎃", "🕸", "💀"]
  • C: ["👻", "🎃", "🕸", { item: "💀" }]
  • D: ["👻", "🎃", "🕸", "[object Object]"]
答案

答案: B

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


128. 輸出什麼?
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));
  • A: true false true false
  • B: true false false false
  • C: false false true false
  • D: false true false true
答案

答案: C

通過方法 Number.isNaN,你可以檢測你傳遞的值是否爲 數字值 並且是否等價於 NaNname 不是一個數字值,因此 Number.isNaN(name) 返回 falseage 是一個數字值,但它不等價於 NaN,因此 Number.isNaN(age) 返回 false.

通過方法 isNaN, 你可以檢測你傳遞的值是否一個 number。name 不是一個 number,因此 isNaN(name) 返回 true. age 是一個 number 因此 isNaN(age) 返回 false.


129. 輸出什麼?
const randomValue = 21;

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

getInfo();
  • A: "number"
  • B: "string"
  • C: undefined
  • D: ReferenceError
答案

答案: D

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


130. 輸出什麼?
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!");
	}
})();
  • A: Woah some cool data
  • B: Oh finally!
  • C: Woah some cool data Oh finally!
  • D: Oops didn't work Oh finally!
答案

答案: C

try 塊區,我們打印 myPromise 變量的 awaited 值: "Woah some cool data"。因爲try 塊區沒有錯誤拋出,catch 塊區的代碼並不執行。finally 塊區的代碼 總是 執行,"Oh finally!" 被輸出。


131. 輸出什麼?
const emojis = ["🥑", ["✨", "✨", ["🍕", "🍕"]]];

console.log(emojis.flat(1));
  • A: ['🥑', ['✨', '✨', ['🍕', '🍕']]]
  • B: ['🥑', '✨', '✨', ['🍕', '🍕']]
  • C: ['🥑', ['✨', '✨', '🍕', '🍕']]
  • D: ['🥑', '✨', '✨', '🍕', '🍕']
答案

答案: B

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


132. 輸出什麼?
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);
  • A: 0
  • B: 1
  • C: 2
  • D: 3
答案

答案: D

counterOne 是類 Counter 的一個實例。類 Counter 包含一個count 屬性在它的構造函數裏, 和一個 increment 方法。首先,我們通過 counterOne.increment() 調用方法 increment 兩次。現在, counterOne.count2.

然後,我們創建一個新的變量 counterTwo 並將 counterOne 的引用地址賦值給它。因爲對象受引用地址的影響,我們剛剛創建了一個新的對象,其引用地址和 counterOne 的等價。因此它們指向同一塊內存地址,任何對其的副作用都會影響 counterTwo。現在 counterTwo.count2

我們調用 counterTwo.increment()count 的值設爲 3。然後,我們打印 counterOne 裏的count,結果爲 3


133. 輸出什麼?
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();
  • A: Promise! Last line! Promise! Last line! Last line! Promise!
  • B: Last line! Timeout! Promise! Last line! Timeout! Promise!
  • C: Promise! Last line! Last line! Promise! Timeout! Timeout!
  • D: Last line! Promise! Promise! Last line! Timeout! Timeout!
答案

答案: D

首先,我們調用 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!


134. 我們怎樣才能在 index.js 中調用 sum.js? 中的 sum
// sum.js
export default function sum(x) {
	return x + x;
}

// index.js
import * as sum from "./sum";
  • A: sum(4)
  • B: sum.sum(4)
  • C: sum.default(4)
  • D: 默認導出不用 * 來導入,只能具名導出
答案

答案: C

使用符號 *,我們引入文件中的所有值,包括默認和具名。如果我們有以下文件:

// 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);

將會輸出以下內容:

{
  default: "I love JavaScript",
  name: "Lydia",
  age: 21
}

sum 爲例,相當於以下形式引入值 sum

{ default: function sum(x) { return x + x } }

我們可以通過調用 sum.default 來調用該函數


135. 輸出什麼?
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;
  • A: Added a new property!
  • B: Accessed a property!
  • C: Added a new property! Accessed a property!
  • D: 沒有任何輸出
答案

答案: C

使用 Proxy 對象,我們可以給一個對象添加自定義行爲。在這個 case,我們傳遞一個包含以下屬性的對象 handler : set and get。每當我門 設置 屬性值時 set 被調用,每當我們 獲取get 被調用。

第一個參數是一個空對象 {},作爲 person 的值。對於這個對象,自定義行爲被定義在對象 handler。如果我們向對象 person 添加屬性,set 將被調用。如果我們獲取 person 的屬性, get 將被調用。

首先,我們向 proxy 對象(person.name = "Lydia")添加一個屬性 nameset 被調用並輸出 "Added a new property!"

然後,我們獲取 proxy 對象的一個屬性,對象 handler 的屬性 get 被調用。輸出 "Accessed a property!"


136. 以下哪一項會對對象 person 有副作用?
const person = { name: "Lydia Hallie" };

Object.seal(person);
  • A: person.name = "Evan Bacon"
  • B: person.age = 21
  • C: delete person.name
  • D: Object.assign(person, { age: 21 })
答案

答案: A

使用 Object.seal 我們可以防止新屬性 被添加,或者存在屬性 被移除.

然而,你仍然可以對存在屬性進行更改。


137. 以下哪一項會對對象 person 有副作用?
const person = {
	name: "Lydia Hallie",
	address: {
		street: "100 Main St"
	}
};

Object.freeze(person);
  • A: person.name = "Evan Bacon"
  • B: delete person.address
  • C: person.address.street = "101 Main St"
  • D: person.pet = { name: "Mara" }
答案

答案: C

使用方法 Object.freeze 對一個對象進行 凍結。不能對屬性進行添加,修改,刪除。

然而,它僅 對對象進行 凍結,意味着只有 對象中的 直接 屬性被凍結。如果屬性是另一個 object,像案例中的 addressaddress 中的屬性沒有被凍結,仍然可以被修改。


138. 輸出什麼?
const add = x => x + x;

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

myFunc();
myFunc(3);
  • A: 2 4 and 3 6
  • B: 2 NaN and 3 NaN
  • C: 2 Error and 3 6
  • D: 2 4 and 3 Error
答案

答案: A

首先我們不傳遞任何參數調用 myFunc()。因爲我們沒有傳遞參數,numvalue 獲取它們各自的默認值:num 爲 2, 而 value 爲函數 add 的返回值。對於函數 add,我們傳遞值爲2的 num 作爲參數。函數 add 返回 4 作爲 value 的值。

然後,我們調用 myFunc(3) 並傳遞值 3 參數 num 的值。我們沒有給 value 傳遞值。因爲我們沒有給參數 value 傳遞值,它獲取默認值:函數 add 的返回值。對於函數 add,我們傳遞值爲3的 num給它。函數 add 返回 6 作爲 value 的值。


139. 輸出什麼?
class Counter {
  #number = 10

  increment() {
    this.#number++
  }

  getNum() {
    return this.#number
  }
}

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

console.log(counter.#number)
  • A: 10
  • B: 11
  • C: undefined
  • D: SyntaxError
答案

答案: D

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


140. 選擇哪一個?
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 }
  • A: yield getMembers(teams[i].members)
  • B: yield* getMembers(teams[i].members)
  • C: return getMembers(teams[i].members)
  • D: return yield getMembers(teams[i].members)
答案

答案: B

爲了遍歷 teams 數組中對象的屬性 members 中的每一項,我們需要將 teams[i].members 傳遞給 Generator 函數 getMembers。Generator 函數返回一個 generator 對象。爲了遍歷這個 generator 對象中的每一項,我們需要使用 yield*.

如果我們沒有寫 yieldreturn yield 或者 return,整個 Generator 函數不會第一時間 return 當我們調用 next 方法.


141. 輸出什麼?
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);
  • A: ["coding"]
  • B: ["coding", "dancing"]
  • C: ["coding", "dancing", "baking"]
  • D: ["coding", "running", "dancing", "baking"]
答案

答案: C

函數 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 dancingbaking 之後,person.hobbies 的值爲 ["coding", "dancing", "baking"]


142. 輸出什麼?
class Bird {
	constructor() {
		console.log("I'm a bird. 🦢");
	}
}

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

const pet = new Flamingo();
  • A: I'm pink. 🌸
  • B: I'm pink. 🌸 I'm a bird. 🦢
  • C: I'm a bird. 🦢 I'm pink. 🌸
  • D: Nothing, we didn’t call any method
答案

答案: B

我們創建了類 Flamingo 的實例 pet。當我們實例化這個實例,Flamingo 中的 constructor 被調用。首相,輸出 "I'm pink. 🌸", 之後我們調用super()super() 調用父類的構造函數,BirdBird 的構造函數被調用,並輸出 "I'm a bird. 🦢"


143. 哪一個選項會導致報錯?
const emojis = ["🎄", "🎅🏼", "🎁", "⭐"];

/* 1 */ emojis.push("🦌");
/* 2 */ emojis.splice(0, 2);
/* 3 */ emojis = [...emojis, "🥂"];
/* 4 */ emojis.length = 0;
  • A: 1
  • B: 1 and 2
  • C: 3 and 4
  • D: 3
答案

答案: D

const 關鍵字意味着我們不能 重定義 變量中的值,它 僅可讀。而然,值本身不可修改。數組 emojis 中的值可被修改,如 push 新的值, 拼接,又或者將數組的長度設置爲0。


144. 我們需要向對象 person 添加什麼,以致執行 [...person] 時獲得形如 ["Lydia Hallie", 21] 的輸出?
const person = {
  name: "Lydia Hallie",
  age: 21
}

[...person] // ["Lydia Hallie", 21]
  • A: 不需要,對象默認就是可迭代的
  • B: *[Symbol.iterator]() { for (let x in this) yield* this[x] }
  • C: *[Symbol.iterator]() { for (let x in this) yield* Object.values(this) }
  • D: *[Symbol.iterator]() { for (let x in this) yield this }
答案

答案: C

對象默認並不是可迭代的。如果迭代規則被定義,則一個對象是可迭代的(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 對象 personObject.values

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章