 Javascript 语法错题集
Javascript 语法错题集
  - 题库来源: JavaScript 进阶问题列表
# 1. 输出是什么?
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
答案
答案:B
注意 diameter 的值是一个常规函数,但是 perimeter 的值是一个箭头函数。
对于箭头函数,this 关键字指向的是它当前周围作用域(简单来说是包含箭头函数的常规函数,如果没有常规函数的话就是全局对象),这个行为和常规函数不同。这意味着当我们调用 perimeter 时,this 不是指向 shape 对象,而是它的周围作用域(在例子中是 window)。
在 window 中没有 radius 这个属性,因此返回 undefined。
# 2.所有对象都有原型
- A:对
- B:错
答案
答案:B 除了基本对象(base object),所有对象都有原型。基本对象可以访问一些方法和属性,比如 .toString。这就是为什么你可以使用内置的 JavaScript 方法!所有这些方法在原型上都是可用的。虽然 JavaScript 不能直接在对象上找到这些方法,但 JavaScript 会沿着原型链找到它们,以便于你使用。
# 3.输出是什么?
[1, 2, 3].map((num) => {
  if (typeof num === "number") return;
  return num * 2;
});
2
3
4
- A:[]
- B:[null,null,null]
- C:[undefined,undefined,undefined]
- D: [3 x empty]
答案
对数组进行映射的时候,num就是当前循环到的元素。在这个例子中,所有的映射都是 number 类型,所以 if 中的判断typeof num === "number"结果都是true.map 函数创建了新数组并且将函数的返回值插入数组。
但是,没有任何值返回。当函数没有返回任何值时,即默认返回 undefined.对数组中的每一个元素来说,函数块都得到了这个返回值,所以结果中每一个元素都是 undefined.
# 4. 输出什么?
const name = "Lydia Hallie";
console.log(name.padStart(13));
console.log(name.padStart(2));
2
3
- 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方法的参数小于字符串的长度,则不会添加填充。
# 5. 输出什么?
async function getData() {
  return await Promise.resolve("I made it!");
}
const data = getData();
console.log(data);
2
3
4
5
6
- 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!"
# 6. 输出什么?
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
答案
答案:B
Object.freeze使得无法添加、删除或修改对象的属性(除非属性的值是另一个对象)。
当我们创建变量shape并将其设置为等于冻结对象box时,shape指向的也是冻结对象。你可以使用Object.isFrozen检查一个对象是否被冻结,上述情况,Object.isFrozen(shape)将返回true。
由于shape被冻结,并且x的值不是对象,所以我们不能修改属性x。x仍然等于10,{x:10,y:20}被打印。
注意,上述例子我们对属性x进行修改,可能会导致抛出 TypeError 异常(最常见但不仅限于严格模式下时)。
# 7. 输出什么?
const { name: myName } = { name: "Lydia" };
console.log(name);
2
3
- A: "Lydia"
- B: "myName"
- C: undefined
- D: ReferenceError
答案
答案:D
当我们从右侧的对象解构属性name时,我们将其值Lydia分配给名为myName的变量。
使用{name:myName},我们是在告诉 JavaScript 我们要创建一个名为myName的新变量,并且其值是右侧对象的name属性的值。
当我们尝试打印name,一个未定义的变量时,就会引发ReferenceError。
# 8. 输出什么?
var status = "😎";
setTimeout(() => {
  const status = "😍";
  const data = {
    status: "🥑",
    getStatus() {
      return this.status;
    },
  };
  console.log(data.getStatus());
  console.log(data.getStatus.call(this));
}, 0);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- A: "🥑"and"😍"
- B: "🥑"and"😎"
- C: "😍"and"😎"
- D: "😎"and"😎"
答案
答案:B
this关键字的指向取决于使用它的位置。在函数中,比如getStatus,this指向的是调用它的对象,上述例子中data对象调用了getStatus,因此this指向的就是data对象。当我们打印this.status时,data对象的status属性被打印,即"🥑"。
使用call方法,可以更改this指向的对象。data.getStatus.call(this)是将this的指向由data对象更改为全局对象。在全局对象上,有一个名为status的变量,其值为”😎“。因此打印this.status时,会打印“😎”。
# 9. 输出什么?
const person = {
  name: "Lydia",
  age: 21,
};
for (const [x, y] of Object.entries(person)) {
  console.log(x, y);
}
2
3
4
5
6
7
8
- A: nameLydiaandage21
- B: ["name", "Lydia"]and["age", 21]
- C: ["name", "age"]andundefined
- D: Error
答案
答案:A
Object.entries()方法返回一个给定对象自身可枚举属性的键值对数组,上述情况返回一个二维数组,数组每个元素是一个包含键和值的数组:
[['name','Lydia'],['age', 21]]
使用for-of循环,我们可以迭代数组中的每个元素,上述情况是子数组。我们可以使用const [x,y]在for-of循环中解构子数组。x等于子数组中的第一个元素,y等于子数组中的第二个元素。
第一个子阵列是[“name”,“Lydia”],其中x等于name,而y等于Lydia。
第二个子阵列是[“age”,21],其中x等于age,而y等于21。
# 10. 输出什么?
const getList = ([x, ...y]) => [x, y]
const getUser = user => { name: user.name, age: user.age }
const list = [1, 2, 3, 4]
const user = { name: "Lydia", age: 21 }
console.log(getList(list))
console.log(getUser(user))
2
3
4
5
6
7
8
- A: [1, [2, 3, 4]]andSyntaxError
- B: [1, [2, 3, 4]]and{ name: "Lydia", age: 21 }
- C: [1, 2, 3, 4]and{ name: "Lydia", age: 21 }
- D: Errorand{ name: "Lydia", age: 21 }
答案
答案:A
getList函数接受一个数组作为其参数。在getList函数的括号之间,我们立即解构这个数组。您可以将其视为:
[x, ...y] = [1, 2, 3, 4]
使用剩余的参数... y,我们将所有剩余参数放在一个数组中。在这种情况下,其余的参数是2,3和4。 y的值是一个数组,包含所有其余参数。在这种情况下,x的值等于1,所以当我们打印[x,y]时,会打印[1,[2,3,4]]。
getUser函数接受一个对象。对于箭头函数,如果只返回一个值,我们不必编写花括号。但是,如果您想从一个箭头函数返回一个对象,您必须将它写在圆括号之间,否则两个花括号之间的所有内容都将被解释为一个块语句!在这种情况下,花括号之间的代码不是有效的 JavaScript 代码,因此会抛出 SyntaxError。
以下函数将返回一个对象:
const getUser = user => ({ name: user.name, age: user.age })
# 11. 输出什么?
const name = "Lydia";
console.log(name());
2
3
- A: SyntaxError
- B: ReferenceError
- C: TypeError
- D: undefined
答案
答案:C
变量name保存字符串的值,该字符串不是函数,因此无法调用。
当值不是预期类型时,会抛出TypeErrors。JavaScript 期望name是一个函数,因为我们试图调用它。但它是一个字符串,因此抛出TypeError:name is not a function
当你编写了一些非有效的 JavaScript 时,会抛出语法错误,例如当你把return这个词写成retrun时。
当 JavaScript 无法找到您尝试访问的值的引用时,抛出ReferenceErrors。
# 12.输出什么?
const one = false || {} || null;
const two = null || false || "";
const three = [] || 0 || true;
console.log(one, two, three);
2
3
4
5
- A: falsenull[]
- B: null""true
- C: {}""[]
- D: nullnulltrue
答案
答案:C
使用||运算符,我们可以返回第一个真值。如果所有值都是假值,则返回最后一个值。
(false || {} || null):空对象{}是一个真值。这是第一个(也是唯一的)真值,它将被返回。one等于{}。
(null || false ||“”):所有值都是假值。这意味着返回传递的值""。two等于""。
([] || 0 ||“”):空数组[]是一个真值。这是第一个返回的真值。three等于[]。
# 13. 输出什么?
function* generatorOne() {
  yield ["a", "b", "c"];
}
function* generatorTwo() {
  yield* ["a", "b", "c"];
}
const one = generatorOne();
const two = generatorTwo();
console.log(one.next().value);
console.log(two.next().value);
2
3
4
5
6
7
8
9
10
11
12
13
- A: aanda
- B: aandundefined
- C: ['a', 'b', 'c']anda
- D: aand['a', 'b', 'c']
答案
答案:C
通过 yield 关键字,我们在 Generator 函数里执行yield表达式。通过 yield* 关键字,我们可以在一个Generator 函数里面执行(yield表达式)另一个 Generator 函数,或可遍历的对象 (如数组).
在函数 generatorOne 中,我们通过 yield 关键字 yield 了一个完整的数组 ['a', 'b', 'c']。函数one通过next方法返回的对象的value 属性的值 (one.next().value) 等价于数组 ['a', 'b', 'c'].
console.log(one.next().value); // ['a', 'b', 'c']
console.log(one.next().value); // undefined
2
在函数 generatorTwo 中,我们使用 yield* 关键字。就相当于函数two第一个yield的值,等价于在迭代器中第一个 yield 的值。数组['a', 'b', 'c']就是这个迭代器。第一个 yield 的值就是 a,所以我们第一次调用 two.next().value时,就返回a。
console.log(two.next().value); // 'a'
console.log(two.next().value); // 'b'
console.log(two.next().value); // 'c'
console.log(two.next().value); // undefined
2
3
4
# 14. 将会发生什么?
let config = {
  alert: setInterval(() => {
    console.log("Alert!");
  }, 1000),
};
config = null;
2
3
4
5
6
7
- A: setInterval的回调不会被调用
- B: setInterval的回调被调用一次
- C: setInterval的回调仍然会被每秒钟调用
- D: 我们从没调用过 config.alert(), config 为null
答案
答案:C
一般情况下当我们将对象赋值为 null,那些对象会被进行 垃圾回收(garbage collected) 因为已经没有对这些对象的引用了。然而,setInterval的参数是一个箭头函数(所以上下文绑定到对象 config 了),回调函数仍然保留着对 config的引用。只要存在引用,对象就不会被垃圾回收。因为没有被垃圾回收,setInterval 的回调每 1000ms (1s) 会被调用一次。
# 15. 输出什么?
const name = "Lydia Hallie";
console.log(!typeof name === "object");
console.log(!typeof name === "string");
2
3
4
- A: falsetrue
- B: truefalse
- C: falsefalse
- D: truetrue
答案
答案:C
typeof name 返回 "string"。字符串 "string" 是一个 truthy 的值,因此 !typeof name 返回一个布尔值 false。false === "object" 和 false === "string" 都返回 false。
(如果我们想检测一个值的类型,我们应该用 !== 而不是 !typeof)
# 16. 输出什么?
const myFunc = ({ x, y, z }) => {
  console.log(x, y, z);
};
myFunc(1, 2, 3);
2
3
4
5
- A: 123
- B: {1: 1}{2: 2}{3: 3}
- C: { 1: undefined }undefinedundefined
- D: undefinedundefinedundefined
答案
答案:D
myFunc 期望接受一个包含 x, y 和 z 属性的对象作为它的参数。因为我们仅仅传递三个单独的数字值 (1, 2, 3) 而不是一个含有 x, y 和 z 属性的对象 ({x: 1, y: 2, z: 3}),x, y 和 z 有着各自的默认值 undefined.
# 17. 输出什么?
const name = "Lydia Hallie";
const age = 21;
console.log(Number.isNaN(name));
console.log(Number.isNaN(age));
console.log(isNaN(name));
console.log(isNaN(age));
2
3
4
5
6
7
8
- A: truefalsetruefalse
- B: truefalsefalsefalse
- C: falsefalsetruefalse
- D: falsetruefalsetrue
答案
答案:C
通过方法 Number.isNaN,你可以检测你传递的值是否为 数字值 并且是否等价于 NaN。name 不是一个数字值,因此 Number.isNaN(name) 返回 false。age 是一个数字值,但它不等价于 NaN,因此 Number.isNaN(age) 返回 false.
通过方法 isNaN,你可以检测你传递的值是否一个 number。name 不是一个 number,因此 isNaN(name) 返回 true. age 是一个 number 因此 isNaN(age) 返回 false.
# 18. 以下哪一项会对对象 person 有副作用?
 const person = { name: "Lydia Hallie" };
