JavaScript?進階問題列表(各種js代碼段108-155)
我在我的 Instagram 上每天都會發(fā)布 JavaScript 的多選問題,并且同時也會在這個倉庫中發(fā)布。
從基礎到進階,測試你有多了解 JavaScript,刷新你的知識,或者幫助你的 coding 面試! :muscle: :rocket: 我每周都會在這個倉庫下更新新的問題。
答案在問題下方的折疊部分,點擊即可展開問題。祝你好運
因為篇幅有限,這里是108-155條,不定期增加
108. 哪些方法修改了原數(shù)組?
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
方法,我們通過刪除,替換或添加元素來修改原始數(shù)組。在這種情況下,我們從索引 1 中刪除了 2 個元素(我們刪除了'??'
和'??'
),同時添加了?emoji 表情。
map
,filter
和slice
返回一個新數(shù)組,find
返回一個元素,而reduce
返回一個減小的值。
109. 輸出什么?
const food = ['??', '??', '??', '??'] const info = { favoriteFood: food[0] } info.favoriteFood = '??' console.log(food)
- A:
['??', '??', '??', '??']
- B:
['??', '??', '??', '??']
- C:
['??', '??', '??', '??', '??']
- D:
ReferenceError
答案
答案:A
我們將info
對象上的favoriteFood
屬性的值設置為披薩表情符號“??”的字符串。字符串是原始數(shù)據(jù)類型。在 JavaScript 中,原始數(shù)據(jù)類型通過值起作用
在這種情況下,我們將info
對象上的favoriteFood
屬性的值設置為等于food
數(shù)組中的第一個元素的值,字符串為披薩表情符號('??'
)。字符串是原始數(shù)據(jù)類型,并且通過值進行交互,我們更改info
對象上favoriteFood
屬性的值。food 數(shù)組沒有改變,因為 favoriteFood 的值只是該數(shù)組中第一個元素的值的復制,并且與該元素上的元素沒有相同的內(nèi)存引用食物[0]
。當我們記錄食物時,它仍然是原始數(shù)組['??','??','??','??']
。
110. 這個函數(shù)干了什么?
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 值。
111. 輸出什么?
let name = 'Lydia' function getName() { console.log(name) let name = 'Sarah' } getName()
- A: Lydia
- B: Sarah
- C:
undefined
- D:
ReferenceError
答案
答案:D
每個函數(shù)都有其自己的執(zhí)行上下文。getName
函數(shù)首先在其自身的上下文(范圍)內(nèi)查找,以查看其是否包含我們嘗試訪問的變量name
。上述情況,getName
函數(shù)包含其自己的name
變量:我們用let
關鍵字和Sarah
的值聲明變量name
。
帶有let
關鍵字(和const
)的變量被提升,但是與var
不同,它不會被* 初始化*。在我們聲明(初始化)它們之前,無法訪問它們。這稱為“暫時性死區(qū)”。當我們嘗試在聲明變量之前訪問變量時,JavaScript 會拋出ReferenceError: Cannot access 'name' before initialization
。
如果我們不在getName
函數(shù)中聲明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
anda
- B:
a
andundefined
- C:
['a', 'b', 'c']
anda
- D:
a
and['a', 'b', 'c']
答案
答案:C
通過 yield
關鍵字,我們在 Generator
函數(shù)里執(zhí)行yield
表達式。通過 yield*
關鍵字,我們可以在一個Generator
函數(shù)里面執(zhí)行(yield
表達式)另一個 Generator
函數(shù),或可遍歷的對象 (如數(shù)組).
在函數(shù) generatorOne
中,我們通過 yield
關鍵字 yield 了一個完整的數(shù)組 ['a', 'b', 'c']
。函數(shù)one
通過next
方法返回的對象的value
屬性的值 (one.next().value
) 等價于數(shù)組 ['a', 'b', 'c']
.
console.log(one.next().value) // ['a', 'b', 'c'] console.log(one.next().value) // undefined
在函數(shù) generatorTwo
中,我們使用 yield*
關鍵字。就相當于函數(shù)two
第一個yield
的值,等價于在迭代器中第一個 yield
的值。數(shù)組['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
帶有模板字面量的表達式首先被執(zhí)行。相當于字符串會包含表達式,這個立即執(zhí)行函數(shù) (x => x)('I love')
返回的值。我們向箭頭函數(shù) x => x
傳遞 'I love'
作為參數(shù)。x
等價于返回的 'I love'
。這就是結果 I love to program
。
114. 將會發(fā)生什么?
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) 因為已經(jīng)沒有對這些對象的引用了。然而,setInterval
的參數(shù)是一個箭頭函數(shù)(所以上下文綁定到對象 config
了),回調函數(shù)仍然保留著對 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
方法的參數(shù)將會是鍵名,第二個參數(shù)將會是值。在這個 case 里,鍵名為 函數(shù) () => 'greeting'
,值為'Hello world'
。 myMap
現(xiàn)在就是 { () => 'greeting' => 'Hello world!' }
。
1 是錯的,因為鍵名不是 'greeting'
而是 () => 'greeting'
。 3 是錯的,因為我們給get
方法傳遞了一個新的函數(shù)。對象受 引用 影響。函數(shù)也是對象,因此兩個函數(shù)嚴格上并不等價,盡管他們相同:他們有兩個不同的內(nèi)存引用地址。
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
函數(shù) changeAge
和函數(shù) changeAgeAndName
有著不同的參數(shù),定義一個 新 生成的對象 { ...person }
。這個對象有著所有 person
對象 中 k/v 值的副本。
首項,我們調用 changeAge
函數(shù)并傳遞 person
對象作為它的參數(shù)。這個函數(shù)對 age
屬性進行加一操作。person
現(xiàn)在是 { name: "Lydia", age: 22 }
。
然后,我們調用函數(shù) changeAgeAndName
,然而我們沒有傳遞參數(shù)。取而代之,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
通過展開操作符 ...
,我們可以 暫開 單個可迭代的元素。函數(shù) sumValues
function 接收三個參數(shù):x
, y
和 z
。...[1, 2, 3]
的執(zhí)行結果為 1, 2, 3
,將會傳遞給函數(shù) 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
的執(zhí)行結果為 2
。數(shù)組 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
ReferenceError
- C:
Mara
null
Lydia Hallie
null
- D:
null
ReferenceError
null
ReferenceError
答案
答案:B
通過 ES10 或 TS3.7+可選鏈操作符 ?.,我們不再需要顯式檢測更深層的嵌套值是否有效。如果我們嘗試獲取 undefined
或 null
的值 (nullish),表達將會短路并返回 undefined
.
person.pet?.name
:person
有一個名為 pet
的屬性:person.pet
不是 nullish。它有個名為 name
的屬性,并返回字符串 Mara
。 person.pet?.family?.name
:person
有一個名為 pet
的屬性:person.pet
不是 nullish. pet
并沒有 一個名為 family
的屬性,person.pet.family
是 nullish。表達式返回 undefined
。 person.getFullName?.()
:person
有一個名為 getFullName
的屬性:person.getFullName()
不是 nullish 并可以被調用,返回字符串 Lydia Hallie
。 member.getLastName?.()
: 變量member
不存在,因此會拋出錯誤ReferenceError
。
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
我們傳遞了一個狀態(tài) groceries.indexOf("banana")
給 if 條件語句。groceries.indexOf("banana")
返回 0
,一個 falsy 的值。因為 if 條件語句的狀態(tài)為 falsy,else
塊區(qū)內(nèi)的代碼執(zhí)行,并且 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
返回一個布爾值 false
。false === "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
函數(shù) add
是一個返回 返回箭頭函數(shù)的箭頭函數(shù) 的箭頭函數(shù)(still with me?)。第一個函數(shù)接收一個值為 4
的參數(shù) x
。我們調用第二個函數(shù),它接收一個值為 5
的參數(shù) y
。然后我們調用第三個函數(shù),它接收一個值為 6
的參數(shù) z
。當我們嘗試在最后一個箭頭函數(shù)中獲取 x
, y
和 z
的值,JS 引擎根據(jù)作用域鏈去找 x
和 y
的值。得到 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
我們給 函數(shù) range 傳遞:Promise{1}
, Promise{2}
, Promise{3}
,Generator 函數(shù) range
返回一個全是 async object promise 數(shù)組。我們將 async object 賦值給變量 gen
,之后我們使用for await ... of
進行循環(huán)遍歷。我們將返回的 Promise 實例賦值給 item
:第一個返回 Promise{1}
,第二個返回 Promise{2}
,之后是 Promise{3}
。因為我們正 awaiting item
的值,resolved 狀態(tài)的 promise,promise 數(shù)組的 resolved 值 以此為:1
,2
,3
.
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
, y
和 z
屬性的對象作為它的參數(shù)。因為我們僅僅傳遞三個單獨的數(shù)字值 (1, 2, 3) 而不是一個含有 x
, y
和 z
屬性的對象 ({x: 1, y: 2, z: 3}),x
, y
和 z
有著各自的默認值 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
,我們可以格式化任意區(qū)域的數(shù)字值。我們對數(shù)字值 130
進行 mile-per-hour
作為 unit
的 en-US
區(qū)域 格式化,結果為 130 mph
。對數(shù)字值 300
進行 USD
作為 currency
的 en-US
區(qū)域格式化,結果為 $300.00
.
127. 輸出什么?
const spookyItems = ["??", "??", "??"]; ({ item: spookyItems[3] } = { item: "??" }); console.log(spookyItems);
- A:
["??", "??", "??"]
- B:
["??", "??", "??", "??"]
- C:
["??", "??", "??", { item: "??" }]
- D:
["??", "??", "??", "[object Object]"]
答案
答案:B
通過解構對象們,我們可以從右手邊的對象中拆出值,并且將拆出的值分配給左手邊對象同名的屬性。在這種情況下,我們將值 "??" 分配給 spookyItems[3]
。相當于我們正在篡改數(shù)組 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
,你可以檢測你傳遞的值是否為 數(shù)字值 并且是否等價于 NaN
。name
不是一個數(shù)字值,因此 Number.isNaN(name)
返回 false
。age
是一個數(shù)字值,但它不等價于 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
關鍵字聲明的變量在被初始化之前不可被引用:這被稱之為 暫時性死區(qū)。在函數(shù) getInfo
中,變量 randomValue
聲明在getInfo
的作用域的此法環(huán)境中。在想要對 typeof randomValue
進行 log 之前,變量 randomValue
仍未被初始化:錯誤ReferenceError
被拋出!JS 引擎并不會根據(jù)作用域鏈網(wǎng)上尋找該變量,因為我們已經(jīng)在 getInfo
函數(shù)中聲明了 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
塊區(qū),我們打印 myPromise
變量的 awaited 值:"Woah some cool data"
。因為try
塊區(qū)沒有錯誤拋出,catch
塊區(qū)的代碼并不執(zhí)行。finally
塊區(qū)的代碼 總是 執(zhí)行,"Oh finally!"
被輸出。
131. 輸出什么?
const emojis = ["??", ["?", "?", ["??", "??"]]]; console.log(emojis.flat(1));
- A:
['??', ['?', '?', ['??', '??']]]
- B:
['??', '?', '?', ['??', '??']]
- C:
['??', ['?', '?', '??', '??']]
- D:
['??', '?', '?', '??', '??']
答案
答案:B
通過方法 flat
,我們可以創(chuàng)建一個新的,已被扁平化的數(shù)組。被扁平化的深度取決于我們傳遞的值。在這個 case 里,我們傳遞了值 1
(并不必要,這是默認值),相當于只有第一層的數(shù)組才會被連接。即這個 case 里的 ['??']
and ['?', '?', ['??', '??']]
。連接這兩個數(shù)組得到結果 ['??', '?', '?', ['??', '??']]
.
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
屬性在它的構造函數(shù)里,和一個 increment
方法。首先,我們通過 counterOne.increment()
調用方法 increment
兩次?,F(xiàn)在,counterOne.count
為 2
.
然后,我們創(chuàng)建一個新的變量 counterTwo
并將 counterOne
的引用地址賦值給它。因為對象受引用地址的影響,我們剛剛創(chuàng)建了一個新的對象,其引用地址和 counterOne
的等價。因此它們指向同一塊內(nèi)存地址,任何對其的副作用都會影響 counterTwo
?,F(xiàn)在 counterTwo.count
為 2
。
我們調用 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
。在函數(shù) funcOne
的第一行,我們調用myPromise
promise 異步操作。當 JS 引擎在忙于執(zhí)行 promise,它繼續(xù)執(zhí)行函數(shù) funcOne
。下一行 異步操作 setTimeout
,其回調函數(shù)被 Web API 調用。 (詳情請參考我關于 event loop 的文章.)
promise 和 timeout 都是異步操作,函數(shù)繼續(xù)執(zhí)行當 JS 引擎忙于執(zhí)行 promise 和 處理 setTimeout
的回調。相當于 Last line!
首先被輸出,因為它不是異步操作。執(zhí)行完 funcOne
的最后一行,promise 狀態(tài)轉變?yōu)?resolved,Promise!
被打印。然而,因為我們調用了 funcTwo()
,調用棧不為空,setTimeout
的回調仍不能入棧。
我們現(xiàn)在處于 funcTwo
,先 awaiting myPromise。通過 await
關鍵字,我們暫停了函數(shù)的執(zhí)行直到 promise 狀態(tài)變?yōu)?resolved (或 rejected)。然后,我們輸出 res
的 awaited 值(因為 promise 本身返回一個 promise)。接著輸出 Promise!
。
下一行就是 異步操作 setTimeout
,其回調函數(shù)被 Web API 調用。
我們執(zhí)行到函數(shù) funcTwo
的最后一行,輸出 Last line!
?,F(xiàn)在,因為 funcTwo
出棧,調用棧為空。在事件隊列中等待的回調函數(shù)(() => 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);
將會輸出以下內(nèi)容:
{ default: "I love JavaScript", name: "Lydia", age: 21 }
以 sum
為例,相當于以下形式引入值 sum
:
{ default: function sum(x) { return x + x } }
我們可以通過調用 sum.default
來調用該函數(shù)
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
被調用。
第一個參數(shù)是一個空對象 {}
,作為 person
的值。對于這個對象,自定義行為被定義在對象 handler
。如果我們向對象 person
添加屬性,set
將被調用。如果我們獲取 person
的屬性,get
將被調用。
首先,我們向 proxy 對象 (person.name = "Lydia"
) 添加一個屬性 name
。set
被調用并輸出 "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,像案例中的 address
,address
中的屬性沒有被凍結,仍然可以被修改。
138. 輸出什么?
const add = x => x + x; function myFunc(num = 2, value = add(num)) { console.log(num, value); } myFunc(); myFunc(3);
- A:
2
4
and3
6
- B:
2
NaN
and3
NaN
- C:
2
Error
and3
6
- D:
2
4
and3
Error
答案
答案:A
首先我們不傳遞任何參數(shù)調用 myFunc()
。因為我們沒有傳遞參數(shù),num
和 value
獲取它們各自的默認值:num 為 2
,而 value
為函數(shù) add
的返回值。對于函數(shù) add
,我們傳遞值為 2 的 num
作為參數(shù)。函數(shù) add
返回 4
作為 value
的值。
然后,我們調用 myFunc(3)
并傳遞值 3
參數(shù) num
的值。我們沒有給 value
傳遞值。因為我們沒有給參數(shù) value
傳遞值,它獲取默認值:函數(shù) add
的返回值。對于函數(shù) add
,我們傳遞值為 3 的 num
給它。函數(shù) 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
數(shù)組中對象的屬性 members
中的每一項,我們需要將 teams[i].members
傳遞給 Generator 函數(shù) getMembers
。Generator 函數(shù)返回一個 generator 對象。為了遍歷這個 generator 對象中的每一項,我們需要使用 yield*
.
如果我們沒有寫 yield
,return yield
或者 return
,整個 Generator 函數(shù)不會第一時間 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
函數(shù) addHobby
接受兩個參數(shù),hobby
和有著對象 person
中數(shù)組 hobbies
默認值的 hobbies
。
首相,我們調用函數(shù) addHobby
,并給 hobby
傳遞 "running"
以及給 hobbies
傳遞一個空數(shù)組。因為我們給 hobbies
傳遞了空數(shù)組,"running"
被添加到這個空數(shù)組。
然后,我們調用函數(shù) addHobby
,并給 hobby
傳遞 "dancing"
。我們不向 hobbies
傳遞值,因此它獲取其默認值 —— 對象 person
的 屬性 hobbies
。我們向數(shù)組 person.hobbies
push dancing
。
最后,我們調用函數(shù) addHobby
,并向 hobby
傳遞 值 "baking"
,并且向 hobbies
傳遞 person.hobbies
。我們向數(shù)組 person.hobbies
push dancing
。
pushing dancing
和 baking
之后,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
我們創(chuàng)建了類 Flamingo
的實例 pet
。當我們實例化這個實例,Flamingo
中的 constructor
被調用。首相,輸出 "I'm pink. ??"
,之后我們調用super()
。super()
調用父類的構造函數(shù),Bird
。Bird
的構造函數(shù)被調用,并輸出 "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
關鍵字意味著我們不能 重定義 變量中的值,它 僅可讀。然而,值本身不可修改。數(shù)組 emojis
中的值可被修改,如 push 新的值,拼接,又或者將數(shù)組的長度設置為 0。
144. 我們需要向對象 person
添加什么,以致執(zhí)行 [...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]() { yield* Object.values(this) }
- D:
*[Symbol.iterator]() { for (let x in this) yield this }
答案
答案:C
對象默認并不是可迭代的。如果迭代規(guī)則被定義,則一個對象是可迭代的(An iterable is an iterable if the iterator protocol is present)。我們可以通過添加迭代器 symbol [Symbol.iterator]
來定義迭代規(guī)則,其返回一個 generator 對象,比如說構建一個 generator 函數(shù) *[Symbol.iterator]() {}
。如果我們想要返回數(shù)組 ["Lydia Hallie", 21]
: yield* Object.values(this)
,這個 generator 函數(shù)一定要 yield 對象 person
的Object.values
。
145. 輸出什么?
let count = 0; const nums = [0, 1, 2, 3]; nums.forEach(num => { if (num) count += 1 }) console.log(count)
- A: 1
- B: 2
- C: 3
- D: 4
答案
答案:C
在 forEach
循環(huán)內(nèi)部的 if
會判斷 num
的值是 truthy 或者是 falsy。因為 nums
數(shù)組的第一個數(shù)字是 0
,一個 falsy 值,if
語句代碼塊不會被執(zhí)行。count
僅僅在 nums
數(shù)組的其他 3 個數(shù)字 1
,2
,3
時加 1。因為 count
執(zhí)行了 3 次加 1
運算,所以 count
的值為 3
。
146. 輸出是什么?
function getFruit(fruits) { console.log(fruits?.[1]?.[1]) } getFruit([['??', '??'], ['??']]) getFruit() getFruit([['??'], ['??', '??']])
- A:
null
,undefined
, ?? - B:
[]
,null
, ?? - C:
[]
,[]
, ?? - D:
undefined
,undefined
, ??
答案
答案:D
?
允許我們?nèi)ミx擇性地訪問對象內(nèi)部更深層的嵌套屬性。我們嘗試打印 fruits
數(shù)組索引值為 1
的子數(shù)組內(nèi)部的索引值為 1
的元素。如果在 fruits
數(shù)組索引值 為 1
的位置不存在元素,會直接返回 undefined
。如果 fruits
數(shù)組在索引值為 1
的位置存在元素,但是子數(shù)組在索引值為 1
的位置不存在元素,也會返回 undefined
。
首先,我們嘗試打印 [['??', '??'], ['??']]
的子數(shù)組 ['??']
的第 2 個元素。這個子數(shù)組只包含一個元素,也就意味著在索引值為 1
的位置不存在元素,所以返回的是 undefined
。
其次,我們在沒有傳入任何參數(shù)調用了 getFruits
函數(shù),也就意味著形參 fruits
的默認值為undefined
。因為我們選擇性地鏈接了 fruits
在索引值為 1
的元素,因為在索引值為 1
的位置不存在元素,因此返回的是 undefined
。
最后,我們嘗試打印 ['??'], ['??', '??']
的子數(shù)組 ['??', '??']
的第 2 個元素。子數(shù)組索引值為 1
的位置為 ??
,因此它被打印出了。
147. 輸出什么?
class Calc { constructor() { this.count = 0 } increase() { this.count++ } } const calc = new Calc() new Calc().increase() console.log(calc.count)
- A:
0
- B:
1
- C:
undefined
- D:
ReferenceError
答案
答案:A
我們設置 calc
變量為 Calc
類的一個新實例。然后,我們初始化一個 Calc
的新實例,而且調用了這個實例的 increase
方法。因為 count 屬性是在 Calc
class 的 constructor 內(nèi)部的,所以 count 屬性不會在 Calc
的原型鏈上共享出去。這就意味著 calc 實例的 count 值不會被更新,count 仍然是 0
。
148. 輸出什么?
const user = { email: "e@mail.com", password: "12345" } const updateUser = ({ email, password }) => { if (email) { Object.assign(user, { email }) } if (password) { user.password = password } return user } const updatedUser = updateUser({ email: "new@email.com" }) console.log(updatedUser === user)
- A:
false
- B:
true
- C:
TypeError
- D:
ReferenceError
答案
答案:B
updateUser
函數(shù)更新 user 的 email
和 password
屬性的值,如果它們的值傳入函數(shù),函數(shù)返回的就是 user
對象。updateUser
函數(shù)的返回值是 user
對象,意味著 updatedUser 的值與 user
指向的是同一個 user
對象。updatedUser === user
為 true
.
149. 輸出什么?
const fruit = ['??', '??', '??'] fruit.slice(0, 1) fruit.splice(0, 1) fruit.unshift('??') console.log(fruit)
- A:
['??', '??', '??']
- B:
['??', '??']
- C:
['??', '??', '??']
- D:
['??', '??', '??', '??']
答案
答案:C
首先,我們在 fruit 數(shù)組上調用 slice
方法。slice 方法不會修改原始數(shù)組,但是會返回從數(shù)組切片下來的值:香蕉 emoji。 其次,我們在 fruit 數(shù)組上調用 splice
方法。splice 方法會修改原始數(shù)組,也就意味著 fruit 數(shù)組此時為 ['??', '??']
。 最后,我們在 fruit 數(shù)組上調用 unshift
方法,通過添加一個值的方式改變了原始數(shù)組,添加的是'??',它成為了數(shù)組的第一個元素?,F(xiàn)在 fruit 數(shù)組的組成為 ['??', '??', '??']
。
150. 輸出什么?
const animals = {}; let dog = { emoji: '??' } let cat = { emoji: '??' } animals[dog] = { ...dog, name: "Mara" } animals[cat] = { ...cat, name: "Sara" } console.log(animals[dog])
- A:
{ emoji: "??", name: "Mara" }
- B:
{ emoji: "??", name: "Sara" }
- C:
undefined
- D:
ReferenceError
答案
答案:B
對象的鍵會被轉換為字符串。
因為 dog
的值是一個對象,animals[dog]
實際上意味著我們創(chuàng)建了一個叫做 "object Object"
的屬性來代表新的對象。animals["object Object"]
現(xiàn)在等于 { emoji: "??", name: "Mara"}
。
cat
也是一個對象,animals[cat]
實際上意味著我們在用新的 cat 的屬性覆蓋 animals[
"
object Object
"
]
的值。
打印 animals[dog]
,實際上是animals["object Object"]
,這是因為轉化dog
對象為一個字符串結果 "object Object"
,所以返回 { emoji: "??", name: "Sara" }
。
151. 輸出什么?
const user = { email: "my@email.com", updateEmail: email => { this.email = email } } user.updateEmail("new@email.com") console.log(user.email)
- A:
my@email.com
- B:
new@email.com
- C:
undefined
- D:
ReferenceError
答案
答案:A
updateEmail
函數(shù)是一個箭頭函數(shù),它沒有和 user
對象綁定。這就意味著 this
關鍵字不會引用到 user
對象,但是會引用到全局對象。user
對象內(nèi)部的 email
的值不會更新。當打印 user.email
的時候,原始值 my@email.com
被返回。
152. 輸出什么?
const promise1 = Promise.resolve('First') const promise2 = Promise.resolve('Second') const promise3 = Promise.reject('Third') const promise4 = Promise.resolve('Fourth') const runPromises = async () => { const res1 = await Promise.all([promise1, promise2]) const res2 = await Promise.all([promise3, promise4]) return [res1, res2] } runPromises() .then(res => console.log(res)) .catch(err => console.log(err))
- A:
[['First', 'Second'], ['Fourth']]
- B:
[['First', 'Second'], ['Third', 'Fourth']]
- C:
[['First', 'Second']]
- D:
'Third'
答案
答案:D
Promise.all
方法可以并行式運行 promise。如果其中一個 promise 失敗了,Promise.all
方法會帶上被 reject 的 promise 的值rejects。在這個例子中,promise3
帶著 "Third"
值 reject。我們在調用 runPromises
時在 runPromises
函數(shù)內(nèi)部的 catch
方法去捕獲任意 error 從而捕獲到被 reject 的值。因為 promise3
帶著 "Third"
被 reject,所以只有 "Third"
打印。
153. 哪個作為method
的值可以打印{ name: "Lydia", age: 22 }
?
const keys = ["name", "age"] const values = ["Lydia", 22] const method = /* ?? */ Object[method](keys.map((_, i) => { return [keys[i], values[i]] })) // { name: "Lydia", age: 22 }
- A:
entries
- B:
values
- C:
fromEntries
- D:
forEach
答案
答案:C
fromEntries
方法可以將二維數(shù)組轉換為對象。在每個子數(shù)組的第一個元素是 key,在每個子數(shù)組的第二個元素是 value。在這個例子中,我們映射了 keys
數(shù)組,它返回了一個數(shù)組,數(shù)組的第一個元素為 keys 數(shù)組當前索引的值,第二個元素為 values 數(shù)組當前索引的值。
這樣就創(chuàng)建了一個包含正確 keys 和 values 的子數(shù)組的數(shù)組,因此結果為{ name: "Lydia", age: 22 }
。
154. 輸出什么?
const createMember = ({ email, address = {}}) => { const validEmail = /.+\@.+\..+/.test(email) if (!validEmail) throw new Error("Valid email pls") return { email, address: address ? address : null } } const member = createMember({ email: "my@email.com" }) console.log(member)
- A:
{ email: "my@email.com", address: null }
- B:
{ email: "my@email.com" }
- C:
{ email: "my@email.com", address: {} }
- D:
{ email: "my@email.com", address: undefined }
答案
答案:C
address
的默認值是一個空對象 {}
。當我們設置 member
變量為 createMember
函數(shù)返回的對象,我們沒有為 address 參數(shù)傳值,意味著 address 的值為默認的空對象 {}
。一個空對象是一個 truthy 值,意味著 address ? address : null
條件會返回 true
。address 的值為空對象 {}
。
155. 輸出什么?
let randomValue = { name: "Lydia" } randomValue = 23 if (!typeof randomValue === "string") { console.log("It's not a string!") } else { console.log("Yay it's a string!") }
- A:
It's not a string!
- B:
Yay it's a string!
- C:
TypeError
- D:
undefined
答案
答案:B
if
語句的條件判斷 !typeof randomValue
的值是否等于 "string"
。!
操作符將這個值轉化為一個布爾值。如果值是 truthy 的話,返回值會是 false
,如果值是 falsy,返回值會是 true
。在這里,typeof randomValue
的返回值是一個 truthy 值 "number"
,意味著 !typeof randomValue
的值是一個布爾值 false
。
!typeof randomValue === "string"
總是返回 false,因為我們實際上是在執(zhí)行 false === "string"
。因為條件返回的是 false
,所以 else
語句中的代碼塊會被運行,因此打印 Yay it's a string!
。
相關文章
javascript(jquery)利用函數(shù)修改全局變量的代碼
現(xiàn)在博客系統(tǒng)的評論遇到一個問題,用戶點擊“最后一頁”鏈接之后就自動調取最后一頁的資料來顯示。2009-11-11JavaScript高仿支付寶倒計時頁面及代碼實現(xiàn)
在支付寶上我們經(jīng)常會見到支付寶倒計時功能,倒計時應用非常廣泛,下文給大家介紹js制作支付寶倒計時功能,但是里面涉及到,倒計時,彈框,以及字體圖的相關知識,感興趣的朋友一起看看吧2016-10-10