这45道面试可能被问到的JS判断题!你能答对几道?

语言: CN / TW / HK

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。


前言

先想一想再看答案哟~

第1题

输出是什么?

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

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

⏳ 点击查看答案 > 答案:4 在函数内部,我们首先通过 `var` 关键字声明了 `name` 变量。这意味着变量被提升了(内存空间在创建阶段就被设置好了),直到程序运行到定义变量位置之前默认值都是 `undefined`。因为当我们打印 `name` 变量时还没有执行到定义变量的位置,因此变量的值保持为 `undefined`。 通过 `let` 和 `const` 关键字声明的变量也会提升,但是和 `var` 不同,它们**不会被初始化**。在我们声明(初始化)之前是不能访问它们的。这个行为被称之为暂时性死区。当我们试图在声明之前访问它们时,JavaScript 将会抛出一个 `ReferenceError` 错误。

第2题

下面那个选项将会返回 '6' ?

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

⏳ 点击查看答案 > 答案:3 通过展开操作符 `...`,我们可以 _暂开_ 单个可迭代的元素。函数 `sumValues` function 接收三个参数: `x`, `y` 和 `z`。`...[1, 2, 3]` 的执行结果为 `1, 2, 3`,将会传递给函数 `sumValues`。

第3题

哪一个方法会返回 'Hello world!' ?

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

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

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

⏳ 点击查看答案 > 答案:2 当通过 `set` 方法添加一个键值对,一个传递给 `set`方法的参数将会是键名,第二个参数将会是值。在这个case里,键名为 _函数_ `() => 'greeting'`,值为`'Hello world'`。 `myMap` 现在就是 `{ () => 'greeting' => 'Hello world!' }`。 1 是错的,因为键名不是 `'greeting'` 而是 `() => 'greeting'`。 3 是错的,因为我们给`get` 方法传递了一个新的函数。对象受 _引用_ 影响。函数也是对象,因此两个函数严格上并不等价,尽管他们相同:他们有两个不同的内存引用地址。

第4题

setInterval 方法的返回值是什么?

javascript setInterval(() => console.log('Hi'), 1000) 1. 一个唯一的id 2. 该方法指定的毫秒数 3. 传递的函数 4. undefined

⏳ 点击查看答案 > 答案:1 `setInterval` 返回一个唯一的 id。此 id 可被用于 `clearInterval` 函数来取消定时。

第5题

输出什么?

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

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

⏳ 点击查看答案 > 答案:2 `if` 语句的条件判断 `!typeof randomValue` 的值是否等于 `"string"`。 `!` 操作符将这个值转化为一个布尔值。如果值是truthy的话,返回值会是 `false`,如果值是falsy,返回值会是 `true`。在这里, `typeof randomValue` 的返回值是一个truthy值 `"number"`,意味着 `!typeof randomValue` 的值是一个布尔值 `false`。 `!typeof randomValue === "string"` 总是返回false,因为我们实际上是在执行 `false === "string"`。因为条件返回的是 `false`,所以 `else` 语句中的代码块会被运行,因此打印 `Yay it's a string!` 。

第6题

输出什么?

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

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

}

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

⏳ 点击查看答案 > 答案:3 `address` 的默认值是一个空对象 `{}`。当我们设置 `member` 变量为 `createMember` 函数返回的对象,我们没有为address参数传值,意味着address的值为默认的空对象 `{}`。一个空对象是一个truthy值,意味着 `address ? address : null` 条件会返回 `true`。address的值为空对象 `{}`。

第7题

method 的值选择哪个时,会输出 { name: "Lydia", age: 22 } ?

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

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

⏳ 点击查看答案 > 答案:3 `fromEntries` 方法可以将二维数组转换为对象。在每个子数组的第一个元素是key,在每个子数组的第二个元素是value。在这个例子中,我们映射了 `keys` 数组,它返回了一个数组,数组的第一个元素为keys数组当前索引的值,第二个元素为values数组当前索引的值。 这样就创建了一个包含正确keys和values的子数组的数组,因此结果为`{ name: "Lydia", age: 22 }`。

