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:
20and62.83185307179586 - B:
20andNaN - C:
20and63 - D:
NaNand63
答案
# 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:
112 - B:
122 - C:
022 - D:
012
答案
# 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:
mapreduceslicesplice - C:
mapslicesplice - 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:
truefalse - B:
falsefalse - C:
truefalse - D:
falsetrue
答案
# 17.1. 答案: C
通过方法 isNaN, 你可以检测你传递的值是否一个 number。name 不是一个 number,因此 isNaN(name) 返回 true. age 是一个 number 因此 isNaN(age) 返回 false.