setInterval
方法的返回值什么?setInterval(() => console.log("Hi"), 1000);
A:一个唯一的id
B:指定的毫秒数
C:传递的函数
D:undefined
答案: A
它返回一个唯一的id。 此id可用于使用clearInterval()函数清除该定时器。
[..."Lydia"];
A: [“L”, “y”, “d”, “i”, “a”]
B: [“Lydia”]
C: [[], “Lydia”]
D: [[“L”, “y”, “d”, “i”, “a”]]
答案: A
字符串是可迭代的。 扩展运算符将迭代的每个字符映射到一个元素。
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, 10 and 10, 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。
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,是为输出结果。
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数组时,第一个元素会将引用的对象打印出来。
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。
console.log(3 + 4 + "5");
A: “345”
B: “75”
C: 12
D: “12”
答案: B
当所有运算符的 优先级 相同时,计算表达式需要确定运算符的结合顺序,即从右到左还是从左往右。在这个例子中,我们只有一类运算符+,对于加法来说,结合顺序就是从左到右。
3 + 4首先计算,得到数字7.
由于类型的强制转换,7 + '5’的结果是"75". JavaScript将7转换成了字符串,可以参考问题15.我们可以用+号把两个字符串连接起来。 “7” + “5” 就得到了"75".
const num = parseInt("7*6", 10);
A: 42
B: “42”
C: 7
D: NaN
答案: C
只返回了字符串中第一个字母. 设定了 进制 后 (也就是第二个参数,指定需要解析的数字是什么进制: 十进制、十六机制、八进制、二进制等等……),parseInt 检查字符串中的字符是否合法. 一旦遇到一个在指定进制中不合法的字符后,立即停止解析并且忽略后面所有的字符。
*就是不合法的数字字符。所以只解析到"7",并将其解析为十进制的7. num的值即为7.
[1, 2, 3].map(num => {
if (typeof num === "number") return;
return num * 2;
});
A: []
B: [null, null, null]
C: [undefined, undefined, undefined]
D: [ 3 x empty ]
答案: C
对数组进行映射的时候,num就是当前循环到的元素. 在这个例子中,所有的映射都是number类型,所以if中的判断typeof num === "number"结果都是true.
map函数创建了新数组并且将函数的返回值插入数组。
但是,没有任何值返回。当函数没有返回任何值时,即默认返回undefined.对数组中的每一个元素来说,函数块都得到了这个返回值,所以结果中每一个元素都是undefined.
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”.
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 only throw Error objects
D: "Oh no an error: Hello world!
答案: D
通过throw语句,我么可以创建自定义错误。 而通过它,我们可以抛出异常。异常可以是一个字符串, 一个 数字, 一个 布尔类型 或者是一个 对象。在本例中,我们的异常是字符串’Hello world’.
通过 catch语句,我们可以设定当try语句块中抛出异常后应该做什么处理。在本例中抛出的异常是字符串’Hello world’.
e就是这个字符串,因此被输出。最终结果就是’Oh an error: Hello world’.
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".
(() => {
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(typeof x)返回"undefined".
而我们创建了全局变量y,并且设定y等于10.这个值在我们的代码各处都访问的到。 y已经被定义了,而且有一个"number"类型的值。 console.log(typeof y)返回"number".
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在执行了delete Dog.prototype.bark后不可用, 然而后面的代码还在调用它。
当我们尝试调用一个不存在的函数时TypeError异常会被抛出。在本例中就是 TypeError: pet.bark is not a function,因为pet.bark是undefined.
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}.
// 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是只读的,不能被修改。
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的属性给全局对象。对象中的属性是可以删除的,全局对象也是如此,所以delete age返回true.
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.
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 }.
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方法添加的属性有了更多的控制权。