第8题

输出什么?

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

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

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

⏳ 点击查看答案 > 答案:4 `Promise.all` 方法可以并行式运行promise。如果其中一个promise失败了,`Promise.all` 方法会带上被reject的promise的值_rejects_。在这个例子中, `promise3` 带着 `"Third"` 值reject。我们在调用 `runPromises` 时在 `runPromises` 函数内部的 `catch` 方法去捕获任意error从而捕获到被reject的值。因为 `promise3` 带着 `"Third"` 被reject,所以只有 `"Third"` 打印。

第9题

输出什么?

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

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

⏳ 点击查看答案 > 答案:1 `updateEmail` 函数是一个箭头函数,它没有和 `user` 对象绑定。这就意味着 `this` 关键字不会引用到 `user` 对象,但是会引用到全局对象。 `user` 对象内部的 `email` 的值不会更新。当打印 `user.email` 的时候, 原始值 `[email protected]` 被返回。

第10题

输出什么?

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

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

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

⏳ 点击查看答案 > 答案:2 对象的键会被转换为字符串。 因为 `dog` 的值是一个对象, `animals[dog]` 实际上意味着我们创建了一个叫做 `"object Object"` 的属性来代表新的对象。 `animals["object Object"]` 现在等于 `{ emoji: "🐶", name: "Mara"}`。 `cat` 也是一个对象,`animals[cat]` 实际上意味着我们在用新的cat的属性覆盖 `animals[``"``object Object``"``]` 的值。 打印 `animals[dog]`,实际上是`animals["object Object"]`,这是因为转化`dog`对象为一个字符串结果 `"object Object"` ,所以返回 `{ emoji: "🐈", name: "Sara" }`。

第11题

输出什么?

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

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

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

⏳ 点击查看答案 > 答案:3 首先,我们在fruit数组上调用 `slice` 方法。 slice方法不会修改原始数组,但是会返回从数组切片下来的值:香蕉emoji。 其次,我们在fruit数组上调用 `splice` 方法。 splice方法会修改原始数组,也就意味着fruit数组此时为 `['🍊', '🍎']`。 最后,我们在fruit数组上调用 `unshift` 方法,通过添加一个值的方式改变了原始数组,添加的是'🍇',它成为了数组的第一个元素。现在fruit数组的组成为 `['🍇', '🍊', '🍎']`。

第12题

输出什么?

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

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

if (password) {
    user.password = password
}

return user

}

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

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

⏳ 点击查看答案 > 答案:2 `updateUser` 函数更新user的 `email` 和 `password` 属性的值, 如果它们的值传入函数, 函数返回的就是 `user` 对象。 `updateUser` 函数的返回值是 `user` 对象,意味着updatedUser的值与 `user` 指向的是同一个 `user` 对象。`updatedUser === user` 为 `true`.

第13题

输出什么?

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

increase() {
    this.count ++
}

}

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

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

⏳ 点击查看答案 > 答案:1 我们设置 `calc` 变量为 `Calc` 类的一个新实例。 然后,我们初始化一个 `Calc` 的新实例,而且调用了这个实例的 `increase` 方法。因为count属性是在 `Calc` class的constructor内部的,所以count属性不会在 `Calc` 的原型链上共享出去。这就意味着calc实例的count值不会被更新,count仍然是 `0`。

第14题

输出是什么?

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

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

