「JS-错题」JS自测清单(一),那些我做错的题
# JS 自测清单(一)
答案在问题下方的折叠部分,点击即可展开问题。祝你好运 ❤️
# 错题1
# 输出是什么?
function sayHi() {
console.log(name)
console.log(age)
var name = 'Lydia'
let age = 21
}
sayHi()
2
3
4
5
6
7
8
- A:
Lydia
和undefined
- B:
Lydia
和ReferenceError
- C:
ReferenceError
和21
- D:
undefined
和ReferenceError
答案
答案: D
在函数内部,我们首先通过 var
关键字声明了 name
变量。这意味着变量被提升了(内存空间在创建阶段就被设置好了),直到程序运行到定义变量位置之前默认值都是 undefined
。因为当我们打印 name
变量时还没有执行到定义变量的位置,因此变量的值保持为 undefined
。
通过 let
和 const
关键字声明的变量也会提升,但是和 var
不同,它们不会被初始化。在我们声明(初始化)之前是不能访问它们的。这个行为被称之为暂时性死区。当我们试图在声明之前访问它们时,JavaScript 将会抛出一个 ReferenceError
错误。
# 错题2
# 输出是什么?
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1)
}
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1)
}
2
3
4
5
6
7
- A:
0 1 2
和0 1 2
- B:
0 1 2
和3 3 3
- C:
3 3 3
和0 1 2
答案
答案: C
由于 JavaScript 的事件循环,setTimeout
回调会在遍历结束后才执行。因为在第一个遍历中遍历 i
是通过 var
关键字声明的,所以这个值是全局作用域下的。在遍历过程中,我们通过一元操作符 ++
来每次递增 i
的值。当 setTimeout
回调执行的时候,i
的值等于 3。
在第二个遍历中,遍历 i
是通过 let
关键字声明的:通过 let
和 const
关键字声明的变量是拥有块级作用域(指的是任何在 {} 中的内容)。在每次的遍历过程中,i
都有一个新值,并且每个值都在循环内的作用域中。
# 错题3
# 输出是什么?
const shape = {
radius: 10,
diameter() {
return this.radius * 2
},
perimeter: () => 2 * Math.PI * this.radius,
}
shape.diameter()
shape.perimeter()
2
3
4
5
6
7
8
9
10
- A:
20
and62.83185307179586
- B:
20
andNaN
- C:
20
and63
- D:
NaN
and63
答案
答案: B
注意 diameter
的值是一个常规函数,但是 perimeter
的值是一个箭头函数。
对于箭头函数,this
关键字指向的是它当前周围作用域(简单来说是包含箭头函数的常规函数,如果没有常规函数的话就是全局对象),这个行为和常规函数不同。这意味着当我们调用 perimeter
时,this
不是指向 shape
对象,而是它的周围作用域(在例子中是 window
)。
在 window
中没有 radius
这个属性,因此返回 undefined
。
# 错题4
# 输出是什么?
;+true
!'Lydia'
2
- A:
1
andfalse
- B:
false
andNaN
- C:
false
and `false
答案
答案: A
一元操作符加号尝试将 bool 转为 number。true
转换为 number 的话为 1
,false
为 0
。
字符串 'Lydia'
是一个真值,真值取反那么就返回 false
。
# 错题5
# 哪一个是正确的?
const bird = {
size: 'small',
}
const mouse = {
name: 'Mickey',
small: true,
}
2
3
4
5
6
7
8
- A:
mouse.bird.size
是无效的 - B:
mouse[bird.size]
是无效的 - C:
mouse[bird["size"]]
是无效的 - D: 以上三个选项都是有效的
答案
答案:A
在 JavaScript 中,所有对象的 keys 都是字符串(除非对象是 Symbol)。尽管我们可能不会定义它们为字符串,但它们在底层总会被转换为字符串。
当我们使用括号语法时([]),JavaScript 会解释(或者 unboxes)语句。它首先看到第一个开始括号 [
并继续前进直到找到结束括号 ]
。只有这样,它才会计算语句的值。
mouse[bird.size]
:首先计算 bird.size
,这会得到 small
。mouse["small"]
返回 true
。
然后使用点语法的话,上面这一切都不会发生。mouse
没有 bird
这个 key,这也就意味着 mouse.bird
是 undefined
。然后当我们使用点语法 mouse.bird.size
时,因为 mouse.bird
是 undefined
,这也就变成了 undefined.size
。这个行为是无效的,并且会抛出一个错误类似 Cannot read property "size" of undefined
。
# 错题6
# 输出是什么?
let c = { greeting: 'Hey!' }
let d
d = c
c.greeting = 'Hello'
console.log(d.greeting)
2
3
4
5
6
- 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)
2
3
4
5
6
7
- 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')
2
3
4
5
6
7
8
9
10
11
12
13
- A:
orange
- B:
purple
- C:
green
- D:
TypeError
答案
答案: D
colorChange
是一个静态方法。静态方法被设计为只能被创建它们的构造器使用(也就是 Chameleon
),并且不能传递给实例。因为 freddie
是一个实例,静态方法不能被实例使用,因此抛出了 TypeError
错误。
# 错题9
# 输出是什么?
let greeting
greetign = {} // Typo!
console.log(greetign)
2
3
- 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'
2
3
4
5
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())
2
3
4
5
6
7
8
9
10
11
- A:
TypeError
- B:
SyntaxError
- C:
Lydia Hallie
- D:
undefined
undefined
答案
答案: A
一元操作符加号尝试将 bool 转为 number。true
转换为 number 的话为 1
,false
为 0
。
字符串 'Lydia'
是一个真值,真值取反那么就返回 false
。
# 错题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)
2
3
4
5
6
7
8
9
10
- A:
Person {firstName: "Lydia", lastName: "Hallie"}
andundefined
- B:
Person {firstName: "Lydia", lastName: "Hallie"}
andPerson {firstName: "Sarah", lastName: "Smith"}
- C:
Person {firstName: "Lydia", lastName: "Hallie"}
and{}
- D:
Person {firstName: "Lydia", lastName: "Hallie"}
andReferenceError
答案
答案: A
对于 sarah
,我们没有使用 new
关键字。当使用 new
时,this
引用我们创建的空对象。当未使用 new
时,this
引用的是全局对象(global object)。
我们说 this.firstName
等于 "Sarah"
,并且 this.lastName
等于 "Smith"
。实际上我们做的是,定义了 global.firstName = 'Sarah'
和 global.lastName = 'Smith'
。而 sarah
本身是 undefined
。:::
# 错题13
# 事件传播的三个阶段是什么?
- A: Target > Capturing > Bubbling
- B: Bubbling > Target > Capturing
- C: Target > Bubbling > Capturing
- D: Capturing > Target > Bubbling
答案
答案: D
在捕获(capturing)阶段中,事件从祖先元素向下传播到目标元素。当事件达到目标(target)元素后,冒泡(bubbling)才开始。
# 错题14
# 所有对象都有原型。
- A: 对
- B: 错
答案
答案: B
除了基本对象(base object),所有对象都有原型。基本对象可以访问一些方法和属性,比如 .toString
。这就是为什么你可以使用内置的 JavaScript 方法!所有这些方法在原型上都是可用的。虽然 JavaScript 不能直接在对象上找到这些方法,但 JavaScript 会沿着原型链找到它们,以便于你使用。
# 错题15
# 输出是什么?
function sum(a, b) {
return a + b
}
sum(1, '2')
2
3
4
5
- A:
NaN
- B:
TypeError
- C:
"12"
- D:
3
答案
答案: C
JavaScript 是一种动态类型语言:我们不指定某些变量的类型。值可以在你不知道的情况下自动转换成另一种类型,这种类型称为隐式类型转换(implicit type coercion)。Coercion 是指将一种类型转换为另一种类型。
在本例中,JavaScript 将数字 1
转换为字符串,以便函数有意义并返回一个值。在数字类型(1
)和字符串类型('2'
)相加时,该数字被视为字符串。我们可以连接字符串,比如 "Hello" + "World"
,这里发生的是 "1" + "2"
,它返回 "12"
。