JavaScript-test
答案在问题下方的折叠部分,点击即可展开
# 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
答案
# 1.1. 答案: D
在函数内部,我们首先通过 var
关键字声明了 name
变量。这意味着变量被提升了(内存空间在创建阶段就被设置好了),直到程序运行到定义变量位置之前默认值都是 undefined
。因为当我们打印 name
变量时还没有执行到定义变量的位置,因此变量的值保持为 undefined
。
通过 let
和 const
关键字声明的变量也会提升,但是和 var
不同,它们不会被初始化。在我们声明(初始化)之前是不能访问它们的。这个行为被称之为暂时性死区。当我们试图在声明之前访问它们时,JavaScript 将会抛出一个 ReferenceError
错误。
考点:
- 声明变量关键字 var、let、const 的区别
- 变量提升
# 2. 输出是什么?
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
答案
# 2.1. 答案: B
注意 diameter
的值是一个常规函数,但是 perimeter
的值是一个箭头函数。
对于箭头函数,this
关键字指向的是它当前周围作用域(简单来说是包含箭头函数的常规函数,如果没有常规函数的话就是全局对象),这个行为和常规函数不同。这意味着当我们调用 perimeter
时,this
不是指向 shape
对象,而是它的周围作用域(在例子中是 window
)。
在 window
中没有 radius
这个属性,因此返回 undefined
。
考点: 箭头函数与普通函数的 this 指向
问题
# 3. 输出是什么?
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
答案
# 3.1. 答案: C
由于 JavaScript 的事件循环,setTimeout
回调会在遍历结束后才执行。因为在第一个遍历中遍历 i
是通过 var
关键字声明的,所以这个值是全局作用域下的。在遍历过程中,我们通过一元操作符 ++
来每次递增 i
的值。当 setTimeout
回调执行的时候,i
的值等于 3。
在第二个遍历中,遍历 i
是通过 let
关键字声明的:通过 let
和 const
关键字声明的变量是拥有块级作用域(指的是任何在 {} 中的内容)。在每次的遍历过程中,i
都有一个新值,并且每个值都在循环内的作用域中。
考点: let、const 声明变量拥有块级作用域
# 4. 输出是什么?
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
答案
# 4.1. 答案: A
在 JavaScript 中,当设置两个对象彼此相等时,它们会通过引用进行交互。
首先,变量 c
的值是一个对象。接下来,我们给 d
分配了一个和 c
对象相同的引用。
因此当我们改变其中一个对象时,其实是改变了所有的对象。
考点:引用类型的存储方式
# 5. 事件传播的三个阶段是什么?
- A: Target > Capturing > Bubbling
- B: Bubbling > Target > Capturing
- C: Target > Bubbling > Capturing
- D: Capturing > Target > Bubbling
# 6. 输出是什么?
let number = 0
console.log(number++)
console.log(++number)
console.log(number)
2
3
4
- A:
1
1
2
- B:
1
2
2
- C:
0
2
2
- D:
0
1
2
答案
# 6.1. 答案: C
一元后自增运算符 ++
:
- 返回值(返回
0
) - 值自增(number 现在是
1
)
一元前自增运算符 ++
:
- 值自增(number 现在是
2
) - 返回值(返回
2
)
结果是 0 2 2
.
# 7. cool_secret 可访问多长时间?
sessionStorage.setItem('cool_secret', 123)
- A: 永远,数据不会丢失。
- B: 当用户关掉标签页时。
- C: 当用户关掉整个浏览器,而不只是关掉标签页。
- D: 当用户关闭电脑时。
答案
# 7.1. 答案: B
关闭 tab 标签页 后,sessionStorage
存储的数据才会删除。
如果使用 localStorage
,那么数据将永远在那里,除非调用了 localStorage.clear()
。
# 8. setInterval
方法的返回值是什么?
setInterval(() => console.log('Hi'), 1000)
- A: 一个唯一的 id
- B: 该方法指定的毫秒数
- C: 传递的函数
- D:
undefined
# 9. 输出是什么?
const person = {
name: 'Lydia',
age: 21
}
for (const item in person) {
console.log(item)
}
2
3
4
5
6
7
8
- A:
{ name: "Lydia" }, { age: 21 }
- B:
"name", "age"
- C:
"Lydia", 21
- D:
["name", "Lydia"], ["age", 21]
答案
# 9.1. 答案: B
在for-in
循环中,我们可以通过对象的 key 来进行迭代,也就是这里的name
和age
。在底层,对象的 key 都是字符串(如果他们不是 Symbol 的话)。在每次循环中,我们将item
设定为当前遍历到的 key.所以一开始,item
是name
,之后 item
输出的则是age
。
扩展: for-of
输出什么?
for (const item of person) {
console.log(item)
}
2
3
# 10. 输出什么?
const box = { x: 10, y: 20 }
Object.freeze(box)
const shape = box
shape.x = 100
console.log(shape)
2
3
4
5
6
7
- A:
{ x: 100, y: 20 }
- B:
{ x: 10, y: 20 }
- C:
{ x: 100 }
- D:
ReferenceError
答案
# 10.1. 答案: B
Object.freeze
使得无法添加、删除或修改对象的属性(除非属性的值是另一个对象)。
当我们创建变量shape
并将其设置为等于冻结对象box
时,shape
指向的也是冻结对象。你可以使用Object.isFrozen
检查一个对象是否被冻结,上述情况,Object.isFrozen(shape)
将返回true
。
由于shape
被冻结,并且x
的值不是对象,所以我们不能修改属性x
。 x
仍然等于10
,{x:10,y:20}
被打印。
注意,上述例子我们对属性x
进行修改,可能会导致抛出 TypeError 异常(最常见但不仅限于严格模式下时)。
# 11. 以下哪一项会对对象 person
有作用?
const person = {
name: 'Lydia Hallie',
address: {
street: '100 Main St'
}
}
Object.freeze(person)
2
3
4
5
6
7
8
- A:
person.name = "Evan Bacon"
- B:
delete person.address
- C:
person.address.street = "101 Main St"
- D:
person.pet = { name: "Mara" }
答案
# 11.1. 答案: C
使用方法 Object.freeze
对一个对象进行 冻结。不能对属性进行添加,修改,删除。
然而,它仅 对对象进行 浅 冻结,意味着只有 对象中的 直接 属性被冻结。如果属性是另一个 object,像案例中的 address
,address
中的属性没有被冻结,仍然可以被修改。
# 12. 输出什么?
const person = {
name: 'Lydia',
age: 21
}
let city = person.city
city = 'Amsterdam'
console.log(person)
2
3
4
5
6
7
8
9
- A:
{ name: "Lydia", age: 21 }
- B:
{ name: "Lydia", age: 21, city: "Amsterdam" }
- C:
{ name: "Lydia", age: 21, city: undefined }
- D:
"Amsterdam"
答案
# 12.1. 答案: A
我们将变量city
设置为等于person
对象上名为city
的属性的值。 这个对象上没有名为city
的属性,因此变量city
的值为undefined
。
请注意,我们没有引用person
对象本身,只是将变量city
设置为等于person
对象上city
属性的当前值。
然后,我们将city
设置为等于字符串“Amsterdam”
。 这不会更改 person 对象:没有对该对象的引用。
因此打印person
对象时,会返回未修改的对象。
# 13. 输出什么?
// module.js
export default () => 'Hello world'
export const name = 'Lydia'
// index.js
import * as data from './module'
console.log(data)
2
3
4
5
6
7
8
- A:
{ default: function default(), name: "Lydia" }
- B:
{ default: function default() }
- C:
{ default: "Hello world", name: "Lydia" }
- D: Global object of
module.js
答案
# 13.1. 答案: A
使用import * as name
语法,我们将module.js
文件中所有export
导入到index.js
文件中,并且创建了一个名为data
的新对象。 在module.js
文件中,有两个导出:默认导出和命名导出。 默认导出是一个返回字符串 “Hello World” 的函数,命名导出是一个名为name
的变量,其值为字符串“Lydia”
。
data
对象具有默认导出的default
属性,其他属性具有指定 exports 的名称及其对应的值。
# 14. 哪些方法修改了原数组?
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, '✨')
2
3
4
5
6
7
8
- A:
All of them
- B:
map
reduce
slice
splice
- C:
map
slice
splice
- D:
splice
答案
# 14.1. 答案: D
使用splice
方法,我们通过删除,替换或添加元素来修改原始数组。 在这种情况下,我们从索引 1 中删除了 2 个元素(我们删除了'🥑'
和'😍'
),同时添加了 ✨emoji 表情。
map
,filter
和slice
返回一个新数组,find
返回一个元素,而reduce
返回一个减小的值。
# 15. 输出什么?
const colorConfig = {
red: true,
blue: false,
green: true,
black: true,
yellow: false
}
const colors = ['pink', 'red', 'blue']
console.log(colorConfig.colors[1])
2
3
4
5
6
7
8
9
10
11
- A:
true
- B:
false
- C:
undefined
- D:
TypeError
答案
# 15.1. 答案: 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 属性的值。
# 16. 下面那个选项将会返回 6
?
function sumValues(x, y, z) {
return x + y + z
}
2
3
- A:
sumValues([...1, 2, 3])
- B:
sumValues([...[1, 2, 3]])
- C:
sumValues(...[1, 2, 3])
- D:
sumValues([1, 2, 3])
答案
# 16.1. 答案: C
通过展开操作符 ...
,我们可以 暂开 单个可迭代的元素。函数 sumValues
function 接收三个参数: x
, y
和 z
。...[1, 2, 3]
的执行结果为 1, 2, 3
,将会传递给函数 sumValues
。
# 17. 输出什么?
const name = 'Lydia Hallie'
const age = 21
console.log(isNaN(name))
console.log(isNaN(age))
2
3
4
5
- A:
true
false
- B:
false
false
- C:
true
false
- D:
false
true
答案
# 17.1. 答案: C
通过方法 isNaN
, 你可以检测你传递的值是否一个 number。name
不是一个 number
,因此 isNaN(name)
返回 true
. age
是一个 number
因此 isNaN(age)
返回 false
.