⏳ 点击查看答案 > 答案:4 `?` 允许我们去选择性地访问对象内部更深层的嵌套属性。 我们尝试打印 `fruits` 数组索引值为 `1` 的子数组内部的索引值为 `1` 的元素。 如果在 `fruits` 数组索引值 为 `1` 的位置不存在元素,会直接返回 `undefined`。 如果 `fruits` 数组在索引值为 `1` 的位置存在元素,但是子数组在索引值为 `1` 的位置不存在元素,也会返回 `undefined`。 首先,我们尝试打印 `[['🍊', '🍌'], ['🍍']]` 的子数组 `['🍍']` 的第2个元素。这个子数组只包含一个元素,也就意味着在索引值为 `1` 的位置不存在元素,所以返回的是 `undefined` 。 其次,我们在没有传入任何参数调用了 `getFruits` 函数,也就意味着形参 `fruits` 的默认值为`undefined`。因为我们选择性地链接了 `fruits` 在索引值为 `1` 的元素,因为在索引值为 `1` 的位置不存在元素,因此返回的是 `undefined` 。 最后,我们尝试打印 `['🍍'], ['🍊', '🍌']` 的子数组 `['🍊', '🍌']` 的第2个元素。子数组索引值为 `1`的位置为 `🍌` ,因此它被打印出了。

第15题

输出什么?

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

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

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

⏳ 点击查看答案 > 答案:3 在 `forEach` 循环内部的 `if` 会判断 `num` 的值是truthy或者是falsy。因为 `nums` 数组的第一个数字是 `0`,一个falsy值, `if` 语句代码块不会被执行。`count` 仅仅在 `nums` 数组的其他3个数字 `1`,`2`,`3` 时加1。因为 `count` 执行了3次加 `1` 运算,所以 `count` 的值为 `3`。

第16题

向对象 person 添加什么时,可以通过执行 [...person] 获得类似 ["Lydia Hallie", 21] 的输出?

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

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

⏳ 点击查看答案 > 答案:3 对象默认并不是可迭代的。如果迭代规则被定义,则一个对象是可迭代的(An iterable is an iterable if the iterator protocol is present)。我们可以通过添加迭代器symbol `[Symbol.iterator]` 来定义迭代规则,其返回一个 generator 对象,比如说构建一个 generator 函数 `*[Symbol.iterator]() {}`。如果我们想要返回数组 `["Lydia Hallie", 21]`: `yield* Object.values(this)`,这个 generator 函数一定要 yield 对象 `person` 的`Object.values`。

第17题

哪一个选项会导致报错?

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

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

⏳ 点击查看答案 > 答案:4 `const` 关键字意味着我们不能 _重定义_ 变量中的值,它 _仅可读_。而然,值本身不可修改。数组 `emojis` 中的值可被修改,如 push 新的值, 拼接,又或者将数组的长度设置为0。

第18题

输出什么?

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

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

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

⏳ 点击查看答案 > 答案:2 我们创建了类 `Flamingo` 的实例 `pet`。当我们实例化这个实例,`Flamingo` 中的 `constructor` 被调用。首相,输出 `"I'm pink. 🌸"`, 之后我们调用`super()`。`super()` 调用父类的构造函数,`Bird`。`Bird` 的构造函数被调用,并输出 `"I'm a bird. 🦢"`。

第19题

输出什么?

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

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

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

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

⏳ 点击查看答案 > 答案:3 函数 `addHobby` 接受两个参数,`hobby` 和有着对象 `person` 中数组 `hobbies` 默认值的 `hobbies`。 首相,我们调用函数 `addHobby`,并给 `hobby` 传递 `"running"` 以及给 `hobbies` 传递一个空数组。因为我们给 `hobbies` 传递了空数组,`"running"` 被添加到这个空数组。 然后,我们调用函数 `addHobby`,并给 `hobby` 传递 `"dancing"`。我们不向 `hobbies` 传递值,因此它获取其默认值 —— 对象 `person` 的 属性 `hobbies`。我们向数组 `person.hobbies` push `dancing`。 最后,我们调用函数 `addHobby`,并向 `hobby` 传递 值 `"bdaking"`,并且向 `hobbies` 传递 `person.hobbies`。我们向数组 `person.hobbies` push `dancing`。 pushing `dancing` 和 `baking` 之后,`person.hobbies` 的值为 `["coding", "dancing", "baking"]`

第20题

选择哪一个?

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

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

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

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

