2020年從基礎到進階,測試你有多瞭解 JavaScript,刷新你的知識!

【譯】JavaScript 進階問題列表

從基礎到進階,測試你有多瞭解 JavaScript,刷新你的知識!javascript

答案在問題下方的摺疊部分,點擊便可展開問題。html


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 變量時尚未執行到定義變量的位置,所以變量的值保持爲 undefinedjava

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


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。git

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


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 的值是一個箭頭函數。web

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

window 中沒有 radius 這個屬性,所以返回 undefinedjson


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

答案: A

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

字符串 '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: true
  • B: false
答案

答案: 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: true
  • B: false
  • C: it depends
答案

答案: 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 answer = yield "Do you love JavaScript?";
  if (answer !== "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, 這意味着此時變量 answerundefined

next方法能夠帶一個參數,該參數會被看成上一個 yield 表達式的返回值。當咱們調用game.next("Yes").value時,先前的 yield 的返回值將被替換爲傳遞給next()函數的參數"Yes"。此時變量 answer 被賦值爲 "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 的屬性,並返回字符串 Maraperson.pet?.family?.nameperson 有一個名爲 pet 的屬性: person.pet 不是 nullish. pet 並無 一個名爲 family 的屬性, person.pet.family 是 nullish。表達式返回 undefinedperson.getFullName?.()person 有一個名爲 getFullName 的屬性: person.getFullName() 不是 nullish 並能夠被調用,返回字符串 Lydia Halliemember.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. 如下哪一項會對對象 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 中的屬性沒有被凍結,仍然能夠被修改。


139. 輸出什麼?
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 的值。


140. 輸出什麼?
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 外部獲取它!


141. 選擇哪個?
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 方法.


142. 輸出什麼?
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"]


143. 輸出什麼?
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. 🦢"


144. 哪個選項會致使報錯?
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。


145. 咱們須要向對象 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


原文出自Lydia Hallie的 Instagram,若是沒法訪問,請移步到這裏

❤️ 看完三件事:

若是你以爲這篇內容對你挺有啓發,我想邀請你幫我個小忙:

  • 點贊,讓更多的人也能看到這篇內容,也方便本身隨時找到這篇內容(收藏不點贊,都是耍流氓 -_-)
  • 關注咱們,不按期分好文章。
  • 也看看其它文章
相關文章
相關標籤/搜索