- 送你74道JavaScript面试题
- 导读
- JavaScript 进阶问题列表
- 1. 下面代码的输出是什么?
- 2. 下面代码的输出是什么?
- 3. 下面代码的输出是什么?
- 4. 下面代码的输出是什么?
- 5. 哪个选项是不正确的?
- 6. 下面代码的输出是什么?
- 7. 下面代码的输出是什么?
- 8. 下面代码的输出是什么?
- 9. 下面代码的输出是什么?
- 10. 当我们这样做时会发生什么?
- 11. 下面代码的输出是什么?
- 12. 下面代码的输出是什么?
- 12. 事件传播的三个阶段是什么??
- 13. 所有对象都有原型.
- 14. 下面代码的输出是什么?
- 15. 下面代码的输出是什么?
- 16. 下面代码的输出是什么?
- 17. 下面代码的输出是什么?
- 18. 下面代码的输出是什么?
- 20. 下面代码的输出是什么?
- 21. 下面代码的输出是什么?
- 22. cool_secret可以访问多长时间?
- 23. 下面代码的输出是什么?
- 24. 下面代码的输出是什么?
- 25. 下面代码的输出是什么?
- 26. JavaScript全局执行上下文为你创建了两个东西:全局对象和this关键字.
- 27. 下面代码的输出是什么?
- 28. 下面代码的输出是什么?
- 29. 下面代码的输出是什么?
- 30. 下面代码的输出是什么?
- 31. 单击按钮时event.target是什么?
- 32. 单击下面的html片段打印的内容是什么?
- 33. 下面代码的输出是什么?
- 34. 下面代码的输出是什么?
- 35. 下面这些值哪些是假值?
- 36. 下面代码的输出是什么?
- 37. 下面代码的输出是什么?
- 38. 下面代码的输出是什么?
- 39. JavaScript中的所有内容都是…
- 40. 下面代码的输出是什么?
- 41. 下面代码的输出是什么?
- 42.
setInterval
方法的返回值什么? - 43. What does this return?
- 44. 下面代码的输出是什么?
- 45. 下面代码的返回值是什么?
- 46. 下面代码的输出是什么?
- 47. 下面代码的输出是什么?
- 48. 下面代码的输出是什么?
- 49.
num
的值是什么? - 50. 下面代码的输出是什么?
- 51. 下面代码输出的是什么?
- 52. 下面代码的输出是什么?
- 53. 下面代码的输出是什么?
- 54. 下面代码的输出是什么?
- 55. 下面代码的输出是什么?
- 56. 下面代码的输出是什么?
- 57. 下面代码的输出是什么?
- 58. 下面代码的输出是什么?
- 59. 下面代码的输出是什么?
- 60. 下面代码的输出是什么?
- 61. 下面代码的输出是什么?
- 62. 下面代码的输出是什么?
- 63. 下面代码的输出是什么?
- 64. 下面代码输出什么?
- 65. 下面代码输出什么?
- 66. 使用哪个构造函数可以成功继承
Dog
类? - 67. 下面代码输出什么?
- 68. 下面代码输出什么?
- 69. 下面代码输出什么?
- 70. 下面代码输出什么?
- 71. 如何能打印出
console.log
语句后注释掉的值? - 72. 下面代码输出什么?
- 74. 下面代码输出什么?
送你74道JavaScript面试题
导读
这两天的GitHub Trending repositories
被一个名叫 javascript-questions
的项目霸榜了,项目中记录了一些JavaScript
题目。
我大概从头到尾看了一遍,都是一些基础的题目,我大概花了半个小时(有些题很简单,可以一扫而过)把这些题做完了,虽然题目很简单,但是每道题都对应一个知识点,如果这个知识点你没有接触过,那肯定会做错,如果你接触过这些知识点,那么这些题对你来说就很容易。
建议大家也花半个小时来做一做,以便查漏补缺。
为方便大家能够更快的做题,而不把时间浪费在翻译上,我又花了几个小时把它们翻译成了中文,当然已经获得了作者授权。
文中有些点作者解释的不太完整,为了更好的理解,我在文中添加了一些个人解释。 仓库地址:https://github.com/lydiahallie/javascript-questions
JavaScript 进阶问题列表
我在我的Instagram上发布了每日JavaScript
选择题,我也会在这里发布!
从基础到高级:测试您对JavaScript
的了解程度,刷新您的知识,或为您的编码面试做好准备!
? ?我每周用新问题更新这个项目。
答案位于问题下方的折叠部分,只需单击它们即可展开。 祝你好运❤️
1. 下面代码的输出是什么?
function sayHi() {
console.log(name);
console.log(age);
var name = "Lydia";
let age = 21;
}
sayHi();
- A:
Lydia
和undefined
- B:
Lydia
和ReferenceError
- C:
ReferenceError
和21
-
答案: D
在函数中,我们首先使用
var
关键字声明了name
变量。 这意味着变量在创建阶段会被提升(JavaScript
会在创建变量创建阶段为其分配内存空间),默认值为undefined
,直到我们实际执行到使用该变量的行。 我们还没有为name
变量赋值,所以它仍然保持undefined
的值。
使用let
关键字(和const
)声明的变量也会存在变量提升,但与var
不同,初始化没有被提升。 在我们声明(初始化)它们之前,它们是不可访问的。 这被称为“暂时死区”。 当我们在声明变量之前尝试访问变量时,JavaScript
会抛出一个ReferenceError
。
译者注:
关于let
的是否存在变量提升,我们何以用下面的例子来验证:
let name = ‘ConardLi’
{
console.log(name) // Uncaught ReferenceError: name is not defined
let name = ‘code秘密花园’
}let
变量如果不存在变量提升,console.log(name)
就会输出ConardLi
,结果却抛出了ReferenceError
,那么这很好的说明了,let
也存在变量提升,但是它存在一个“暂时死区”,在变量未初始化或赋值前不允许访问。
变量的赋值可以分为三个阶段: 创建变量,在内存中开辟空间
- 初始化变量,将变量初始化为
undefined
- 真正赋值
关于let
、var
和function
:
let
的「创建」过程被提升了,但是初始化没有提升。var
的「创建」和「初始化」都被提升了。function
的「创建」「初始化」和「赋值」都被提升了。
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);
}
- A:
0 1 2
and0 1 2
- B:
0 1 2
and3 3 3
- C:
3 3 3
and0 1 2
答案: C
由于JavaScript
中的事件执行机制,setTimeout
函数真正被执行时,循环已经走完。 由于第一个循环中的变量i
是使用var
关键字声明的,因此该值是全局的。 在循环期间,我们每次使用一元运算符++
都会将i
的值增加1
。 因此在第一个例子中,当调用setTimeout
函数时,i
已经被赋值为3
。
在第二个循环中,使用let
关键字声明变量i
:使用let
(和const
)关键字声明的变量是具有块作用域的(块是{}
之间的任何东西)。 在每次迭代期间,i
将被创建为一个新值,并且每个值都会存在于循环内的块级作用域。
3. 下面代码的输出是什么?
const shape = {
radius: 10,
diameter() {
return this.radius 2;
},
perimeter: () => 2 Math.PI * this.radius
};
shape.diameter();
shape.perimeter();
- A:
20
and62.83185307179586
- B:
20
andNaN
- C:
20
and63
- D:
NaN
and63
答案: B
请注意,diameter
是普通函数,而perimeter
是箭头函数。
对于箭头函数,this
关键字指向是它所在上下文(定义时的位置)的环境,与普通函数不同! 这意味着当我们调用perimeter
时,它不是指向shape
对象,而是指其定义时的环境(window)。没有值radius
属性,返回undefined
。
4. 下面代码的输出是什么?
+true;
!”Lydia”;
- A:
1
andfalse
- B:
false
andNaN
- C:
false
andfalse
答案: A
一元加号会尝试将boolean
类型转换为数字类型。true
被转换为1
,false
被转换为0
。
字符串'Lydia'
是一个真值。 我们实际上要问的是“这个真值是假的吗?”。 这会返回false
。
5. 哪个选项是不正确的?
const bird = {
size: “small”
};
const mouse = {
name: “Mickey”,
small: true
};
- A:
mouse.bird.size
- B:
mouse[bird.size]
- C:
mouse[bird["size"]]
- D: All of them are valid
答案: A
在JavaScript
中,所有对象键都是字符串(除了Symbol
)。尽管有时我们可能不会给定字符串类型,但它们总是被转换为字符串。JavaScript
解释语句。当我们使用方括号表示法时,它会看到第一个左括号[
,然后继续,直到找到右括号]
。只有在那个时候,它才会对这个语句求值。mouse [bird.size]
:首先它会对bird.size
求值,得到small
。mouse [“small”]
返回true
。
但是,使用点表示法,这不会发生。mouse
没有名为bird
的键,这意味着mouse.bird
是undefined
。 然后,我们使用点符号来询问size
: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);
- 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);
- A:
true
false
true
- B:
false
false
true
- C:
true
false
false
- D:
false
true
true
答案: C
new Number()
是一个内置的函数构造函数。 虽然它看起来像一个数字,但它并不是一个真正的数字:它有一堆额外的功能,是一个对象。
当我们使用==
运算符时,它只检查它是否具有相同的值。 他们都有3
的值,所以它返回true
。译者注:
==
会引发隐式类型转换,右侧的对象类型会自动拆箱为Number
类型。
然而,当我们使用===
操作符时,类型和值都需要相等,new Number()
不是一个数字,是一个对象类型。两者都返回 false
。
8. 下面代码的输出是什么?
class Chameleon {
static colorChange(newColor) {
this.newColor = newColor;
}
constructor({ newColor = “green” } = {}) {
this.newColor = newColor;
}
}
const freddie = new Chameleon({ newColor: “purple” });
freddie.colorChange(“orange”);
- A:
orange
- B:
purple
- C:
green
- D:
TypeError
答案: D
colorChange
方法是静态的。 静态方法仅在创建它们的构造函数中存在,并且不能传递给任何子级。 由于freddie
是一个子级对象,函数不会传递,所以在freddie
实例上不存在freddie
方法:抛出TypeError
。
9. 下面代码的输出是什么?
let greeting;
greetign = {}; // Typo!
console.log(greetign);
- 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”;
- A: Nothing, this is totally fine!
- B:
SyntaxError
. You cannot add properties to a function this way. - 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 = () => this.firstName + this.lastName;
console.log(member.getFullName());
- A:
TypeError
- B:
SyntaxError
- C:
Lydia Hallie
- D:
undefined
undefined
答案: A
您不能像使用常规对象那样向构造函数添加属性。 如果要一次向所有对象添加功能,则必须使用原型。 所以在这种情况下应该这样写:
Person.prototype.getFullName = function () {
return${this.firstName} ${this.lastName}
;
}
这样会使member.getFullName()
是可用的,为什么样做是对的? 假设我们将此方法添加到构造函数本身。 也许不是每个Person
实例都需要这种方法。这会浪费大量内存空间,因为它们仍然具有该属性,这占用了每个实例的内存空间。 相反,如果我们只将它添加到原型中,我们只需将它放在内存中的一个位置,但它们都可以访问它!
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);
- 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
时,它指的是我们创建的新空对象。 但是,如果你不添加new
它指的是全局对象!
我们指定了this.firstName
等于'Sarah
和this.lastName
等于Smith
。 我们实际做的是定义global.firstName ='Sarah'
和global.lastName ='Smith
。sarah
本身的返回值是undefined
。
12. 事件传播的三个阶段是什么??
- A: 目标 > 捕获 > 冒泡
- B: 冒泡 > 目标 > 捕获
- C: 目标 > 冒泡 > 捕获
- D: 捕获 > 目标 > 冒泡
答案: D
在捕获阶段,事件通过父元素向下传递到目标元素。 然后它到达目标元素,冒泡开始。
13. 所有对象都有原型.
- A: 对
- B: 错误
答案: B
除基础对象外,所有对象都有原型。 基础对象可以访问某些方法和属性,例如.toString
。 这就是您可以使用内置JavaScript
方法的原因! 所有这些方法都可以在原型上找到。 虽然JavaScript
无法直接在您的对象上找到它,但它会沿着原型链向下寻找并在那里找到它,这使您可以访问它。
译者注:基础对象指原型链终点的对象。基础对象的原型是null
。
14. 下面代码的输出是什么?
function sum(a, b) {
return a + b;
}
sum(1, “2”);
- A:
NaN
- B:
TypeError
- C:
"12"
- D:
3
答案: C
JavaScript
是一种动态类型语言:我们没有指定某些变量的类型。 在您不知情的情况下,值可以自动转换为另一种类型,称为隐式类型转换。 强制从一种类型转换为另一种类型。
在此示例中,JavaScript
将数字1
转换为字符串,以使函数有意义并返回值。 在让数字类型(1
)和字符串类型('2'
)相加时,该数字被视为字符串。 我们可以连接像“Hello”+“World”
这样的字符串,所以这里发生的是“1”+“2”
返回“12”
。
15. 下面代码的输出是什么?
let number = 0;
console.log(number++);
console.log(++number);
console.log(number);
- 返回值(返回
0
) - 增加值(数字现在是
1
)
前缀一元运算符++
:
- 增加值(数字现在是
2
) - 返回值(返回
2
)
所以返回0 2 2
。
16. 下面代码的输出是什么?
function getPersonInfo(one, two, three) {
console.log(one);
console.log(two);
console.log(three);
}
const person = “Lydia”;
const age = 21;
getPersonInfo${person} is ${age} years old
;
- A:
Lydia
21
["", "is", "years old"]
- B:
["", "is", "years old"]
Lydia
21
- C:
Lydia
["", "is", "years old"]
21
答案: B
如果使用标记的模板字符串,则第一个参数的值始终是字符串值的数组。 其余参数获取传递到模板字符串中的表达式的值!
17. 下面代码的输出是什么?
function checkAge(data) {
if (data === { age: 18 }) {
console.log(“You are an adult!”);
} else if (data == { age: 18 }) {
console.log(“You are still an adult.”);
} else {
console.log(Hmm.. You don't have an age I guess
);
}
}
checkAge({ age: 18 });
- A:
You are an adult!
- B:
You are still an adult.
- C:
Hmm.. You don't have an age I guess
答案: C
在比较相等性,原始类型通过它们的值进行比较,而对象通过它们的引用进行比较。JavaScript
检查对象是否具有对内存中相同位置的引用。
我们作为参数传递的对象和我们用于检查相等性的对象在内存中位于不同位置,所以它们的引用是不同的。
这就是为什么{ age: 18 } === { age: 18 }
和{ age: 18 } == { age: 18 }
返回false
的原因。
18. 下面代码的输出是什么?
function getAge(…args) {
console.log(typeof args);
}
getAge(21);
- A:
"number"
- B:
"array"
- C:
"object"
- D:
"NaN"
答案: C
扩展运算符(... args
)返回一个带参数的数组。 数组是一个对象,因此typeof args
返回object
。
20. 下面代码的输出是什么?
function getAge() {
“use strict”;
age = 21;
console.log(age);
}
getAge();
- A:
21
- B:
undefined
- C:
ReferenceError
- D:
TypeError
答案: C
使用“use strict”
,可以确保不会意外地声明全局变量。 我们从未声明变量age
,因为我们使用`use strict'
,它会引发一个ReferenceError
。 如果我们不使用“use strict”
,它就会起作用,因为属性age
会被添加到全局对象中。
21. 下面代码的输出是什么?
const sum = eval(“10*10+5”);
- A:
105
- B:
"105"
- C:
TypeError
- D:
"10*10+5"
答案: A
eval
会为字符串传递的代码求值。 如果它是一个表达式,就像在这种情况下一样,它会计算表达式。 表达式为10 * 10 + 5
计算得到105
。
22. cool_secret可以访问多长时间?
sessionStorage.setItem(“cool_secret”, 123);
- A:永远,数据不会丢失。
- B:用户关闭选项卡时。
- C:当用户关闭整个浏览器时,不仅是选项卡。
- D:用户关闭计算机时。
答案: B
关闭选项卡后,将删除存储在sessionStorage
中的数据。
如果使用localStorage
,数据将永远存在,除非例如调用localStorage.clear()
。
23. 下面代码的输出是什么?
var num = 8;
var num = 10;
console.log(num);
- A:
8
- B:
10
- C:
SyntaxError
- D:
ReferenceError
答案: B
使用var
关键字,您可以用相同的名称声明多个变量。然后变量将保存最新的值。
您不能使用let
或const
来实现这一点,因为它们是块作用域的。
24. 下面代码的输出是什么?
const obj = { 1: “a”, 2: “b”, 3: “c” };
const set = new Set([1, 2, 3, 4, 5]);
obj.hasOwnProperty(“1”);
obj.hasOwnProperty(1);
set.has(“1”);
set.has(1);
- A:
false
true
false
true
- B:
false
true
true
true
- C:
true
true
false
true
- D:
true
true
true
true
答案: C
所有对象键(不包括Symbols
)都会被存储为字符串,即使你没有给定字符串类型的键。 这就是为什么obj.hasOwnProperty('1')
也返回true
。
上面的说法不适用于Set
。 在我们的Set
中没有“1”
:set.has('1')
返回false
。 它有数字类型1
,set.has(1)
返回true
。
25. 下面代码的输出是什么?
const obj = { a: “one”, b: “two”, a: “three” };
console.log(obj);
- A:
{ a: "one", b: "two" }
- B:
{ b: "two", a: "three" }
- C:
{ a: "three", b: "two" }
- D:
SyntaxError
答案: C
如果对象有两个具有相同名称的键,则将替前面的键。它仍将处于第一个位置,但具有最后指定的值。
26. JavaScript全局执行上下文为你创建了两个东西:全局对象和this关键字.
27. 下面代码的输出是什么?
for (let i = 1; i < 5; i++) {
if (i === 3) continue;
console.log(i);
}
28. 下面代码的输出是什么?
String.prototype.giveLydiaPizza = () => {
return “Just give Lydia pizza already!”;
};
const name = “Lydia”;
name.giveLydiaPizza();
- A:
"Just give Lydia pizza already!"
- B:
TypeError: not a function
- C:
SyntaxError
-
答案: A
String
是一个内置的构造函数,我们可以为它添加属性。 我刚给它的原型添加了一个方法。 原始类型的字符串自动转换为字符串对象,由字符串原型函数生成。 因此,所有字符串(字符串对象)都可以访问该方法!
译者注:
当使用基本类型的字符串调用giveLydiaPizza
时,实际上发生了下面的过程: 创建一个
String
的包装类型实例- 在实例上调用
substring
方法 - 销毁实例
29. 下面代码的输出是什么?
const a = {};
const b = { key: “b” };
const c = { key: “c” };
a[b] = 123;
a[c] = 456;
console.log(a[b]);
- A:
123
- B:
456
- C:
undefined
- D:
ReferenceError
答案: B
对象键自动转换为字符串。我们试图将一个对象设置为对象a
的键,其值为123
。
但是,当对象自动转换为字符串化时,它变成了[Object object]
。 所以我们在这里说的是a["Object object"] = 123
。 然后,我们可以尝试再次做同样的事情。c
对象同样会发生隐式类型转换。那么,a["Object object"] = 456
。
然后,我们打印a[b]
,它实际上是a["Object object"]
。 我们将其设置为456
,因此返回456
。
30. 下面代码的输出是什么?
const foo = () => console.log(“First”);
const bar = () => setTimeout(() => console.log(“Second”));
const baz = () => console.log(“Third”);
bar();
foo();
baz();
- A:
First
Second
Third
- B:
First
Third
Second
- C:
Second
First
Third
- D:
Second
Third
First
答案: B
我们有一个setTimeout
函数并首先调用它。 然而却最后打印了它。
这是因为在浏览器中,我们不只有运行时引擎,我们还有一个叫做WebAPI
的东西。WebAPI
为我们提供了setTimeout
函数,例如DOM
。
将callback
推送到WebAPI
后,setTimeout
函数本身(但不是回调!)从堆栈中弹出。
现在,调用foo
,并打印First
。
foo
从堆栈弹出,baz
被调用,并打印Third
。
WebAPI
不能只是在准备就绪时将内容添加到堆栈中。 相反,它将回调函数推送到一个称为任务队列
的东西。
这是事件循环开始工作的地方。 事件循环查看堆栈和任务队列。 如果堆栈为空,则会占用队列中的第一个内容并将其推送到堆栈中。
bar
被调用,Second
被打印,它从栈中弹出。
31. 单击按钮时event.target是什么?
32. 单击下面的html片段打印的内容是什么?
Click here!
- A:
p
div
- B:
div
p
- C:
p
- D:
div
答案: A
如果我们单击p
,我们会看到两个日志:p
和div
。在事件传播期间,有三个阶段:捕获,目标和冒泡。 默认情况下,事件处理程序在冒泡阶段执行(除非您将useCapture
设置为true
)。 它从最深的嵌套元素向外延伸。
33. 下面代码的输出是什么?
const person = { name: “Lydia” };
function sayHi(age) {
console.log(${this.name} is ${age}
);
}
sayHi.call(person, 21);
sayHi.bind(person, 21);
- A:
undefined is 21
Lydia is 21
- B:
function
function
- C:
Lydia is 21
Lydia is 21
- D:
Lydia is 21
function
答案: D
使用两者,我们可以传递我们想要this
关键字引用的对象。 但是,.call
方法会立即执行!.bind
方法会返回函数的拷贝值,但带有绑定的上下文! 它不会立即执行。
34. 下面代码的输出是什么?
function sayHi() {
return (() => 0)();
}
typeof sayHi();
- A:
"object"
- B:
"number"
- C:
"function"
- D:
"undefined"
答案: B
sayHi
函数返回立即调用的函数(IIFE
)的返回值。 该函数返回0
,类型为数字
。
仅供参考:只有7种内置类型:null
,undefined
,boolean
,number
,string
,object
和symbol
。function
不是一个类型,因为函数是对象,它的类型是object
。
35. 下面这些值哪些是假值?
0;
new Number(0);
(“”);
(“ “);
new Boolean(false);
undefined;
- A:
0
,''
,undefined
- B:
0
,new Number(0)
,''
,new Boolean(false)
,undefined
- C:
0
,''
,new Boolean(false)
,undefined
-
答案: A
JavaScript
中只有6个假值: undefined
null
NaN
0
''
(empty string)false
函数构造函数,如new Number
和new Boolean
都是真值。
36. 下面代码的输出是什么?
console.log(typeof typeof 1);
- A:
"number"
- B:
"string"
- C:
"object"
- D:
"undefined"
答案: B
typeof 1
返回"number"
.typeof "number"
返回"string"
37. 下面代码的输出是什么?
const numbers = [1, 2, 3];
numbers[10] = 11;
console.log(numbers);
- A:
[1, 2, 3, 7 x null, 11]
- B:
[1, 2, 3, 11]
- C:
[1, 2, 3, 7 x empty, 11]
- D:
SyntaxError
答案: C
When you set a value to an element in an array that exceeds the length of the array, JavaScript creates something called “empty slots”. These actually have the value ofundefined
, but you will see something like:
当你为数组中的元素设置一个超过数组长度的值时,JavaScript
会创建一个名为“空插槽”的东西。 这些位置的值实际上是undefined
,但你会看到类似的东西:[1, 2, 3, 7 x empty, 11]
这取决于你运行它的位置(每个浏览器有可能不同)。
38. 下面代码的输出是什么?
(() => {
let x, y;
try {
throw new Error();
} catch (x) {
(x = 1), (y = 2);
console.log(x);
}
console.log(x);
console.log(y);
})();
- A:
1
undefined
2
- B:
undefined
undefined
undefined
- C:
1
1
2
- D:
1
undefined
undefined
答案: A
catch
块接收参数x
。当我们传递参数时,这与变量的x
不同。这个变量x
是属于catch
作用域的。
之后,我们将这个块级作用域的变量设置为1
,并设置变量y
的值。 现在,我们打印块级作用域的变量x
,它等于1
。
在catch
块之外,x
仍然是undefined
,而y
是2
。 当我们想在catch
块之外的console.log(x)
时,它返回undefined
,而y
返回2
。
39. JavaScript中的所有内容都是…
- A:原始或对象
- B:函数或对象
- C:技巧问题!只有对象
- D:数字或对象
答案: A
JavaScript
只有原始类型和对象。
原始类型是boolean
,null
,undefined
,bigint
,number
,string
和symbol
。
40. 下面代码的输出是什么?
[[0, 1], [2, 3]].reduce(
(acc, cur) => {
return acc.concat(cur);
},
[1, 2]
);
- A:
[0, 1, 2, 3, 1, 2]
- B:
[6, 1, 2]
- C:
[1, 2, 0, 1, 2, 3]
- D:
[1, 2, 6]
答案: C
[1,2]
是我们的初始值。 这是我们开始执行reduce
函数的初始值,以及第一个acc
的值。 在第一轮中,acc
是[1,2]
,cur
是[0,1]
。 我们将它们连接起来,结果是[1,2,0,1]
。
然后,acc
的值为[1,2,0,1]
,cur
的值为[2,3]
。 我们将它们连接起来,得到[1,2,0,1,2,3]
。
41. 下面代码的输出是什么?
!!null;
!!””;
!!1;
- A:
false
true
false
- B:
false
false
true
- C:
false
true
true
- D:
true
true
false
答案: B
null
是假值。!null
返回true
。!true
返回false
。""
是假值。!""
返回true
。!true
返回false
。1
是真值。!1
返回false
。!false
返回true
。
42. setInterval
方法的返回值什么?
setInterval(() => console.log(“Hi”), 1000);
43. What does this return?
[…”Lydia”];
- A:
["L", "y", "d", "i", "a"]
- B:
["Lydia"]
- C:
[[], "Lydia"]
- D:
[["L", "y", "d", "i", "a"]]
答案: A
字符串是可迭代的。 扩展运算符将迭代的每个字符映射到一个元素。
如果你看过我这篇文章:【JS进阶】你真的掌握变量和类型了吗 那么这些题目中的变量和类型问题肯定难不倒44. 下面代码的输出是什么?
function generator(i) {
yield i;
yield i 2;
}
const gen = generator(10);
console.log(gen.next().value);
console.log(gen.next().value);
- A:
[0,10],[10,20]
- B:
20,20
- C:
10,20
- D:
0,10and10,20
答案: C
一般的函数在执行之后是不能中途停下的。但是,生成器函数却可以中途“停下”,之后可以再从停下的地方继续。当生成器遇到yield
关键字的时候,会生成yield
后面的值。注意,生成器在这种情况下不 返回(return )值,而是 生成 (yield)值。
首先,我们用10
作为参数i
来初始化生成器函数。然后使用next()
方法一步步执行生成器。第一次执行生成器的时候,i
的值为10
,遇到第一个yield
关键字,它要生成i
的值。此时,生成器“暂停”,生成了10
。
然后,我们再执行next()
方法。生成器会从刚才暂停的地方继续,这个时候i
还是10
。于是我们走到了第二个yield
关键字处,这时候需要生成的值是i*2
,i
为10
,那么此时生成的值便是20
。所以这道题的最终结果是10,20
。45. 下面代码的返回值是什么?
const firstPromise = new Promise((res, rej) => {
setTimeout(res, 500, “one”);
});
const secondPromise = new Promise((res, rej) => {
setTimeout(res, 100, “two”);
});
Promise.race([firstPromise, secondPromise]).then(res => console.log(res));
- A:
"one"
- B:
"two"
- C:
"two""one"
- D:
"one""two"
答案: B
当我们向Promise.race
方法中传入多个Promise
时,会进行 优先 解析。在这个例子中,我们用setTimeout
给firstPromise
和secondPromise
分别设定了500ms和100ms的定时器。这意味着secondPromise
会首先解析出字符串two
。那么此时res
参数即为two
,是为输出结果。
46. 下面代码的输出是什么?
let person = { name: “Lydia” };
const members = [person];
person = null;
console.log(members);
- A:
null
- B:
[null]
- C:
[{}]
- D:
[{name:"Lydia"}]
答案: D
首先我们声明了一个拥有name
属性的对象person
。
然后我们又声明了一个变量members
. 将首个元素赋值为变量person
。 当设置两个对象彼此相等时,它们会通过 引用 进行交互。但是当你将引用从一个变量分配至另一个变量时,其实只是执行了一个 复制 操作。(注意一点,他们的引用 并不相同!)
接下来我们让 person
等于 null
。
我们没有修改数组第一个元素的值,而只是修改了变量 person
的值,因为元素(复制而来)的引用与 person
不同。members
的第一个元素仍然保持着对原始对象的引用。当我们输出 members
数组时,第一个元素会将引用的对象打印出来。
47. 下面代码的输出是什么?
const person = {
name: “Lydia”,
age: 21
};
for (const item in person) {
console.log(item);
}
- A:
{name:"Lydia"},{age:21}
- B:
"name","age"
- C:
"Lydia",21
- D:
["name","Lydia"],["age",21]
答案: B
在for-in
循环中,我们可以通过对象的key来进行迭代,也就是这里的name
和age
。在底层,对象的key都是字符串(如果他们不是Symbol的话)。在每次循环中,我们将item
设定为当前遍历到的key.所以一开始,item
是name
,之后item
输出的则是age
。
48. 下面代码的输出是什么?
console.log(3 + 4 + “5”);
- A:
"345"
- B:
"75"
- C:
12
-
答案: B
当所有运算符的 优先级 相同时,计算表达式需要确定运算符的结合顺序,即从右到左还是从左往右。在这个例子中,我们只有一类运算符
+
,对于加法来说,结合顺序就是从左到右。3+4
首先计算,得到数字7
.
由于类型的强制转换,7+'5'
的结果是"75"
. JavaScript将7
转换成了字符串,可以参考问题15.我们可以用+
号把两个字符串连接起来。"7"+"5"
就得到了"75"
.49.
num
的值是什么?const num = parseInt(“7*6”, 10);
A:
42
- B:
"42"
- C:
7
- D:
NaN
答案: C
只返回了字符串中第一个字母. 设定了 进制 后 (也就是第二个参数,指定需要解析的数字是什么进制: 十进制、十六机制、八进制、二进制等等……),parseInt
检查字符串中的字符是否合法. 一旦遇到一个在指定进制中不合法的字符后,立即停止解析并且忽略后面所有的字符。*
就是不合法的数字字符。所以只解析到"7"
,并将其解析为十进制的7
.num
的值即为7
.
50. 下面代码的输出是什么?
[1, 2, 3].map(num => {
if (typeof num === “number”) return;
return num * 2;
});
- A:
[]
- B:
[null,null,null]
- C:
[undefined,undefined,undefined]
- D:
[3x empty]
答案: C
对数组进行映射的时候,num
就是当前循环到的元素. 在这个例子中,所有的映射都是number类型,所以if中的判断typeofnum==="number"
结果都是true
.map函数创建了新数组并且将函数的返回值插入数组。
但是,没有任何值返回。当函数没有返回任何值时,即默认返回undefined
.对数组中的每一个元素来说,函数块都得到了这个返回值,所以结果中每一个元素都是undefined
.
51. 下面代码输出的是什么?
function getInfo(member, year) {
member.name = “Lydia”;
year = “1998”;
}
const person = { name: “Sarah” };
const birthYear = “1997”;
getInfo(person, birthYear);
console.log(person, birthYear);
- A:
{name:"Lydia"},"1997"
- B:
{name:"Sarah"},"1998"
- C:
{name:"Lydia"},"1998"
- D:
{name:"Sarah"},"1997"
答案: A
普通参数都是 值 传递的,而对象则不同,是 引用 传递。所以说,birthYear
是值传递,因为他是个字符串而不是对象。当我们对参数进行值传递时,会创建一份该值的 复制 。(可以参考问题46)
变量birthYear
有一个对"1997"
的引用,而传入的参数也有一个对"1997"
的引用,但二者的引用并不相同。当我们通过给year
赋值"1998"
来更新year
的值的时候我们只是更新了year
(的引用)。此时birthYear
仍然是"1997"
.
而person
是个对象。参数member
引用与之 相同的 对象。当我们修改member
所引用对象的属性时,person
的相应属性也被修改了,因为他们引用了相同的对象.person
的name
属性也变成了"Lydia"
.
52. 下面代码的输出是什么?
function greeting() {
throw “Hello world!”;
}
function sayHi() {
try {
const data = greeting();
console.log(“It worked!”, data);
} catch (e) {
console.log(“Oh no an error!”, e);
}
}
sayHi();
- A:
"It worked! Hello world!"
- B:
"Oh no an error: undefined
- C:
SyntaxError:can onlythrowErrorobjects
- D:
"Oh no an error: Hello world!
答案: D
通过throw
语句,我么可以创建自定义错误。而通过它,我们可以抛出异常。异常可以是一个字符串, 一个 数字, 一个 布尔类型 或者是一个 对象。在本例中,我们的异常是字符串'Hello world'
.
通过catch
语句,我们可以设定当try
语句块中抛出异常后应该做什么处理。在本例中抛出的异常是字符串'Hello world'
.e
就是这个字符串,因此被输出。最终结果就是'Oh an error: Hello world'
.
53. 下面代码的输出是什么?
function Car() {
this.make = “Lamborghini”;
return { make: “Maserati” };
}
const myCar = new Car();
console.log(myCar.make);
- A:
"Lamborghini"
- B:
"Maserati"
- C:
ReferenceError
- D:
TypeError
答案: B
返回属性的时候,属性的值等于 返回的 值,而不是构造函数中设定的值。我们返回了字符串"Maserati"
,所以myCar.make
等于"Maserati"
.
54. 下面代码的输出是什么?
(() => {
let x = (y = 10);
})();
console.log(typeof x);
console.log(typeof y);
- A:
"undefined","number"
- B:
"number","number"
- C:
"object","number"
- D:
"number","undefined"
答案: A
letx=y=10;
是下面这个表达式的缩写:
y = 10;
let x = y;
我们设定y
等于10
时,我们实际上增加了一个属性y
给全局对象(浏览器里的window
, Nodejs里的global
)。在浏览器中,window.y
等于10
.
然后我们声明了变量x
等于y
,也是10
.但变量是使用let
声明的,它只作用于 块级作用域, 仅在声明它的块中有效;就是案例中的立即调用表达式(IIFE)。使用typeof
操作符时, 操作值x
没有被定义:因为我们在x
声明块的外部,无法调用它。这就意味着x
未定义。未分配或是未声明的变量类型为"undefined"
.console.log(typeofx)
返回"undefined"
.
而我们创建了全局变量y
,并且设定y
等于10
.这个值在我们的代码各处都访问的到。y
已经被定义了,而且有一个"number"
类型的值。console.log(typeofy)
返回"number"
.
55. 下面代码的输出是什么?
class Dog {
constructor(name) {
this.name = name;
}
}
Dog.prototype.bark = function() {
console.log(Woof I am ${this.name}
);
};
const pet = new Dog(“Mara”);
pet.bark();
delete Dog.prototype.bark;
pet.bark();
- A:
"Woof I am Mara"
,TypeError
- B:
"Woof I am Mara"
,"Woof I am Mara"
- C:
"Woof I am Mara"
,undefined
- D:
TypeError
,TypeError
答案: A
我们可以用delete
关键字删除对象的属性,对原型也是适用的。删除了原型的属性后,该属性在原型链上就不可用了。在本例中,函数bark
在执行了deleteDog.prototype.bark
后不可用, 然而后面的代码还在调用它。
当我们尝试调用一个不存在的函数时TypeError
异常会被抛出。在本例中就是TypeError:pet.barkisnotafunction
,因为pet.bark
是undefined
.
56. 下面代码的输出是什么?
const set = new Set([1, 1, 2, 3, 4]);
console.log(set);
- A:
[1,1,2,3,4]
- B:
[1,2,3,4]
- C:
{1,1,2,3,4}
- D:
{1,2,3,4}
答案: D
Set
对象手机 独一无二 的值:也就是说同一个值在其中仅出现一次。
我们传入了数组[1,1,2,3,4]
,他有一个重复值1
.以为一个集合里不能有两个重复的值,其中一个就被移除了。所以结果是{1,2,3,4}
.
57. 下面代码的输出是什么?
// counter.js
let counter = 10;
export default counter;
// index.js
import myCounter from “./counter”;
myCounter += 1;
console.log(myCounter);
- A:
10
- B:
11
- C:
Error
- D:
NaN
答案: C
引入的模块是 只读 的: 你不能修改引入的模块。只有导出他们的模块才能修改其值。
当我们给myCounter
增加一个值的时候会抛出一个异常:myCounter
是只读的,不能被修改。
58. 下面代码的输出是什么?
const name = “Lydia”;
age = 21;
console.log(delete name);
console.log(delete age);
- A:
false
,true
- B:
"Lydia"
,21
- C:
true
,true
- D:
undefined
,undefined
答案: A
delete
操作符返回一个布尔值:true
指删除成功,否则返回false
. 但是通过var
,const
或let
关键字声明的变量无法用delete
操作符来删除。name
变量由const
关键字声明,所以删除不成功:返回false
. 而我们设定age
等于21
时,我们实际上添加了一个名为age
的属性给全局对象。对象中的属性是可以删除的,全局对象也是如此,所以deleteage
返回true
.59. 下面代码的输出是什么?
const numbers = [1, 2, 3, 4, 5];
const [y] = numbers;
console.log(y);
- A:
[[1,2,3,4,5]]
- B:
[1,2,3,4,5]
- C:
1
- D:
[1]
答案: C
我们可以通过解构赋值来解析来自对象的数组或属性的值,比如说:
[a, b] = [1, 2];a
的值现在是1
,b
的值现在是2
.而在题目中,我们是这么做的:
[y] = [1, 2, 3, 4, 5];
也就是说,y
等于数组的第一个值就是数字1
.我们输出y
, 返回1
.
60. 下面代码的输出是什么?
const user = { name: “Lydia”, age: 21 };
const admin = { admin: true, …user };
console.log(admin);
- A:
{admin:true,user:{name:"Lydia",age:21}}
- B:
{admin:true,name:"Lydia",age:21}
- C:
{admin:true,user:["Lydia",21]}
- D:
{admin:true}
答案: B
扩展运算符...
为对象的组合提供了可能。你可以复制对象中的键值对,然后把它们加到另一个对象里去。在本例中,我们复制了user
对象键值对,然后把它们加入到admin
对象中。admin
对象就拥有了这些键值对,所以结果为{admin:true,name:"Lydia",age:21}
.
61. 下面代码的输出是什么?
const person = { name: “Lydia” };
Object.defineProperty(person, “age”, { value: 21 });
console.log(person);
console.log(Object.keys(person));
- A:
{name:"Lydia",age:21}
,["name","age"]
- B:
{name:"Lydia",age:21}
,["name"]
- C:
{name:"Lydia"}
,["name","age"]
- D:
{name:"Lydia"}
,["age"]
答案: B
通过defineProperty
方法,我们可以给对象添加一个新属性,或者修改已经存在的属性。而我们使用defineProperty
方法给对象添加了一个属性之后,属性默认为 不可枚举(not enumerable).Object.keys
方法仅返回对象中 可枚举(enumerable) 的属性,因此只剩下了"name"
.
用defineProperty
方法添加的属性默认不可变。你可以通过writable
,configurable
和enumerable
属性来改变这一行为。这样的话, 相比于自己添加的属性,defineProperty
方法添加的属性有了更多的控制权。
62. 下面代码的输出是什么?
const settings = {
username: “lydiahallie”,
level: 19,
health: 90
};
const data = JSON.stringify(settings, [“level”, “health”]);
console.log(data);
- A:
"{"level":19, "health":90}"
- B:
"{"username": "lydiahallie"}"
- C:
"["level", "health"]"
- D:
"{"username": "lydiahallie", "level":19, "health":90}"
答案: A
JSON.stringify
的第二个参数是 替代者(replacer). 替代者(replacer)可以是个函数或数组,用以控制哪些值如何被转换为字符串。
如果替代者(replacer)是个 数组 ,那么就只有包含在数组中的属性将会被转化为字符串。在本例中,只有名为"level"
和"health"
的属性被包括进来,"username"
则被排除在外。data
就等于"{"level":19, "health":90}"
.
而如果替代者(replacer)是个 函数,这个函数将被对象的每个属性都调用一遍。函数返回的值会成为这个属性的值,最终体现在转化后的JSON字符串中(译者注:Chrome下,经过实验,如果所有属性均返回同一个值的时候有异常,会直接将返回值作为结果输出而不会输出JSON字符串),而如果返回值为undefined
,则该属性会被排除在外。
63. 下面代码的输出是什么?
let num = 10;
const increaseNumber = () => num++;
const increasePassedNumber = number => number++;
const num1 = increaseNumber();
const num2 = increasePassedNumber(num1);
console.log(num1);
console.log(num2);
- A:
10
,10
- B:
10
,11
- C:
11
,11
- D:
11
,12
答案: A
一元操作符++
先返回 操作值, 再累加 操作值。num1
的值是10
, 因为increaseNumber
函数首先返回num
的值,也就是10
,随后再进行num
的累加。num2
是10
因为我们将num1
传入increasePassedNumber
.number
等于10
(num1
的值。同样道理,++
先返回 操作值, 再累加 操作值。)number
是10
,所以num2
也是10
.
64. 下面代码输出什么?
const value = { number: 10 };
const multiply = (x = { …value }) => {
console.log(x.number *= 2);
};
multiply();
multiply();
multiply(value);
multiply(value);
- A:
20
,40
,80
,160
- B:
20
,40
,20
,40
- C:
20
,20
,20
,40
- D:
NaN
,NaN
,20
,40
答案: C
在ES6中,我们可以使用默认值初始化参数。如果没有给函数传参,或者传的参值为"undefined"
,那么参数的值将是默认值。上述例子中,我们将value
对象进行了解构并传到一个新对象中,因此x
的默认值为{number:10}
。
默认参数在调用时才会进行计算,每次调用函数时,都会创建一个新的对象。我们前两次调用multiply
函数且不传递值,那么每一次x
的默认值都为{number:10}
,因此打印出该数字的乘积值为20
。
第三次调用multiply
时,我们传递了一个参数,即对象value
。*=
运算符实际上是x.number=x.number*2
的简写,我们修改了x.number
的值,并打印出值20
。
第四次,我们再次传递value
对象。x.number
之前被修改为20
,所以x.number*=2
打印为40
。
65. 下面代码输出什么?
[1, 2, 3, 4].reduce((x, y) => console.log(x, y));
- A:
1
2
and3
3
and6
4
- B:
1
2
and2
3
and3
4
- C:
1
undefined
and2
undefined
and3
undefined
and4
undefined
- D:
1
2
andundefined
3
andundefined
4
答案: D
reducer
函数接收4个参数:
- Accumulator (acc) (累计器)
- Current Value (cur) (当前值)
- Current Index (idx) (当前索引)
- Source Array (src) (源数组)
reducer
函数的返回值将会分配给累计器,该返回值在数组的每个迭代中被记住,并最后成为最终的单个结果值。reducer
函数还有一个可选参数 initialValue
, 该参数将作为第一次调用回调函数时的第一个参数的值。如果没有提供 initialValue
,则将使用数组中的第一个元素。
在上述例子, reduce
方法接收的第一个参数(Accumulator)是 x
, 第二个参数(Current Value)是 y
。
在第一次调用时,累加器 x
为 1
,当前值 “y”
为 2
,打印出累加器和当前值:1
和 2
。
例子中我们的回调函数没有返回任何值,只是打印累加器的值和当前值。如果函数没有返回值,则默认返回 undefined
。在下一次调用时,累加器为 undefined
,当前值为“3”, 因此 undefined
和 3
被打印出。
在第四次调用时,回调函数依然没有返回值。累加器再次为 undefined
,当前值为“4”。undefined
和 4
被打印出。
66. 使用哪个构造函数可以成功继承 Dog
类?
class Dog {
constructor(name) {
this.name = name;
}
};
class Labrador extends Dog {
// 1
constructor(name, size) {
this.size = size;
}
// 2
constructor(name, size) {
super(name);
this.size = size;
}
// 3
constructor(size) {
super(name);
this.size = size;
}
// 4
constructor(name, size) {
this.name = name;
this.size = size;
}
};
- A: 1
- B: 2
- C: 3
- D: 4
答案: B
在子类中,在调用super
之前不能访问到this
关键字。如果这样做,它将抛出一个ReferenceError
:1和4将引发一个引用错误。
使用super
关键字,需要用给定的参数来调用父类的构造函数。父类的构造函数接收name
参数,因此我们需要将name
传递给super
。Labrador
类接收两个参数,name
参数是由于它继承了Dog
,size
作为Labrador
类的额外属性,它们都需要传递给Labrador
的构造函数,因此使用构造函数2正确完成。
67. 下面代码输出什么?
// index.js
console.log(‘running index.js’);
import { sum } from ‘./sum.js’;
console.log(sum(1, 2));
// sum.js
console.log(‘running sum.js’);
export const sum = (a, b) => a + b;
- A:
running index.js
,running sum.js
,3
- B:
running sum.js
,running index.js
,3
- C:
running sum.js
,3
,running index.js
- D:
running index.js
,undefined
,running sum.js
答案: B
import
命令是编译阶段执行的,在代码运行之前。因此这意味着被导入的模块会先运行,而导入模块的文件会后执行。
这是CommonJS中require()
和import
之间的区别。使用require()
,您可以在运行代码时根据需要加载依赖项。如果我们使用require
而不是import
,running index.js
,running sum.js
,3
会被依次打印。
68. 下面代码输出什么?
console.log(Number(2) === Number(2))
console.log(Boolean(false) === Boolean(false))
console.log(Symbol(‘foo’) === Symbol(‘foo’))
- A:
true
,true
,false
- B:
false
,true
,false
- C:
true
,false
,true
- D:
true
,true
,true
答案: A
每个Symbol
都是完全唯一的。传递给Symbol
的参数只是给Symbol
的一个描述。Symbol
的值不依赖于传递的参数。当我们测试相等时,我们创建了两个全新的符号:第一个Symbol('foo')
,第二个Symbol('foo')
, 这两个值是唯一的,彼此不相等,因此返回false
。
69. 下面代码输出什么?
const name = “Lydia Hallie”
console.log(name.padStart(13))
console.log(name.padStart(2))
- A:
"Lydia Hallie"
,"Lydia Hallie"
- B:
" Lydia Hallie"
," Lydia Hallie"
("[13x whitespace]Lydia Hallie"
,"[2x whitespace]Lydia Hallie"
) - C:
" Lydia Hallie"
,"Lydia Hallie"
("[1x whitespace]Lydia Hallie"
,"Lydia Hallie"
) -
答案: C
使用
padStart
方法,我们可以在字符串的开头添加填充。传递给此方法的参数是字符串的总长度(包含填充)。字符串LydiaHallie
的长度为12
, 因此name.padStart(13)
在字符串的开头只会插入1(13-12=1
)个空格。
如果传递给padStart
方法的参数小于字符串的长度,则不会添加填充。70. 下面代码输出什么?
console.log(“?” + “?”);
A:
"??"
- B:
257548
- C: A string containing their code points
- D: Error
答案: A
使用+
运算符,您可以连接字符串。上述情况,我们将字符串“?”
与字符串”?“
连接起来,产生”??“
。
71. 如何能打印出 console.log
语句后注释掉的值?
function* startGame() {
const answer = yield “Do you love JavaScript?”;
if (answer !== “Yes”) {
return “Oh wow… Guess we’re gone here”;
}
return “JavaScript loves you back ❤️”;
}
const game = startGame();
console.log(/ 1 /); // Do you love JavaScript?
console.log(/ 2 /); // JavaScript loves you back ❤️
- A:
game.next("Yes").value
andgame.next().value
- B:
game.next.value("Yes")
andgame.next.value()
- C:
game.next().value
andgame.next("Yes").value
- D:
game.next.value()
andgame.next.value("Yes")
答案: C
generator
函数在遇到yield
关键字时会“暂停”其执行。首先,我们需要让函数产生字符串Doyou loveJavaScript?
,这可以通过调用game.next().value
来完成。上述函数的第一行就有一个yield
关键字,那么运行立即停止了,yield
表达式本身没有返回值,或者说总是返回undefined
, 这意味着此时变量answer
为undefined
next
方法可以带一个参数,该参数会被当作上一个yield
表达式的返回值。当我们调用game.next("Yes").value
时,先前的yield
的返回值将被替换为传递给next()
函数的参数"Yes"
。此时变量answer
被赋值为"Yes"
,if
语句返回false
,所以JavaScriptloves you back❤️
被打印。
72. 下面代码输出什么?
console.log(String.rawHello\nworld
);
- A:
Helloworld!
- B:
Hello
world
- C:
Hello\nworld
- D:
Hello\n
world
答案: C
String.raw
函数是用来获取一个模板字符串的原始字符串的,它返回一个字符串,其中忽略了转义符(\n
,\v
,\t
等)。但反斜杠可能造成问题,因为你可能会遇到下面这种类似情况:
const path =C:\Documents\Projects\table.html
String.raw${path}
这将导致:"C:DocumentsProjects able.html"
直接使用String.raw
String.rawC:\Documents\Projects\table.html
它会忽略转义字符并打印:C:\Documents\Projects\table.html
上述情况,字符串是Hello\nworld
被打印出。
73.下面代码输出什么?
async function getData() {
return await Promise.resolve(“I made it!”);
}
const data = getData();
console.log(data);
- A:
"I made it!"
- B:
Promise{<resolved>:"I made it!"}
- C:
Promise{<pending>}
- D:
undefined
答案: C
异步函数始终返回一个promise。await
仍然需要等待promise的解决:当我们调用getData()
并将其赋值给data
,此时data
为getData
方法返回的一个挂起的promise,该promise并没有解决。
如果我们想要访问已解决的值"I made it!"
,可以在data
上使用.then()
方法:data.then(res=>console.log(res))
这样将打印"I made it!"
74. 下面代码输出什么?
function addToList(item, list) {
return list.push(item);
}
const result = addToList(“apple”, [“banana”]);
console.log(result);