⏳ 点击查看答案 > 答案:2 为了遍历 `teams` 数组中对象的属性 `members` 中的每一项,我们需要将 `teams[i].members` 传递给 Generator 函数 `getMembers`。Generator 函数返回一个 generator 对象。为了遍历这个 generator 对象中的每一项,我们需要使用 `yield*`. 如果我们没有写 `yield`,`return yield` 或者 `return`,整个 Generator 函数不会第一时间 return 当我们调用 `next` 方法.

第21题

输出什么?

```javascript class Counter { #number = 10

increment() { this.#number++ }

getNum() { return this.#number } }

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

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

⏳ 点击查看答案 > 答案:4 在 ES2020 中,通过 `#` 我们可以给 class 添加私有变量。在 class 的外部我们无法获取该值。当我们尝试输出 `counter.#number`,语法错误被抛出:我们无法在 class `Counter` 外部获取它!

第22题

输出什么?

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

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

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

⏳ 点击查看答案 > 答案:1 首先我们不传递任何参数调用 `myFunc()`。因为我们没有传递参数,`num` 和 `value` 获取它们各自的默认值:num 为 `2`, 而 `value` 为函数 `add` 的返回值。对于函数 `add`,我们传递值为2的 `num` 作为参数。函数 `add` 返回 `4` 作为 `value` 的值。 然后,我们调用 `myFunc(3)` 并传递值 `3` 参数 `num` 的值。我们没有给 `value` 传递值。因为我们没有给参数 `value` 传递值,它获取默认值:函数 `add` 的返回值。对于函数 `add`,我们传递值为3的 `num`给它。函数 `add` 返回 `6` 作为 `value` 的值。

第23题

以下哪一项会对对象 person 有副作用?

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

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

⏳ 点击查看答案 > 答案:3 使用方法 `Object.freeze` 对一个对象进行 _冻结_。不能对属性进行添加,修改,删除。 然而,它仅 对对象进行 _浅_ 冻结,意味着只有 对象中的 _直接_ 属性被冻结。如果属性是另一个 object,像案例中的 `address`,`address` 中的属性没有被冻结,仍然可以被修改。

第24题

以下哪一项会对对象 person 有副作用?

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

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

⏳ 点击查看答案 > 答案:1 使用 `Object.seal` 我们可以防止新属性 _被添加_,或者存在属性 _被移除_. 然而,你仍然可以对存在属性进行更改。

第25题

输出什么?

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

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

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

⏳ 点击查看答案 > 答案:3 使用 Proxy 对象,我们可以给一个对象添加自定义行为。在这个 case,我们传递一个包含以下属性的对象 `handler` : `set` and `get`。每当我们 _设置_ 属性值时 `set` 被调用,每当我们 _获取_ 时 `get` 被调用。 第一个参数是一个空对象 `{}`,作为 `person` 的值。对于这个对象,自定义行为被定义在对象 `handler`。如果我们向对象 `person` 添加属性,`set` 将被调用。如果我们获取 `person` 的属性, `get` 将被调用。 首先,我们向 proxy 对象(`person.name = "Lydia"`)添加一个属性 `name`。`set` 被调用并输出 `"Added a new property!"`。 然后,我们获取 proxy 对象的一个属性,对象 handler 的属性 `get` 被调用。输出 `"Accessed a property!"`。

第26题

怎样能在 index.js 中调用 sum.js 中的 sum 方法?

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

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

⏳ 点击查看答案 > 答案:3 使用符号 `*`,我们引入文件中的所有值,包括默认和具名。如果我们有以下文件: ```javascript // info.js export const name = "Lydia"; export const age = 21; export default "I love JavaScript"; // index.js import * as info from "./info"; console.log(info); ``` 将会输出以下内容: ```javascript { default: "I love JavaScript", name: "Lydia", age: 21 } ``` 以 `sum` 为例,相当于以下形式引入值 `sum`: ```javascript { default: function sum(x) { return x + x } } ``` 我们可以通过调用 `sum.default` 来调用该函数

第27题

输出什么?

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

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

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

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