Object.seal(person);
2
3
- A: person.name = "Evan Bacon"
- B: person.age = 21
- C: delete person.name
- D: Object.assign(person, { age: 21 })
答案
答案:A
使用 Object.seal 我们可以防止新属性 被添加,或者存在属性 被移除.
然而,你仍然可以对存在属性进行更改。
# 19. 输出什么?
class Bird {
  constructor() {
    console.log("I'm a bird. 🦢");
  }
}
class Flamingo extends Bird {
  constructor() {
    console.log("I'm pink. 🌸");
    super();
  }
}
const pet = new Flamingo();
2
3
4
5
6
7
8
9
10
11
12
13
14
- A: I'm pink. 🌸
- B: I'm pink. 🌸I'm a bird. 🦢
- C: I'm a bird. 🦢I'm pink. 🌸
- D: Nothing, we didn't call any method
答案
答案:B
我们创建了类 Flamingo 的实例 pet。当我们实例化这个实例,Flamingo 中的 constructor 被调用。首相,输出 "I'm pink. 🌸",之后我们调用super()。super() 调用父类的构造函数,Bird。Bird 的构造函数被调用,并输出 "I'm a bird. 🦢"。
# 20. 哪一个选项会导致报错?
const emojis = ["🎄", "🎅🏼", "🎁", "⭐"];
/* 1 */ emojis.push("🦌");
/* 2 */ emojis.splice(0, 2);
/* 3 */ emojis = [...emojis, "🥂"];
/* 4 */ emojis.length = 0;
2
3
4
5
6
- A: 1
- B: 1 and 2
- C: 3 and 4
- D: 3
答案
答案:D
const 关键字意味着我们不能 重定义 变量中的值,它 仅可读。然而,值本身不可修改。数组 emojis 中的值可被修改,如 push 新的值,拼接,又或者将数组的长度设置为 0。
# 21. 输出什么?
const createMember = ({ email, address = {} }) => {
  const validEmail = /.+\@.+\..+/.test(email);
  if (!validEmail) throw new Error("Valid email pls");
  return {
    email,
    address: address ? address : null,
  };
};
const member = createMember({ email: "my@email.com" });
console.log(member);
2
3
4
5
6
7
8
9
10
11
12
- A: { email: "my@email.com", address: null }
- B: { email: "my@email.com" }
- C: { email: "my@email.com", address: {} }
- D: { email: "my@email.com", address: undefined }
答案
答案:C
address 的默认值是一个空对象 {}。当我们设置 member 变量为 createMember 函数返回的对象,我们没有为 address 参数传值,意味着 address 的值为默认的空对象 {}。一个空对象是一个 truthy 值,意味着 address ? address : null 条件会返回 true。address 的值为空对象 {}。
# 22. 输出什么?
const user = {
  email: "my@email.com",
  updateEmail: (email) => {
    this.email = email;
  },
};
user.updateEmail("new@email.com");
console.log(user.email);
2
3
4
5
6
7
8
9
- A: my@email.com
- B: new@email.com
- C: undefined
- D: ReferenceError
答案
答案:A
updateEmail 函数是一个箭头函数,它没有和 user 对象绑定。这就意味着 this 关键字不会引用到 user 对象,但是会引用到全局对象。user 对象内部的 email 的值不会更新。当打印 user.email 的时候,原始值 my@email.com 被返回。
