1.num的值是什么?
const num = parseInt("7*6",10);
- A: 42
- B: “42”
- C: 7
- D: NaN
答案:C
只返回了字符串中第一个字母,设定了进制后(也就是第二个参数,指定需要解析的数字是什么进制:二进制、八进制、十进制、十六进制等等…),
parseInt
检查字符串中的字符是否合法,一旦遇到一个在指定进制中不合法的字符后,立即停止解析并且忽略后面所有的字符。
*
就是不合法的数字字符。所以只解析到"7"
,并将其解析为十进制的7
,num
的值即为7
2.下面代码的输出是什么?
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
数组时,第一个元素会将引用的对象打印出来。
3.下面代码的输出是什么?
function Car(){
this.make = "AAA";
return { make:"BBB" };
}
const myCar = new Car();
console.log(myCar.make);
- A: “AAA”
- B: “BBB”
- C: ReferenceError
- D: TypeError
答案:B
返回属性的时候,属性的值等于 返回的 值,而不是构造函数中设定的值。我们返回了字符串
"BBB"
,所以myCar.make
等于"BBB"
.
4.下面代码的输出是什么?
(() => {
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
let x=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"
.
5.下面代码的输出是什么?
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
.
6.下面代码的输出是什么?
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}
.
7.下面代码的输出是什么?
// 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
是只读的,不能被修改
8.下面代码的输出是什么?
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
.
9.下面代码的输出是什么?
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
10.下面代码的输出是什么?
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}
.
11.下面代码的输出是什么?
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
方法添加的属性有了更多的控制权。
12.下面代码的输出是什么?
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
,则该属性会被排除在外。
13.下面代码的输出是什么?
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
.
14.下面代码的输出是什么?
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,41,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
15.下面代码的输出是什么?
[1,2,3,4].reduce((x,y) => console.log(x,y))
- A: 1 2 , 3 3 , 6 4
- B: 1 2 , 2 3 , 3 4
- C: 1 undefined , 2 undefined , 3 undefined , 4 undefined
- D: 1 2 , undefined 3 , undefined 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
被打印出。
16.使用哪个构造函数可以成功继承 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正确完成。
17.下面代码的输出是什么?
//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
会被依次打印。
18.下面代码的输出是什么?
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
。
19.下面代码的输出是什么?
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”)
- D: “Lydia Hallie” , “Lyd”
答案:C
使用
padStart
方法,我们可以在字符串的开头添加填充。传递给此方法的参数是字符串的总长度(包含填充)。字符串Lydia Hallie
的长度为12
, 因此name.padStart(13)
在字符串的开头只会插入1(13-12=1
)个空格。
如果传递给
padStart
方法的参数小于字符串的长度,则不会添加填充。
20.下面代码的输出是什么?
console.log("🥑"+"💻");
- A: 🥑💻
- B: 257548
- C: A string containing their code points
- D: Error
答案:A
使用 +运算符,您可以连接字符串。上述情况,我们将字符串 “🥑”与字符串 ”💻“连接起来,产生 ”🥑💻“。
21.如何能打印出 console.log语句后注释掉的值?
console.log(String.raw`Hello\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.raw`C:\Documents\Projects\table.html`
它会忽略转义字符并打印:
C:\Documents\Projects\table.html
上述情况,字符串是Hello\nworld
被打印出
22.下面代码的输出是什么?
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!"
23.下面代码的输出是什么?
function addToList(item,list){
return list.push(item)
}
const result = addToList("apple",["banana"]);
console.log(result);
- A: [‘apple’,‘banana’]
- B: 2
- C: true
- D: undefined
答案:B
push()
方法返回新数组的长度。一开始,数组包含一个元素(字符串"banana"
),长度为1。在数组中添加字符串"apple"
后,长度变为2,并将从addToList
函数返回。
push
方法修改原始数组,如果你想从函数返回数组而不是数组长度,那么应该在pushitem
之后返回list
。