⏳ 点击查看答案 > 答案:4 首先,我们调用 `funcOne`。在函数 `funcOne` 的第一行,我们调用`myPromise` promise _异步操作_。当JS引擎在忙于执行 promise,它继续执行函数 `funcOne`。下一行 _异步操作_ `setTimeout`,其回调函数被 Web API 调用。 (详情请参考我关于event loop的文章.) promise 和 timeout 都是异步操作,函数继续执行当JS引擎忙于执行promise 和 处理 `setTimeout` 的回调。相当于 `Last line!` 首先被输出, 因为它不是异步操作。执行完 `funcOne` 的最后一行,promise 状态转变为 resolved,`Promise!` 被打印。然而,因为我们调用了 `funcTwo()`, 调用栈不为空,`setTimeout` 的回调仍不能入栈。 我们现在处于 `funcTwo`,先 _awaiting_ myPromise。通过 `await` 关键字, 我们暂停了函数的执行直到 promise 状态变为 resolved (或 rejected)。然后,我们输出 `res` 的 awaited 值(因为 promise 本身返回一个 promise)。 接着输出 `Promise!`。 下一行就是 _异步操作_ `setTimeout`,其回调函数被 Web API 调用。 我们执行到函数 `funcTwo` 的最后一行,输出 `Last line!`。现在,因为 `funcTwo` 出栈,调用栈为空。在事件队列中等待的回调函数(`() => console.log("Timeout!")` from `funcOne`, and `() => console.log("Timeout!")` from `funcTwo`)以此入栈。第一个回调输出 `Timeout!`,并出栈。然后,第二个回调输出 `Timeout!`,并出栈。得到结果 `Last line! Promise! Promise! Last line! Timeout! Timeout!`

第28题

输出什么?

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

increment() {
    this.count++;
}

}

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

const counterTwo = counterOne; counterTwo.increment();

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

⏳ 点击查看答案 > 答案:4 `counterOne` 是类 `Counter` 的一个实例。类 Counter 包含一个`count` 属性在它的构造函数里, 和一个 `increment` 方法。首先,我们通过 `counterOne.increment()` 调用方法 `increment` 两次。现在, `counterOne.count` 为 `2`. 然后,我们创建一个新的变量 `counterTwo` 并将 `counterOne` 的引用地址赋值给它。因为对象受引用地址的影响,我们刚刚创建了一个新的对象,其引用地址和 `counterOne` 的等价。因此它们指向同一块内存地址,任何对其的副作用都会影响 `counterTwo`。现在 `counterTwo.count` 为 `2`。 我们调用 `counterTwo.increment()` 将 `count` 的值设为 `3`。然后,我们打印 `counterOne` 里的count,结果为 `3`。

第29题

输出什么?

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

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

⏳ 点击查看答案 > 答案:2 通过方法 `flat`, 我们可以创建一个新的, 已被扁平化的数组。被扁平化的深度取决于我们传递的值。在这个case里,我们传递了值 `1` (并不必要,这是默认值),相当于只有第一层的数组才会被连接。即这个 case 里的 `['🥑']` and `['✨', '✨', ['🍕', '🍕']]`。连接这两个数组得到结果 `['🥑', '✨', '✨', ['🍕', '🍕']]`.

第30题

输出什么?

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

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

⏳ 点击查看答案 > 答案:3 在 `try` 块区,我们打印 `myPromise` 变量的 awaited 值: `"Woah some cool data"`。因为`try` 块区没有错误抛出,`catch` 块区的代码并不执行。`finally` 块区的代码 _总是_ 执行,`"Oh finally!"` 被输出。

第31题

输出什么?

```javascript const randomValue = 21;

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

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

⏳ 点击查看答案 > 答案:4 通过 `const` 关键字声明的变量在被初始化之前不可被引用:这被称之为 _暂时性死区_。在函数 `getInfo` 中, 变量 `randomValue` 声明在`getInfo` 的作用域的此法环境中。在想要对 `typeof randomValue` 进行log之前,变量 `randomValue` 仍未被初始化: 错误`ReferenceError` 被抛出! JS引擎并不会根据作用域链网上寻找该变量,因为我们已经在 `getInfo` 函数中声明了 `randomValue` 变量。

第32题

输出什么?

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

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

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

⏳ 点击查看答案 > 答案:3 通过方法 `Number.isNaN`,你可以检测你传递的值是否为 _数字值_ 并且是否等价于 `NaN`。`name` 不是一个数字值,因此 `Number.isNaN(name)` 返回 `false`。`age` 是一个数字值,但它不等价于 `NaN`,因此 `Number.isNaN(age)` 返回 `false`. 通过方法 `isNaN`, 你可以检测你传递的值是否一个 number。`name` 不是一个 `number`,因此 `isNaN(name)` 返回 `true`. `age` 是一个 `number` 因此 `isNaN(age)` 返回 `false`.

第33题

输出什么?

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

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

⏳ 点击查看答案 > 答案:2 通过解构对象们,我们可以从右手边的对象中拆出值,并且将拆出的值分配给左手边对象同名的属性。在这种情况下,我们将值 "💀" 分配给 `spookyItems[3]`。相当于我们正在篡改数组 `spookyItems`,我们给它添加了值 "💀"。当输出 `spookyItems` 时,结果为 `["👻", "🎃", "🕸", "💀"]`。

第34题

输出什么?

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

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

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

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

⏳ 点击查看答案 > 答案:2 通过方法 `Intl.NumberFormat`,我们可以格式化任意区域的数字值。我们对数字值 `130` 进行 `mile-per-hour` 作为 `unit` 的 `en-US` 区域 格式化,结果为 `130 mph`。对数字值 `300` 进行 `USD` 作为 `currentcy` 的 `en-US` 区域格式化,结果为 `$300.00`.

第35题

输出什么?

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

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

⏳ 点击查看答案 > 答案:4 `myFunc` 期望接收一个包含 `x`, `y` 和 `z` 属性的对象作为它的参数。因为我们仅仅传递三个单独的数字值 (1, 2, 3) 而不是一个含有 `x`, `y` 和 `z` 属性的对象 ({x: 1, y: 2, z: 3}), `x`, `y` 和 `z` 有着各自的默认值 `undefined`.

第36题

输出什么?

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

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

⏳ 点击查看答案 > 答案:3 我们给 函数range 传递: `Promise{1}`, `Promise{2}`, `Promise{3}`,Generator 函数 `range` 返回一个全是 async object promise 数组。我们将 async object 赋值给变量 `gen`,之后我们使用`for await ... of` 进行循环遍历。我们将返回的 Promise 实例赋值给 `item`: 第一个返回 `Promise{1}`, 第二个返回 `Promise{2}`,之后是 `Promise{3}`。因为我们正 _awaiting_ `item` 的值,resolved 状态的 promsie,promise数组的resolved _值_ 以此为: `1`,`2`,`3`.

第37题

输出什么?

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

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

⏳ 点击查看答案 > 答案:1 函数 `add` 是一个返回 返回箭头函数的箭头函数 的箭头函数(still with me?)。第一个函数接收一个值为 `4` 的参数 `x`。我们调用第二个函数,它接收一个值为 `5` 的参数 `y`。然后我们调用第三个函数,它接收一个值为 `6` 的参数 `z`。当我们尝试在最后一个箭头函数中获取 `x`, `y` 和 `z` 的值,JS 引擎根据作用域链去找 `x` 和 `y` 的值。得到 `4` `5` `6`.

第38题

输出什么?

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

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

⏳ 点击查看答案 > 答案:3 `typeof name` 返回 `"string"`。字符串 `"string"` 是一个 truthy 的值,因此 `!typeof name` 返回一个布尔值 `false`。 `false === "object"` 和 `false === "string"` 都返回 `false`。 (如果我们想检测一个值的类型,我们应该用 `!==` 而不是 `!typeof`)

第39题

输出什么?

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

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

⏳ 点击查看答案 > 答案:4 方法 `language` 是一个 `setter`。Setters 并不保存一个实际值,它们的使命在于 _修改_ 属性。当调用方法 `setter`, 返回 `undefined`。

第40题

输出什么?

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

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

⏳ 点击查看答案 > 答案:2 我们传递了一个状态 `groceries.indexOf("banana")` 给if条件语句。`groceries.indexOf("banana")` 返回 `0`, 一个 falsy 的值。因为if条件语句的状态为 falsy,`else` 块区内的代码执行,并且 `We don't have to buy bananas!` 被输出.

第41题

输出什么?

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

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

⏳ 点击查看答案 > 答案:2 通过 ES10 或 TS3.7+[可选链操作符 `?.`](http://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/%E5%8F%AF%E9%80%89%E9%93%BE),我们不再需要显式检测更深层的嵌套值是否有效。如果我们尝试获取 `undefined` 或 `null` 的值 (_nullish_),表达将会短路并返回 `undefined`. `person.pet?.name`: `person` 有一个名为 `pet` 的属性: `person.pet` 不是 nullish。它有个名为 `name` 的属性,并返回字符串 `Mara`。 `person.pet?.family?.name`: `person` 有一个名为 `pet` 的属性: `person.pet` 不是 nullish. `pet` _并没有_ 一个名为 `family` 的属性, `person.pet.family` 是 nullish。表达式返回 `undefined`。 `person.getFullName?.()`: `person` 有一个名为 `getFullName` 的属性: `person.getFullName()` 不是 nullish 并可以被调用,返回字符串 `Lydia Hallie`。 `member.getLastName?.()`: `member` is not defined: `member.getLastName()` is nullish. The expression returns `undefined`.

第42题

输出什么?

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

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

⏳ 点击查看答案 > 答案:2 通过 `+=` 操作符,我们对值 `num` 进行加 `1` 操作。 `num` 有初始值 `1`,因此 `1 + 1` 的执行结果为 `2`。数组 `list` 的第二项为 🥰,`console.log(list[2])` 输出 🥰.

第43题

输出什么?

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

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

changeAge(person) changeAgeAndName()

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

⏳ 点击查看答案 > 答案:3 函数 `changeAge` 和函数 `changeAgeAndName` 有着不同的参数,定义一个 _新_ 生成的对象 `{ ...person }`。这个对象有着所有 `person` 对象 中 k/v 值的副本。 首项, 我们调用 `changeAge` 函数并传递 `person` 对象作为它的参数。这个函数对 `age` 属性进行加一操作。`person` 现在是 `{ name: "Lydia", age: 22 }`。 然后,我们调用函数 `changeAgeAndName` ,然而我们没有传递参数。取而代之,`x` 的值等价 _new_ 生成的对象: `{ ...person }`。因为它是一个新生成的对象,它并不会对对象 `person` 造成任何副作用。`person` 仍然等价于 `{ name: "Lydia", age: 22 }`。

第44题

将会发生什么?

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

config = null ``` 1. setInterval 的回调不会被调用 2. setInterval 的回调被调用一次 3. setInterval 的回调仍然会被每秒钟调用 4. 我们从没调用过 config.alert(), config 为 null

⏳ 点击查看答案 > 答案:3 一般情况下当我们将对象赋值为 `null`, 那些对象会被进行 _垃圾回收(garbage collected)_ 因为已经没有对这些对象的引用了。然而,`setInterval`的参数是一个箭头函数(所以上下文绑定到对象 `config` 了),回调函数仍然保留着对 `config`的引用。只要存在引用,对象就不会被垃圾回收。因为没有被垃圾回收,`setInterval` 的回调每1000ms (1s)会被调用一次。

第45题

输出什么?

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

⏳ 点击查看答案 > 答案:1 带有模板字面量的表达式首先被执行。相当于字符串会包含表达式,这个立即执行函数 `(x => x)('I love')` 返回的值. 我们向箭头函数 `x => x` 传递 `'I love'` 作为参数。`x` 等价于返回的 `'I love'`。这就是结果 `I love to program`。

结语

这篇文章来自一个试验...也想验证一些东西,侵删~