JavaScript代码题目


类型问题

  1. var let 变量

    function sayHi() {
      console.log(name);
      console.log(age);
      var name = 'Lydia';
      let age = 21;
    }
    
    sayHi();
    • A: Lydia and undefined
    • B: Lydia and ReferenceError
    • C: ReferenceError and 21
    • D: undefined and ReferenceError
    Answer

    Answer: D

    在函数中,我们使用了 var 关键词来声明name 变量,这导致变量被提升(内存空间在创建阶段设置),默认值为undefined,直到该变量被定义的那一行。

    而带有 let关键字 (和 const)的变量会被提升,但和 var不同的是,它不会被初始化。在我们初始化它们之前,它们是不可访问的,这被称为“时间死区”。

    当我们尝试在声明变量之前访问变量时,JavaScript 会抛出 ReferenceError

  2. 对象解释

    const bird = {
      size: 'small',
    };
    
    const mouse = {
      name: 'Mickey',
      small: true,
    };
    • A: mouse.bird.size is not valid
    • B: mouse[bird.size] is not valid
    • C: mouse[bird["size"]] is not valid
    • D: All of them are valid
    Answer

    Answer: A

    在 JavaScript 中,所有对象键都是字符串(除非它是 Symbol)。尽管我们可能不会将它们输入为字符串,但它们总是会在底层转换为字符串。 当使用方括号表示法时,JavaScript会进行解释(或解包)语句。它看到第一个开放的方括号[,然后继续查找直到找到闭合的方括号]。只有在找到闭合的方括号后,它才会评估语句。

    在这个例子中,mouse[bird.size]首先评估bird.size,它的值是"small"。然后,mouse["small"]返回true

    然而,使用点表示法时,这种情况不会发生。mouse没有一个名为bird的键,这意味着mouse.birdundefined的。然后,我们使用点表示法来获取sizemouse.bird.size。由于mouse.birdundefined的,实际上我们正在请求undefined.size。这是无效的,并且会引发类似于Cannot read property "size" of undefined

  3. 引用类型赋值

    let c = { greeting: 'Hey!' };
    let d;
    
    d = c;
    c.greeting = 'Hello';
    console.log(d.greeting);
    • A: Hello
    • B: Hey!
    • C: undefined
    • D: ReferenceError
    • E: TypeError
    Answer

    **Answer: A**

    Answer: A

    在JavaScript中,当将一个对象赋值给另一个对象时,它们之间是通过引用进行交互的。这意味着,当我们将一个对象赋值给另一个变量时,实际上是将该对象的引用复制到了新变量中,而不是将对象本身复制到新变量中。

    在这个例子中,变量c保存了一个对象的值。稍后,我们将d赋值为与c具有相同引用的对象。这意味着,cd现在都引用同一个对象,因此对该对象的任何更改都会反映在c和d中。这种交互方式可以节省内存,因为它避免了在内存中复制大量的对象。但需要注意的是,如果我们想要复制一个对象而不是引用它,我们需要使用深拷贝(deep copy)或浅拷贝(shallow copy)的技术。

    当你改变一个对象时,所有引用该对象的变量都会改变。

  4. 变量赋值

    let greeting;
    greetign = {}; // Typo!
    console.log(greetign);
    • A: {}
    • B: ReferenceError: greetign is not defined
    • C: undefined
    Answer

    Answer: A

    它记录了对象,因为我们刚刚在全局对象上创建了一个空对象!当我们将greeting拼写错误为greetign时,JS解释器实际上将其视为:

    • 在Node.js中,global.greetign = {}
    • 在浏览器中,window.greetign = {}frames.geetign = {}self.greetign
    • 在Web Workers中,self.greetign
    • 在所有环境中globalThis.greetign
    • 为了避免这种情况,我们可以使用"use strict"。这可以确保在将变量设置为任何值之前已经声明了它。
  5. var 关键字

    var num = 8;
    var num = 10;
    
    console.log(num);
    • A: 8
    • B: 10
    • C: SyntaxError
    • D: ReferenceError
    Answer

    Answer: B

    使用var关键字,您可以声明多个具有相同名称的变量。变量将保存最新的值。

    使用letconst无法这样做,因为它们是块作用域的。

  6. 检测键的存在

    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
    Answer

    Answer: C

    所有对象的键(不包括 Symbols)在底层都是字符串,即使您没有将其键入为字符串。这就是为什么obj.hasOwnProperty('1')也返回true的原因。

    但是对于集合来说,情况并非如此。我们的集合中没有'1',所有set.has('1')返回false。它具有数字类型1set.has(1)返回true

  7. 重复的键

    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
    Answer

    **Answer: B**

    Answer: B

    如果您有两个具有相同名称的键,则该键将被替换。它仍将位于其第一个位置,但具有最后指定的值。

  8. 原型方法

    String.prototype.giveLydiaPizza = () => {
      return 'Just give Lydia pizza already!';
    };
    
    const name = 'Lydia';
    
    console.log(name.giveLydiaPizza())
    • A: "Just give Lydia pizza already!"
    • B: TypeError: not a function
    • C: SyntaxError
    • D: undefined
    Answer

    Answer: A

    String是一个内置的构造函数,我们可以向其添加属性。我刚刚向其原型添加了一个方法。原始字符串会自动转换为由字符串原型函数生成的字符串对象。因此,所有字符串(字符串对象)都可以访问该方法!这意味着,如果您向字符串原型添加一个方法,那么所有字符串都可以使用该方法。

  9. 将对象作为键

    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
    Answer

    Answer: B

    这段代码中,我们尝试将一个对象作为键设置到对象a中,并将其值设置为123。然而,当我们将一个对象转换为字符串时,它会变成"[object Object]"。因此,我们实际上是在说a["[object Object]"] = 123。然后,我们尝试再次做同样的事情。c是另一个我们隐式转换为字符串的对象。因此,a["[object Object]"] = 456。然后,我们记录a[b],实际上是a["[object Object]"]。我们刚刚将其设置为456,因此它返回456

    这段代码中的关键点是对象键自动转换为字符串,因此需要小心处理对象键。

  10. 类型判断再判断

    console.log(typeof typeof 1);
    • A: "number"
    • B: "string"
    • C: "object"
    • D: "undefined"
    Answer

    Answer: B

    typeof 1 返回 "number". typeof "number" 返回 "string"

  11. 数组定义

    const numbers = [1, 2, 3];
    numbers[10] = 11;
    console.log(numbers);
    • A: [1, 2, 3, null x 7, 11]
    • B: [1, 2, 3, 11]
    • C: [1, 2, 3, empty x 7, 11]
    • D: SyntaxError
    Answer

    Answer: C

    当你给数组中的一个元素设置一个超过数组长度的值时,JavaScript会创建一些被称为"empty slots"(空槽)的东西。实际上,它们的值是undefined,但你会看到类似于以下的结果:

    [1, 2, 3, 空 x 7, 11]

    具体的显示方式取决于你运行代码的环境(不同浏览器、Node等)。

  12. 类型判断

    !!null;
    !!'';
    !!1;
    • A: false true false
    • B: false false true
    • C: false true true
    • D: true true false
    Answer

    Answer: B

    null是假值。!null返回 true!true 返回 false

    "" 是假值。!"" 返回 true!true 返回 false

    1 是真值。!1 返回 false!false 返回 true

  13. 对象的引用

    let person = { name: 'Lydia' };
    const members = [person];
    person = null;
    
    console.log(members);
    • A: null
    • B: [null]
    • C: [{}]
    • D: [{ name: "Lydia" }]
    Answer

    Answer: D

    首先,我们声明一个变量person,并赋值为一个具有name属性的对象。

    然后,我们声明一个名为members的变量。我们将该数组的第一个元素设置为person变量的值。当将对象相互赋值时,它们通过引用进行交互。当将一个变量的引用赋给另一个变量时,会复制该引用。(请注意,它们不具有相同的引用!

    然后,我们将变量person的值设置为null

    我们只修改了person变量的值,而没有修改数组中的第一个元素,因为该元素具有与对象的不同(已复制的)引用。members数组中的第一个元素仍然保留对原始对象的引用。当我们记录(log)members数组时,第一个元素仍然保留着对象的值,并将其记录下来。

  14. 对象循环

    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]
    Answer

    Answer: B

    使用for-in循环,我们可以迭代对象的键(在这种情况下为name和age)。在底层,对象的键是字符串(如果它们不是Symbol类型)。在每次循环中,我们将item的值设置为当前迭代的键。首先,item等于name,并进行记录。然后,item等于age,并进行记录。

  15. 箭头函数和类型判断

    (() => {
      let x = (y = 10);
    })();
    
    console.log(typeof x);
    console.log(typeof y);
    • A: "undefined", "number"
    • B: "number", "number"
    • C: "object", "number"
    • D: "number", "undefined"
    Answer

    Answer: A

    let x = (y = 10); 实际上是以下代码的简写形式:

    y = 10; 
    let x = y; 

    当我们将y设置为10时,实际上是向全局对象添加了一个属性y(在浏览器中是window对象,在Node中是global对象)。在浏览器中,window.y现在等于10

    然后,我们声明一个变量x,其值为y,即10。使用let关键字声明的变量是块级作用域的,它们只在声明它们的块中定义;在这种情况下是立即调用的函数表达式(IIFE)。当我们使用typeof运算符时,操作数x未定义:我们试图在声明它的块之外访问x。这意味着x未定义。尚未被赋值或声明的值的类型是"undefined"console.log(typeof x)返回"undefined"

    然而,当我们将y设置为10时,我们创建了一个全局变量y。这个值可以在我们的代码的任何地方访问。y已经定义,并且具有"number"类型的值。console.log(typeof y)返回"number"

  16. 数组赋值

    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]
    Answer

    Answer: C

    我们可以通过解构来从数组中解包值或从对象中解包属性。例如:

    [a, b] = [1, 2];

    现在a的值是1b的值是2。在问题中实际上我们做的是:

    [y] = [1, 2, 3, 4, 5];

    这意味着y的值等于数组中的第一个值,即数字1。当我们记录y时,返回的是1

  17. 类型比较

    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
    Answer

    Answer: A

    每个Symbol都是完全唯一的。传递给Symbol的参数只是给Symbol的一个描述。 Symbol的值不依赖于传递的参数。 当我们测试相等时,我们创建了两个全新的符号:第一个Symbol('foo'),第二个Symbol('foo'),这两个值是唯一的,彼此不相等,因此返回false

  18. 对象解构

    const { name: myName } = { name: "Lydia" };
    
    console.log(name);
    • A: "Lydia"
    • B: "myName"
    • C: undefined
    • D: ReferenceError
    Answer

    Answer: D

    当我们从右侧的对象解构属性name时,我们将其值Lydia分配给名为myName的变量。

    使用{name:myName},我们是在告诉 JavaScript 我们要创建一个名为myName的新变量,并且其值是右侧对象的name属性的值。

    当我们尝试打印name,一个未定义的变量时,就会引发ReferenceError

  19. 对象引用

    const person = {
      name: "Lydia",
      age: 21
    }
    
    let city = person.city
    city = "Amsterdam"
    
    console.log(person)
    • A: { name: "Lydia", age: 21 }
    • B: { name: "Lydia", age: 21, city: "Amsterdam" }
    • C: { name: "Lydia", age: 21, city: undefined }
    • D: "Amsterdam"
    Answer

    Answer: A

    我们将变量city设置为等于person对象上名为city的属性的值。 这个对象上没有名为city的属性,因此变量city的值为undefined

    请注意,我们没有引用person对象本身,只是将变量city设置为等于person对象上city属性的当前值。

    然后,我们将city设置为等于字符串“Amsterdam”。 这不会更改 person 对象:没有对该对象的引用

    因此打印person对象时,会返回未修改的对象。

  20. Symbol类型

    const info = {
      [Symbol('a')]: 'b'
    }
    
    console.log(info)
    console.log(Object.keys(info))
    • A: {Symbol('a'): 'b'} and ["{Symbol('a')"]
    • B: {} and []
    • C: { a: "b" } and ["a"]
    • D: {Symbol('a'): 'b'} and []
    Answer

    Answer: D

    Symbol类型是不可枚举的。Object.keys方法返回对象上的所有可枚举的键属性。Symbol类型是不可见的,并返回一个空数组。 记录整个对象时,所有属性都是可见的,甚至是不可枚举的属性。

    这是Symbol的众多特性之一:除了表示完全唯一的值(防止对象意外名称冲突,例如当使用 2 个想要向同一对象添加属性的库时),您还可以隐藏这种方式对象的属性(尽管不完全。你仍然可以使用Object.getOwnPropertySymbols()方法访问 Symbol

  21. 错误类型

    const name = "Lydia"
    
    console.log(name())
    • A: SyntaxError
    • B: ReferenceError
    • C: TypeError
    • D: undefined
    Answer

    Answer: C

    变量name保存字符串的值,该字符串不是函数,因此无法调用。

    当值不是预期类型时,会抛出TypeErrors。 JavaScript 期望name是一个函数,因为我们试图调用它。 但它是一个字符串,因此抛出TypeErrorname is not a function

    当你编写了一些非有效的 JavaScript 时,会抛出语法错误,例如当你把return这个词写成retrun时。 当 JavaScript 无法找到您尝试访问的值的引用时,抛出ReferenceErrors

  22. 或运算符

    const one = (false || {} || null)
    const two = (null || false || "")
    const three = ([] || 0 || true)
    
    console.log(one, two, three)
    • A: false null []
    • B: null "" true
    • C: {} "" []
    • D: null null true
    Answer

    Answer: C

    使用||运算符,我们可以返回第一个真值。 如果所有值都是假值,则返回最后一个值。

    (false || {} || null):空对象{}是一个真值。 这是第一个(也是唯一的)真值,它将被返回。one等于{}

    (null || false ||""):所有值都是假值。 这意味着返回传递的值""two等于""

    ([] || 0 ||""):空数组[]是一个真值。 这是第一个返回的真值。 three等于[]

  23. 与运算符

    // 🎉✨ This is my 100th question! ✨🎉
    
    const output = `${[] && 'Im'}possible!
    You should${'' && `n't`} see a therapist after so much JavaScript lol`
    • A: possible! You should see a therapist after so much JavaScript lol
    • B: Impossible! You should see a therapist after so much JavaScript lol
    • C: possible! You shouldn't see a therapist after so much JavaScript lol
    • D: Impossible! You shouldn't see a therapist after so much JavaScript lol
    Answer

    Answer: B

    []是一个真值。 使用&&运算符,如果左侧值是真值,则返回右侧值。 在这种情况下,左侧值[]是一个真值,所以返回Im

    ""是一个假值。 如果左侧值是假的,则不返回任何内容。 n't不会被退回。

  24. 变量提升和函数作用域

    var x = 1;
    function foo() {
      x = 10;
      return;
      function x() {}
    }
    foo();
    console.log(x); 
    Answer

    函数声明的提升优先级高于变量声明。如果在同一个作用域内,函数声明和变量声明的名字相同,那么函数声明会覆盖变量声明。

    但是此处var xfunction foo() 是在全局作用域中,而 function x() 是在 foo 函数的局部作用域中。所以,function foo()var x 的提升是在全局作用域中进行的,而 function x() 的提升是在 foo 函数的局部作用域中进行的。

    所以提升的顺序如下:

    var x = undefined;
    function foo() {
      function x() {}
      x = 10;
      return;
    }
    x = 1;
    foo();
    console.log(x);

    当 JavaScript 引擎执行到 x = 10 这一行时,它实际上是修改了 foo 函数作用域内的 x,将其从一个函数改变为了一个数值 10

    但是,这个改变并不影响外部的变量 x,因此,当执行 console.log(x) 时,输出的仍然是 1,这是因为外部的变量 x 并没有被改变。

  25. 函数内部变量提升

    var name = "Lokesh Prajapati";
    (function () {
        console.log(name);
        var name = "foo";
    })(); 
    Answer

    在 JavaScript 中,函数会创建自己的作用域,也被称为局部作用域。在函数内部声明的变量(包括参数)只在该函数内部可见,这被称为变量的局部性。这意味着在函数内部可以使用与外部全局变量同名的变量,而不会影响到全局变量。

    变量和函数声明会被提升到它们所在的作用域的顶部

    var name 在函数作用域内被提升,所以在函数内部的 console.log(name) 执行时,name 已经被声明,但还没有被赋值,因此其值为 undefined

  26. 函数提升、函数声明、变量声明顺序

    function sayHelloWorld() {
        return sayGoodbyWorld();
        var sayGoodbyWorld = function () {
            return "Hello, World!";
        };
    
        function sayGoodbyWorld() {
            return "Goodbye, World!";
        }
    }
    console.log(sayHelloWorld());
    Answer

    函数声明和变量声明都被提升到函数作用域的顶部,但是变量的赋值并没有被提升,所以函数声明会覆盖变量声明。

    所以最后返回的是函数 sayGoodbyWorld(),输出 "Goodbye, World!"

  27. 类型转换,真值和假值

    console.log([] == ![]);
    Answer

    在 JavaScript 中,== 运算符在比较两个值时,如果它们的类型不同,会进行类型转换。

    首先,![] 的结果是 false,因为在 JavaScript 中,空数组是一个真值(truthy value),对其进行逻辑非操作得到 false

    然后,[] == false 的结果是 true。这是因为在进行比较时,两边的值都会被转换为数字。空数组 [] 被转换为数字得到 0false 被转换为数字也得到 0,所以 0 == 0 的结果是 true

    在 JavaScript 中,以下值被认为是假值(falsy):

    • false
    • 0NaN
    • ""(空字符串)
    • null
    • undefined
    • BigInt(0)(仅在支持 BigInt 的环境中)
  28. s

类的问题

  1. 类中方法调用

    class Chameleon {
      static colorChange(newColor) {
        this.newColor = newColor;
        return this.newColor;
      }
    
      constructor({ newColor = 'green' } = {}) {
        this.newColor = newColor;
      }
    }
    
    const freddie = new Chameleon({ newColor: 'purple' });
    console.log(freddie.colorChange('orange'));
    • A: orange
    • B: purple
    • C: green
    • D: TypeError
    Answer

    Answer: D

    colorChange函数是一个静态方法,它只能存在于创建它的构造函数中,不能被传递给任何子类或在类实例上调用。因此,由于freddie是Chameleon类的一个实例,不能在它上面调用colorChange函数,会抛出TypeError错误。

  2. 原型添加方法与删除

    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
    Answer

**Answer: A**

Answer: A

我们可以使用delete关键字从对象中删除属性,也可以从原型上删除属性。通过从原型上删除属性,该属性将不再在原型链中可用。在这种情况下,在删除了Dog.prototype.bark之后,bark函数在原型上不再可用,但我们仍然尝试访问它。

当我们试图调用不是函数的东西时,会抛出TypeError错误。在这种情况下,抛出的错误是TypeError: pet.bark is not a function,因为pet.barkundefined

  1. 使用哪个构造函数可以成功继承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
    Answer

    Answer: B

    在子类中,在调用super之前不能访问到this关键字。 如果这样做,它将抛出一个ReferenceError:1 和 4 将引发一个引用错误。

    使用super关键字,需要用给定的参数来调用父类的构造函数。 父类的构造函数接收name参数,因此我们需要将name传递给super

    Labrador类接收两个参数,name参数是由于它继承了Dogsize作为Labrador类的额外属性,它们都需要传递给Labrador的构造函数,因此使用构造函数 2 正确完成。

  2. 实例对象

    class Person {
      constructor(name) {
        this.name = name
      }
    }
    
    const member = new Person("John")
    console.log(typeof member)
    • A: "class"
    • B: "function"
    • C: "object"
    • D: "string"
    Answer

    Answer: C

    类是构造函数的语法糖,如果用构造函数的方式来重写Person类则将是:

    function Person() {
      this.name = name
    }

    通过new来调用构造函数,将会生成构造函数Person的实例,对实例执行typeof关键字将返回"object",上述情况打印出"object"

  3. 类的设置

    class Person {
      constructor() {
        this.name = "Lydia"
      }
    }
    
    Person = class AnotherPerson {
      constructor() {
        this.name = "Sarah"
      }
    }
    
    const member = new Person()
    console.log(member.name)
    • A: "Lydia"
    • B: "Sarah"
    • C: Error: cannot redeclare Person
    • D: SyntaxError
    Answer

    **Answer: B**

    Answer: B

    我们可以将类设置为等于其他类/函数构造函数。 在这种情况下,我们将Person设置为AnotherPerson。 这个构造函数的名字是Sarah,所以新的Person实例member上的 name 属性是Sarah

  4. 原型和继承

    function Parent() {}
    
    function Child() {}
    Child.prototype = new Parent();
    var obj = new Child();
    console.log(obj instanceof Parent);
    Answer

    在 JavaScript 中,instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

    Child.prototype = new Parent();Child 的原型设置为 Parent 的一个实例。这意味着 Child 的原型链上包含了 Parent 的原型。

    然后,var obj = new Child(); 创建了一个 Child 的实例 obj。由于 Child 的原型链上包含了 Parent 的原型,所以 obj 的原型链上也包含了 Parent 的原型。

    所以,当执行 console.log(obj instanceof Parent); 时,检测 obj 的原型链上是否包含 Parent 的原型,结果为 true,所以输出的是 true

  5. 基于原型的继承和函数引用相等性

    function Person(name) {
      this.name = name;
    }
    
    Person.prototype.greet = function() {
      return "Hello, my name is " + this.name;
    };
    
    var person1 = new Person("张三");
    var person2 = new Person("李四");
    
    console.log(person1.greet === person2.greet);  
    Answer

    在 JavaScript 中,当我们创建一个新的对象通过一个构造函数,这个对象会继承构造函数的 prototype 属性。所有的实例对象共享它们的构造函数的 prototype。这意味着它们可以访问相同的方法,这些方法是定义在构造函数的 prototype 上的。

    在你的代码中,Person.prototype.greet 是一个方法,所有的 Person 实例都可以访问这个方法。所以,person1.greetperson2.greet 实际上指向的是同一个函数。

    尽管 person1person2name 属性是不同的,但他们的 greet 方法是相同的。

    如果你想比较 person1.greet()person2.greet() 的返回值是否相同,你可以直接比较他们的返回值。例如:

    console.log(person1.greet() === person2.greet());

  6. 上的

函数问题

  1. 循环变量

    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 and 0 1 2
    • B: 0 1 2 and 3 3 3
    • C: 3 3 3 and 0 1 2
    Answer

    Answer: C

    在JavaScript中,由于事件队列的存在,setTimeout回调函数在循环执行后才被调用。在第一个循环中,变量i使用var关键字声明,因此该值是全局的。在循环期间,我们每次使用一元运算符++i的值增加1。因此,在循环中使用var声明变量时,每次循环都会覆盖上一次循环中的变量值,最终导致所有的变量都共享同一个值。当setTimeout回调函数被调用时,第一个示例中的i等于3。

    在第二个循环中,变量i使用let关键字声明:使用let(和const)关键字声明的变量是块作用域的(块是{ }之间的任何内容)。在每次迭代期间,i将具有新值,并且每个值都在循环内部作用域。

  2. 函数属性

    function bark() {
      console.log('Woof!');
    }
    
    bark.animal = 'dog';
    • A: 无事发生,这种写法完全正确。
    • B: SyntaxError。你不能以这种方式向函数添加属性。
    • C: 输出的结果是字符串"Woof"
    • D: ReferenceError
    Answer

    **Answer: A**

    Answer: A

    这在JavaScript中是可能的,因为函数是对象!(除了原始类型之外,所有东西都是对象)

    函数是一种特殊类型的对象。你自己编写的代码并不是实际的函数。函数是一个带有属性的对象。这个属性是可调用的。

  3. 原型方法

    function Person(firstName, lastName) {
      this.firstName = firstName;
      this.lastName = lastName;
    }
    
    const member = new Person('Lydia', 'Hallie');
    Person.getFullName = function() {
      return `${this.firstName} ${this.lastName}`;
    };
    
    console.log(member.getFullName());
    • A: TypeError
    • B: SyntaxError
    • C: Lydia Hallie
    • D: undefined undefined
    Answer

    Answer: A

    在JavaScript中,函数是对象。因此,方法getFullName被添加到构造函数对象本身中。因此,我们可以调用Person.getFullName(),但是member.getFullName会抛出TypeError错误。如果你想让一个方法对所有对象实例都可用,你必须将它添加到原型属性中(这是因为原型属性是所有对象实例共享的):

    Person.prototype.getFullName = function() {
      return `${this.firstName} ${this.lastName}`;
    };
  4. 函数作用域

    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"} and undefined
    • B: Person {firstName: "Lydia", lastName: "Hallie"} and Person {firstName: "Sarah", lastName: "Smith"}
    • C: Person {firstName: "Lydia", lastName: "Hallie"} and {}
    • D: Person {firstName: "Lydia", lastName: "Hallie"} and ReferenceError
    Answer

    Answer: A

    对于sarah,我们没有使用new关键字。当使用new时,this指的是我们创建的新空对象。然而,如果你不加newthis指的是全局对象

    我们说this.firstName等于"Sarah"this.lastName等于"Smith"。实际上,我们定义了global.firstName='Sarah'global.lastName='Smith'sarah本身是undefined,因为我们没有从Person函数中返回一个值。

    在JavaScript中,如果我们想要创建一个正确的对象,我们可以使用return语句或者使用new关键字。如果我们使用return语句,我们可以在函数内部返回一个新的对象,这个对象将成为函数的返回值。如果我们使用new关键字,我们可以创建一个新的空对象,并将它作为函数内部的this关键字的值。然后,我们可以在函数内部使用this关键字来设置新对象的属性和方法。最后,函数将返回这个新对象。无论是使用return语句还是使用new关键字,我们都可以创建一个正确的对象。

  5. 函数参数

    function getAge(...args) {
      console.log(typeof args);
    }
    
    getAge(21);
    • A: "number"
    • B: "array"
    • C: "object"
    • D: "NaN"
    Answer

    Answer: C

    rest参数(…args)允许我们将所有剩余的参数“收集”到一个数组中。数组是一个对象,因此typeof args返回"object"。这意味着我们可以使用数组的方法来操作这些参数。例如,我们可以使用args.length来获取传递的参数的数量,或者使用args.forEach来遍历这些参数。使用rest参数可以使函数更加灵活,因为它允许我们接受任意数量的参数。

  6. 严格模式

    function getAge() {
      'use strict';
      age = 21;
      console.log(age);
    }
    
    getAge();
    • A: 21
    • B: undefined
    • C: ReferenceError
    • D: TypeError
    Answer

    **Answer: C**

    Answer: C

    使用"use strict"可以确保不会意外地声明全局变量。在上面的代码中,我们没有声明变量age,但由于我们使用了"use strict",它会抛出一个引用错误。如果我们没有使用"use strict",它仍然可以工作,因为属性age会被添加到全局对象中。使用"use strict"可以帮助我们避免一些常见的错误,例如意外地声明全局变量或使用未声明的变量。它还可以使代码更加严格,从而提高代码的可读性和可维护性。

  7. 异常捕获

    (() => {
      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
    Answer

    Answer: A

    catch块接收参数x。这个x与我们传递参数时的变量不同。这个变量x是块级作用域的。

    稍后,我们将这个块级作用域变量设置为1,并设置变量y的值。现在,我们记录块级作用域变量x的值,它等于1。

    在catch块之外,x仍然是undefined,而y是2。当我们在catch块之外使用console.log(x)时,它返回undefined,而y返回2。

  8. 拓展运算符

    [...'Lydia'];
    • A: ["L", "y", "d", "i", "a"]
    • B: ["Lydia"]
    • C: [[], "Lydia"]
    • D: [["L", "y", "d", "i", "a"]]
    Answer

    Answer: A

    字符串是可迭代的。展开运算符将可迭代对象的每个字符映射到一个元素。

  9. 生成器函数

    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
    Answer

    Answer: C

    常规函数在调用后无法在执行过程中被中止。然而,生成器函数可以在执行过程中被"停止",并且稍后可以从停止的地方继续执行。每当生成器函数遇到一个 yield 关键字时,函数会生成 yield 关键字后指定的值。需要注意的是,在这种情况下,生成器函数不返回该值,而是生成该值

    首先,我们使用 i 等于 10 初始化生成器函数。我们使用 next() 方法调用生成器函数。第一次调用生成器函数时,i 等于 10。它遇到第一个 yield 关键字:生成 yield 后面指定的 i 的值。生成器现在被"暂停",并且输出 10

    然后,我们再次使用 next() 方法调用函数。它从上次停止的地方开始继续执行,仍然将 i 设为 10。现在,它遇到下一个 yield 关键字,并生成 i * 2 的值。i 等于 10,所以返回 10 * 2,即 20。这样就得到了 10, 20 的输出。

  10. Promise 方法

    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"
    Answer

    **Answer: B**

    Answer: B

    当我们将多个 Promise 传递给 Promise.race 方法时,它会解决(resolve)或拒绝(reject)第一个解决或拒绝的 Promise。对于 setTimeout 方法,我们传递了两个定时器:第一个 Promise(firstPromise)设置了 500 毫秒的定时器,而第二个 Promise(secondPromise)设置了 100 毫秒的定时器。这意味着第二个 Promise(secondPromise)会先解决,并带有值 'two'。此时,变量 res 持有值 'two',并被输出。

  11. 参数传递

    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"
    Answer

    Answer: A

    参数按值传递,除非其值是一个对象,那么它们将按引用传递。birthYear是一个字符串,而不是一个对象,所以它是按值传递的。当我们按值传递参数时,会创建该值的副本(参见问题46)。

    变量birthYear引用的是值"1997"。参数year也引用了值"1997",但它引用的值与birthYear引用的不是同一个。当我们通过将year设置为"1998"来更新year的值时,只是更新了year的值,birthYear仍然等于"1997"

    person的值是一个对象。参数member复制了对同一对象的引用。当我们修改member引用的对象的属性时,person的值也会被修改,因为它们都引用同一个对象。personname属性现在等于值"Lydia"

  12. 自定义异常

    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!
    Answer

    Answer: D

    使用throw语句,我们可以创建自定义错误。通过该语句,您可以抛出异常。异常可以是字符串、数字、布尔值或对象。在这种情况下,我们的异常是字符串'Hello world!'

    使用catch语句,我们可以指定在try块中抛出异常时要执行的操作。一个异常被抛出:字符串'Hello world!'。现在,变量e的值等于该字符串,我们将其记录下来。结果是'Oh an error: Hello world!'

  13. 默认参数和解构赋值

    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
    Answer

    **Answer: C** **Answer: 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

  14. 生成器函数

    function* startGame() {
      const 答案 = yield "Do you love JavaScript?";
      if (答案 !== "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 and game.next().value
    • B: game.next.value("Yes") and game.next.value()
    • C: game.next().value and game.next("Yes").value
    • D: game.next.value() and game.next.value("Yes")
    Answer

    Answer: C

    generator函数在遇到yield关键字时会 “暂停” 其执行。 首先,我们需要让函数产生字符串Do you love JavaScript?,这可以通过调用game.next().value来完成。上述函数的第一行就有一个yield关键字,那么运行立即停止了,yield表达式本身没有返回值,或者说总是返回undefined,这意味着此时变量 答案undefined

    next方法可以带一个参数,该参数会被当作上一个 yield 表达式的返回值。当我们调用game.next("Yes").value时,先前的 yield 的返回值将被替换为传递给next()函数的参数"Yes"。此时变量 答案 被赋值为 "Yes"if语句返回false,所以JavaScript loves you back ❤️被打印。

  15. Promise打印

    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
    Answer

    Answer: C

    异步函数始终返回一个 promise。await仍然需要等待 promise 的解决:当我们调用getData()并将其赋值给data,此时datagetData方法返回的一个挂起的 promise,该 promise 并没有解决。

    如果我们想要访问已解决的值"I made it!",可以在data上使用.then()方法:

    data.then(res => console.log(res))

    这样将打印 "I made it!"

  16. 记忆函数

    const add = () => {
      const cache = {};
      return num => {
        if (num in cache) {
          return `From cache! ${cache[num]}`;
        } else {
          const result = num + 10;
          cache[num] = result;
          return `Calculated! ${result}`;
        }
      };
    };
    
    const addFunction = add();
    console.log(addFunction(10));
    console.log(addFunction(10));
    console.log(addFunction(5 * 2));
    • A: Calculated! 20 Calculated! 20 Calculated! 20
    • B: Calculated! 20 From cache! 20 Calculated! 20
    • C: Calculated! 20 From cache! 20 From cache! 20
    • D: Calculated! 20 From cache! 20 Error
    Answer

    Answer: C

    add函数是一个记忆函数。 通过记忆化,我们可以缓存函数的结果,以加快其执行速度。上述情况,我们创建一个cache对象,用于存储先前返回过的值。

    如果我们使用相同的参数多次调用addFunction函数,它首先检查缓存中是否已有该值,如果有,则返回缓存值,这将节省执行时间。如果没有,那么它将计算该值,并存储在缓存中。

    我们用相同的值三次调用了addFunction函数:

    在第一次调用,num等于10时函数的值尚未缓存,if 语句num in cache返回false,else 块的代码被执行:Calculated! 20,并且其结果被添加到缓存对象,cache现在看起来像{10:20}

    第二次,cache对象包含10的返回值。 if 语句 num in cache 返回trueFrom cache! 20被打印。

    第三次,我们将5 * 2(值为 10) 传递给函数。 cache对象包含10的返回值。 if 语句 num in cache 返回trueFrom cache! 20被打印。

  17. 函数默认参数

    function sayHi(name) {
      return `Hi there, ${name}`
    }
    
    console.log(sayHi())
    • A: Hi there,
    • B: Hi there, undefined
    • C: Hi there, null
    • D: ReferenceError
    Answer

    Answer: B

    默认情况下,如果不给函数传参,参数的值将为undefined。 上述情况,我们没有给参数name传值。 name等于undefined,并被打印。

    在 ES6 中,我们可以使用默认参数覆盖此默认的undefined值。 例如:

    function sayHi(name = 'Lydia'){...}

    在这种情况下,如果我们没有传递值或者如果我们传递undefinedname总是等于字符串Lydia

  18. 块级作用域

    function checkAge(age) {
      if (age < 18) {
        const message = "Sorry, you're too young."
      } else {
        const message = "Yay! You're old enough!"
      }
    
      return message
    }
    
    console.log(checkAge(21))
    • A: "Sorry, you're too young."
    • B: "Yay! You're old enough!"
    • C: ReferenceError
    • D: undefined
    Answer

    Answer: C

    constlet声明的变量是具有块级作用域的,块是大括号({})之间的任何东西,即上述情况if / else语句的花括号。 由于块级作用域,我们无法在声明的块之外引用变量,因此抛出ReferenceError

  19. then的调用

    fetch('https://www.website.com/api/user/1')
      .then(res => res.json())
      .then(res => console.log(res))
    • A: fetch方法的结果
    • B: 第二次调用fetch方法的结果
    • C: 前一个.then()中回调方法返回的结果
    • D: 总是undefined
    Answer

    **Answer: B**

    Answer: B

    第二个.thenres的值等于前一个.then中的回调函数返回的值。 你可以像这样继续链接.then,将值传递给下一个处理程序。

  20. 默认参数的位置

    function sum(num1, num2 = num1) {
      console.log(num1 + num2)
    }
    
    sum(10)
    • A: NaN
    • B: 20
    • C: ReferenceError
    • D: undefined
    Answer

    Answer: B

    您可以将默认参数的值设置为函数的另一个参数,只要另一个参数定义在其之前即可。 我们将值10传递给sum函数。 如果sum函数只接收 1 个参数,则意味着没有传递num2的值,这种情况下,num1的值等于传递的值10num2的默认值是num1的值,即10num1 + num2返回20

    如果您尝试将默认参数的值设置为后面定义的参数,则可能导致参数的值尚未初始化,从而引发错误。比如:

    function test(m = n, n = 2) {
    	console.log(m, n)
    }
    test() // Uncaught ReferenceError: Cannot access 'n' before initialization
    test(3) // 3 2
    test(3, 4) // 3 4
  21. 箭头函数的原型

    function giveLydiaPizza() {
      return "Here is pizza!"
    }
    
    const giveLydiaChocolate = () => "Here's chocolate... now go hit the gym already."
    
    console.log(giveLydiaPizza.prototype)
    console.log(giveLydiaChocolate.prototype)
    • A: { constructor: ...} { constructor: ...}
    • B: {} { constructor: ...}
    • C: { constructor: ...} {}
    • D: { constructor: ...} undefined
    Answer

    Answer: D

    常规函数,例如giveLydiaPizza函数,有一个prototype属性,它是一个带有constructor属性的对象(原型对象)。 然而,箭头函数,例如giveLydiaChocolate函数,没有这个prototype属性。 尝试使用giveLydiaChocolate.prototype访问prototype属性时会返回undefined

  22. 默认参数位置

    function getItems(fruitList, ...args, favoriteFruit) {
      return [...fruitList, ...args, favoriteFruit]
    }
    
    getItems(["banana", "apple"], "pear", "orange")
    • A: ["banana", "apple", "pear", "orange"]
    • B: [["banana", "apple"], "pear", "orange"]
    • C: ["banana", "apple", ["pear"], "orange"]
    • D: SyntaxError
    Answer

    Answer: D

    ... args是剩余参数,剩余参数的值是一个包含所有剩余参数的数组,并且只能作为最后一个参数。上述示例中,剩余参数是第二个参数,这是不可能的,并会抛出语法错误。

    function getItems(fruitList, favoriteFruit, ...args) {
      return [...fruitList, ...args, favoriteFruit]
    }
    
    getItems(["banana", "apple"], "pear", "orange")

    上述例子是有效的,将会返回数组:[ 'banana', 'apple', 'orange', 'pear' ]

  23. 语句分号

    function nums(a, b) {
      if
      (a > b)
      console.log('a is bigger')
      else 
      console.log('b is bigger')
      return 
      a + b
    }
    
    console.log(nums(4, 2))
    console.log(nums(1, 2))
    • A: a is bigger, 6 and b is bigger, 3
    • B: a is bigger, undefined and b is bigger, undefined
    • C: undefined and undefined
    • D: SyntaxError
    Answer

    Answer: B

    在 JavaScript 中,我们不必显式地编写分号 (;),但是 JavaScript 引擎仍然在语句之后自动添加分号。这称为自动分号插入。例如,一个语句可以是变量,或者像throwreturnbreak这样的关键字。

    在这里,我们在新的一行上写了一个return语句和另一个值a + b 。然而,由于它是一个新行,引擎并不知道它实际上是我们想要返回的值。相反,它会在return后面自动添加分号。你可以这样看:

    return;
    a + b

    这意味着永远不会到达a + b,因为函数在return关键字之后停止运行。如果没有返回值,就像这里,函数返回undefined。注意,在if/else语句之后没有自动插入!

  24. 箭头函数的返回值

    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))
    • A: [1, [2, 3, 4]] and SyntaxError
    • B: [1, [2, 3, 4]] and { name: "Lydia", age: 21 }
    • C: [1, 2, 3, 4] and { name: "Lydia", age: 21 }
    • D: Error and { name: "Lydia", age: 21 }
    Answer

    Answer: A

    getList函数接收一个数组作为其参数。 在getList函数的括号之间,我们立即解构这个数组。 您可以将其视为:

    [x, ...y] = [1, 2, 3, 4]

    使用剩余的参数... y,我们将所有剩余参数放在一个数组中。 在这种情况下,其余的参数是234y的值是一个数组,包含所有其余参数。 在这种情况下,x的值等于1,所以当我们打印[x,y]时,会打印[1,[2,3,4]]

    getUser函数接收一个对象。对于箭头函数,如果只返回一个值,我们不必编写花括号。但是,如果您想从一个箭头函数返回一个对象,您必须将它写在圆括号之间,否则两个花括号之间的所有内容都将被解释为一个块语句!在这种情况下,花括号之间的代码不是有效的 JavaScript 代码,因此会抛出 SyntaxError。

    以下函数将返回一个对象:

    const getUser = user => ({ name: user.name, age: user.age })
  25. 作用域及闭包

    var callbacks = []
    for (var i = 0; i < 4; i++) {
    callbacks.push(function() {
    console.log(i);
    });
    }
    callbacks.forEach(cb => cb());
    • A:0, 1, 2, 3
    • B:3, 3, 3, 3
    • C:4, 4, 4, 4
    • D:0, 0, 0, 0
    Answer

    Answer: C

    所有的函数都是在同一个作用域中创建的,所以它们共享了同一个 i 变量。当这些函数被创建时,它们并没有保存 i 的当前值,而是保存了对 i 变量的引用。所以,当这些函数在 forEach 循环中被调用时,它们都会打印出 i 的当前值,也就是 for 循环结束后的值 4

    使用 let 关键字代替 var 关键字来声明 i 变量。let 关键字会在每次循环中创建一个新的 i 变量,所以每个函数都会保存它被创建时的 i 值。

  26. 闭包的特性

    var x = 5;
    
    function outer() {
        var x = 10;
    
        function inner() {
            console.log(x);
        }
        return inner;
    }
    var finalResult = outer();
    finalResult();
    Answer

    由于 JavaScript 的作用域规则,这里的 x 指的是 outer函数内部的 x,即 10。最后,outer函数返回了 inner 函数。

    即使 outer 函数已经执行完毕,inner 函数仍然可以访问 outer 函数的作用域,这就是闭包的特性。

    在 JavaScript 中,只要闭包函数(在这个例子中是 inner 函数)还存在,它就可以访问其定义时的外部作用域(在这个例子中是 outer 函数的作用域)。只有当闭包函数被垃圾回收时,它才不能访问其定义时的外部作用域。

    垃圾回收通常发生在以下情况:

    1. 闭包函数不再被引用。在这个例子中,如果 finalResult 被赋值为其他值或者 finalResult 本身被删除,那么 inner 函数就不再被引用,它和 outer 函数的作用域都会被垃圾回收。
    2. 闭包函数的外部作用域不再被引用。在这个例子中,outer 函数的作用域只被 inner 函数引用,所以只有 inner 函数被垃圾回收,outer 函数的作用域才会被垃圾回收。

    请注意,垃圾回收的具体时间取决于 JavaScript 引擎的垃圾回收策略,我们不能精确控制它。

    在 JavaScript 中,垃圾回收主要发生在以下情况:

    1. 局部变量:当函数执行完毕后,函数内部的局部变量通常会被垃圾回收。但如果这些变量被闭包引用,那么它们就不会被垃圾回收,直到闭包也不再被引用。
    2. 无引用的对象:如果一个对象没有被任何变量或者属性引用,那么这个对象就会被垃圾回收。
    3. 循环引用:如果一组对象互相引用,但整个组都不再被外部引用,那么这组对象就会被垃圾回收。
    4. DOM 元素:如果一个 DOM 元素被删除或者不再被引用,那么这个 DOM 元素就会被垃圾回收。
  27. 函数返回值

    function userData() {
        return userData;
    }
    console.log(typeof userData());
    Answer

    userData 函数返回它自己(函数引用)。

    因此,调用 typeof userData() 的结果将是 'function'。因为 typeof 对除 function 之外的引用数据类型均返回 object

  28. 都是

this作用域

  1. 箭头函数的作用域

    const shape = {
      radius: 10,
      diameter() {
        return this.radius * 2;
      },
      perimeter: () => 2 * Math.PI * this.radius,
    };
    
    console.log(shape.diameter());
    console.log(shape.perimeter());
    • A: 20 and 62.83185307179586
    • B: 20 and NaN
    • C: 20 and 63
    • D: NaN and 63
    Answer

    Answer: B

    请注意,diameter的值是一个正则函数,而perimeter的值是一个箭头函数。对于箭头函数,this关键字指的是它当前周围的作用域,这与常规函数不同!这意味着当我们调用 perimeter 时,它不是指形状对象,而是指它周围的范围(例如 window对象)。
    该对象没有值radius,返回 NaN

  2. 绑定 this 作用域

    const person = { name: 'Lydia' };
    
    function sayHi(age) {
      return `${this.name} is ${age}`;
    }
    
    console.log(sayHi.call(person, 21));
    console.log(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
    Answer

    Answer: D

    我们可以使用.call.bind方法来指定函数中的this关键字所引用的对象。但是,.call方法会立即执行函数,而.bind方法则会返回一个新的函数,该函数的上下文已经绑定好了,但不会立即执行。

  3. 函数返回

    function Car() {
      this.make = 'Lamborghini';
      return { make: 'Maserati' };
    }
    
    const myCar = new Car();
    console.log(myCar.make);
    • A: "Lamborghini"
    • B: "Maserati"
    • C: ReferenceError
    • D: TypeError
    Answer

    Answer: B

    当您返回一个属性时,该属性的值等于返回的值,而不是构造函数中设置的值。我们返回字符串"Maserati",所以myCar.make等于"Maserati"

  4. this指向与改变

    var status = "😎"
    
    setTimeout(() => {
      const status = "😍"
    
      const data = {
        status: "🥑",
        getStatus() {
          return this.status
        }
      }
    
      console.log(data.getStatus())
      console.log(data.getStatus.call(this))
    }, 0)
    • A: "🥑" and "😍"
    • B: "🥑" and "😎"
    • C: "😍" and "😎"
    • D: "😎" and "😎"
    Answer

    Answer: B

    this关键字的指向取决于使用它的位置。 在函数中,比如getStatusthis指向的是调用它的对象,上述例子中data对象调用了getStatus,因此this指向的就是data对象。 当我们打印this.status时,data对象的status属性被打印,即"🥑"

    使用call方法,可以更改this指向的对象。data.getStatus.call(this)是将this的指向由data对象更改为全局对象。在全局对象上,有一个名为status的变量,其值为”😎“。 因此打印this.status时,会打印“😎”。如果将此题的 getStatus()函数改为箭头函数,那么结果就不同了:箭头函数没有自己的this,this取决于外层代码块的,而且this无法被改变,所以输出“😍”“😍”

  5. this指向判断

    var name = "window";
    var person = {
      name: "person",
      sayName: function () {
        console.log(this.name);
      }
    };
    function sayName() {
      var sss = person.sayName;
      sss(); 
      person.sayName(); 
      (person.sayName)(); 
      (b = person.sayName)(); 
    }
    sayName();
    Answer

    sss():独立函数调用,没有和任何对象关联。输出 window

    person.sayName():和person对象关联。输出 person

    (person.sayName)():加了括号代表优先级,但在这里并没有什么用,同上。输出 person

    (b = person.sayName)():赋值应用默认绑定规则。输出 window

  6. this指向与改变

    var name = 'window'
    var person1 = {
      name: 'person1',
      foo1: function () {
        console.log(this.name)
      },
      foo2: () => console.log(this.name),
      foo3: function () {
        return function () {
          console.log(this.name)
        }
      },
      foo4: function () {
        return () => {
          console.log(this.name)
        }
      }
    }
    
    var person2 = { name: 'person2' }
    
    person1.foo1(); 
    person1.foo1.call(person2); 
    
    person1.foo2();
    person1.foo2.call(person2);
    
    person1.foo3()();
    person1.foo3.call(person2)();
    person1.foo3().call(person2);
    
    person1.foo4()();
    person1.foo4.call(person2)();
    person1.foo4().call(person2);
    Answer

    person1.foo1(); // person1
    person1.foo1.call(person2); // person2 
    
    person1.foo2(); // window 箭头函数的this和外层代码块相关
    person1.foo2.call(person2); // window 箭头函数的this不能被改变
    
    person1.foo3()(); // window 作为普通函数被调用,没有明确的上下文对象
    person1.foo3.call(person2)(); // window 虽然改变了foo3()的this指向,但其中的匿名函数仍然作为普通函数被调用
    person1.foo3().call(person2); // person2 先返回了匿名函数,再改变这个函数的this指向,指向person2
    
    person1.foo4()(); // person1 返回一个箭头函数,箭头函数的this和外层代码块相关,也就是person1的内部
    person1.foo4.call(person2)(); // person2 改变了foo4的this指向
    person1.foo4().call(person2); // person1 箭头函数的this无法被改变
  7. this和原型链的配合

    function A (cName) {
    if (cName) {
    this.name = cName
    }
    }
    A.prototype.name = 'XiaoMi'
    var a = new A()
    console.log('A', a.name)
    function B (cName) {
    this.name = cName
    }
    B.prototype.name = 'Xiaomi'
    var b = new B()
    console.log('B', b.name)
    • A:A XiaoMi B Xiaomi
    • B:A XiaoMi B undefined
    • C:A undefined B undefined
    • D:A undefined B XiaoMi
    Answer

    Answer: B

    A 的构造函数中,只有当 cName 参数存在时,才会在实例上设置 name 属性。所以当我们使用 new A() 创建一个新的 A 实例 a 时,因为没有传入 cName 参数,所以 a 实例上没有 name 属性,当我们尝试访问 a.name 时,JavaScript 会在 A 的原型链上查找 name 属性,所以 console.log('A', a.name) 输出的是 'A', 'XiaoMi'

    B 的构造函数中,无论 cName 参数是否存在,都会在实例上设置 name 属性。所以当我们使用 new B() 创建一个新的 B 实例 b 时,即使没有传入 cName 参数,b 实例上也会有一个 name 属性,但是它的值是 undefined,因为 cNameundefined。所以 console.log('B', b.name) 输出的是 'B', undefined

  8. 上的

  9. s

运算问题

  1. 计算转换

    +true;
    !'Lydia';
    • A: 1 and false
    • B: false and NaN
    • C: false and false
    Answer

    Answer: A

    一元加号运算符(unary plus)会尝试将操作数转换为数字。在JavaScript中,true被转换为1false被转换为0

    字符串'Lydia',它是一个真值(truthy value),也就是说它在布尔上下文中会被视为true。因此,我们实际上在问“这个真值是否为假值?”这个表达式的结果是false,因为“Lydia”是一个真值,不是假值。

  2. 类型比较

    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
    Answer

    Answer: C

    new Number()是一个内置的函数构造器。虽然它看起来像一个数字,但它实际上不是一个数字:它有许多额外的特性,并且是一个对象。

    当我们使用==运算符(相等运算符)时,它只检查它们是否具有相同的值。它们都具有值3,因此返回true

    然而,当我们使用===运算符(严格相等运算符)时,值和类型都应该相同。但实际上它们不同:new Number()不是一个数字,而是一个对象。因此两者都返回false

  3. 数值运算

    function sum(a, b) {
      return a + b;
    }
    
    sum(1, '2');
    • A: NaN
    • B: TypeError
    • C: "12"
    • D: 3
    Answer

    **Answer: C**

    Answer: C

    JavaScript是一种动态类型语言:不指定某些变量的类型。值可以自动转换为另一种类型,这被称为隐式类型转换。转换是从一种类型转换为另一种类型。

    在这个例子中,JavaScript将数字1转换为字符串,以便函数有意义并返回一个值。在数字类型(1)和字符串类型('2')相加时,数字被视为字符串。我们可以像"Hello"+"World"一样连接字符串,所以这里发生的是"1"+"2",返回"12"

  4. 运算符

    let number = 0;
    console.log(number++);
    console.log(++number);
    console.log(number);
    • A: 1 1 2
    • B: 1 2 2
    • C: 0 2 2
    • D: 0 1 2
    Answer

    Answer: C

    后缀一元运算符++

    返回值(此处返回0
    增加值(数字现在为1
    前缀一元运算符 ++

    增加值(数字现在为2
    返回值(此处返回2
    这将返回0 2 2

  5. 标记模板字面量

    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
    Answer

    Answer: B

    如果你使用标记模板字面量,第一个参数的值总是一个字符串值的数组。其余的参数获取传递的表达式的值!

  6. 对象比较

    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
    Answer

    Answer: C

    JavaScript中比较相等性时,原始值是按照它们的值进行比较的,而对象是按照它们的引用进行比较的。JavaScript会检查这些对象是否具有指向内存中相同位置的引用。

    我们比较的两个对象没有这个引用:我们作为参数传递的对象与我们用来检查相等性的对象在内存中引用的位置不同。因此,它们被认为是不相等的。

    在JavaScript中,==和===都用于比较两个值的相等性。==运算符比较两个值是否相等,但它会进行类型转换。如果两个值的类型不同,==运算符会尝试将它们转换为相同的类型,然后再进行比较。例如,如果我们比较数字1和字符串"1",==运算符会将字符串"1"转换为数字1,然后再进行比较。如果两个值的类型相同,==运算符会直接比较它们的值。

    这就是为什么 { age: 18 } === { age: 18 }{ age: 18 } == { age: 18 } 返回 false.

  7. eval方法

    const sum = eval('10*10+5');
    • A: 105
    • B: "105"
    • C: TypeError
    • D: "10*10+5"
    Answer

    Answer: A

    eval函数评估作为字符串传递的代码。如果它是一个表达式,就像这个例子一样,它会评估这个表达式。这个表达式是10 * 10 + 5。这将返回数字105

  8. 类型判断

    function sayHi() {
      return (() => 0)();
    }
    
    console.log(typeof sayHi());
    • A: "object"
    • B: "number"
    • C: "function"
    • D: "undefined"
    Answer

    Answer: B

    sayHi函数返回立即调用的函数表达式(IIFE)的返回值。这个函数返回了0,它的类型是“number”

    另外,typeof操作符可以返回以下值:undefinedbooleannumberbigintstringsymbolfunctionobject。需要注意的是,typeof null返回的是"object"

  9. 加法运算

    console.log(3 + 4 + '5');
    • A: "345"
    • B: "75"
    • C: 12
    • D: "12"
    Answer

    Answer: B

    运算符的结合性(associativity)是编译器按照左到右或右到左的顺序计算表达式的方式。这仅在所有运算符具有相同的优先级时才会发生。在这里,我们只有一种运算符:+。对于加法运算,其结合性是从左到右。

    首先计算3 + 4,结果为数字7

    接着计算7 + '5',结果为"75",这是由于类型转换。JavaScript将数字7转换为字符串,参见问题15。我们可以使用+运算符来连接两个字符串。"7" + "5"的结果是"75"

  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 }
    Answer

    **Answer: B**

    Answer: B

    使用展开运算符(spread operator)...可以将对象进行合并。它可以创建一个对象的键/值对的副本,并将其添加到另一个对象中。在这种情况下,我们创建了user对象的副本,并将其添加到admin对象中。admin对象现在包含了复制的键/值对,结果为{ admin: true, name: "Lydia", age: 21 }

  11. 运算符

    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
    Answer

    **Answer: A**

    Answer: A

    一元运算符++首先返回操作数的值,然后递增操作数的值。num1的值是10,因为increaseNumber函数首先返回num的值,即10,然后才递增num的值。

    num2的值是10,因为我们将num1传递给了increasePassedNumber函数。number等于10(即num1的值)。同样,一元运算符++首先返回操作数的值,然后递增操作数的值。number的值是10,所以num2等于10

  12. 运算优先级

    var a = 1 + (1 > 2)?1:2;
    • A: 1
    • B: 2
    • C: 3
    • D: undefined
    Answer

    Answer: A

    ?: 条件运算符的优先级只比赋值运算符和逗号运算符更高,所以该代码表示:(1 + 0)?1:2,所以答案应该选A

  13. 函数表达式和type of 运算符

    var x = 1;
    if (function test() {}) {
      x += typeof test;
    }
    console.log(x); 
    Answer

    在 JavaScript 中,if (function test() {}) 是一个立即执行的函数表达式(IIFE)。这个函数表达式创建了一个名为 test 的函数,但这个函数只在其自身的函数体内部可见,外部无法访问到这个函数。

    因此,当执行 x += typeof test; 时,test 是未定义的,typeof test 返回的是 “undefined”。

    所以,x += typeof test; 实际上是 x += "undefined";,由于 x 是一个数字,所以 JavaScript 会将 x 转换为字符串,然后进行字符串连接,得到 “1undefined”。

  14. 上的

内置方法

  1. reduce方法

    [[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]
    Answer

    **Answer: C** **Answer: C**

    [1, 2]是我们的初始值。这是我们开始时的值,也是第一个累加器(acc)的值。在第一轮中,acc[1, 2]cur[0, 1]。我们将它们连接起来,结果为[1, 2, 0, 1]

    接下来,[1, 2, 0, 1]成为新的acc[2, 3]成为cur。我们将它们连接起来,得到[1, 2, 0, 1, 2, 3]

  2. parseInt 方法

    const num = parseInt('7*6', 10);
    • A: 42
    • B: "42"
    • C: 7
    • D: NaN
    Answer

    **Answer: C**

    Answer: C

    只有字符串中的第一个数字被返回。基于基数(作为第二个参数,用于指定要将其解析为的数字类型:十进制、十六进制、八进制、二进制等),parseInt函数会检查字符串中的字符是否有效。一旦遇到在基数中无效的字符,它就会停止解析并忽略后面的字符。

    *不是一个有效的数字。它只解析"7"为十进制数7。现在,变量num的值为7

  3. map方法

    [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 ]
    Answer

    Answer: C

    在对数组进行映射(mapping)时,变量num的值等于当前正在循环的元素。在这种情况下,元素是数字,因此if语句的条件typeof num === "number"返回true。map函数创建一个新数组,并将从函数返回的值插入其中。

    然而,我们没有返回一个值。当我们从函数中没有返回值时,函数将返回undefined。对于数组中的每个元素,函数块都会被调用,因此对于每个元素,我们都返回undefined。

  4. set方法

    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}
    Answer

    Answer: D

    Set对象是一个包含唯一值的集合:在一个集合中,一个值只能出现一次。

    我们传递了可迭代对象[1, 1, 2, 3, 4],其中有一个重复值1。由于在一个集合中不能有两个相同的值,其中一个被移除。结果是{1, 2, 3, 4}

  5. delete方法

    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
    Answer

    Answer: A

    delete运算符返回一个布尔值:如果删除成功则返回true,否则返回false。然而,使用varconstlet关键字声明的变量无法使用delete运算符删除。

    name变量是使用const关键字声明的,所以删除操作不成功:返回false。当我们将age设置为21时,实际上是向全局对象添加了一个名为age的属性。你可以通过这种方式成功删除对象的属性,也可以删除全局对象,因此delete age返回true

  6. Object.defineProperty和Object.keys()方法

    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"]
    Answer

    Answer: B

    使用defineProperty方法,我们可以向对象添加新属性或修改现有属性。当我们使用defineProperty方法向对象添加属性时,默认情况下它们是不可枚举的。Object.keys方法从对象中返回所有可枚举的属性名,本例中只有"name"

    使用defineProperty方法添加的属性默认是不可变的。您可以使用writableconfigurableenumerable属性来覆盖此行为。这样,defineProperty方法使您对要添加到对象中的属性具有更多控制权。

  7. stringify方法

    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}"
    Answer

    Answer: A

    JSON.stringify的第二个参数是replacerreplacer可以是一个函数或一个数组,它允许您控制值的字符串化方式和内容。

    如果replacer是一个array,只有数组中包含的属性名将被添加到JSON字符串中。在这种情况下,只有名为"level""health"的属性被包含在内,"username"被排除在外。data现在等于"{ "level": 19, "health": 90 }"

    如果replacer是一个函数,该函数将在您对对象进行字符串化时调用。从该函数返回的值将成为将属性添加到JSON字符串时的属性值。如果值为undefined,则该属性将被排除在JSON字符串之外。

  8. reduce方法

    [1, 2, 3, 4].reduce((x, y) => console.log(x, y));
    • A: 1 2 and 3 3 and 6 4
    • B: 1 2 and 2 3 and 3 4
    • C: 1 undefined and 2 undefined and 3 undefined and 4 undefined
    • D: 1 2 and undefined 3 and undefined 4
    Answer

    **Answer: D**

    Answer: D

    reduce方法接收的第一个参数是累加器,本例中为x。第二个参数是当前值,为y。使用reduce方法,我们在数组中的每个元素上执行一个回调函数,最终可能会得到一个单一的值。

    在这个例子中,我们并没有返回任何值,只是记录了累加器和当前值的值。

    累加器的值等于回调函数先前返回的值。如果您没有将可选的initialValue参数传递给reduce方法,第一次调用时累加器等于第一个元素。

    在第一次调用时,累加器(x)为1,当前值(y)为2。我们没有从回调函数返回值,而是记录了累加器和当前值:输出为12

    如果您没有从函数中返回值,它将返回undefined。在下一次调用时,累加器为undefined,当前值为3。输出为undefined3

    在第四次调用时,我们再次没有从回调函数返回值。累加器再次为undefined,当前值为4。输出为undefined4

  9. padStart 方法

    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"
    Answer

    Answer: C

    使用padStart方法,我们可以在字符串的开头添加填充。传递给此方法的参数是字符串的总长度(包含填充)。字符串Lydia Hallie的长度为12,因此name.padStart(13)在字符串的开头只会插入 1(13 - 12 = 1)个空格。

    如果传递给padStart方法的参数小于字符串的长度,则不会添加填充。

  10. String.raw 方法

    console.log(String.raw`Hello\nworld`);
    • A: Hello world!
    • B: Hello
      world
    • C: Hello\nworld
    • D: Hello\n
      world
    Answer

    Answer: 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被打印出。

  11. list.push 方法

    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
    Answer

    Answer: B

    push()方法返回新数组的长度。一开始,数组包含一个元素(字符串"banana"),长度为 1。 在数组中添加字符串"apple"后,长度变为 2,并将从addToList函数返回。

    push方法修改原始数组,如果你想从函数返回数组而不是数组长度,那么应该在 push item之后返回list

  12. Object.freeze方法

    const box = { x: 10, y: 20 };
    
    Object.freeze(box);
    
    const shape = box;
    shape.x = 100;
    console.log(shape)
    • A: { x: 100, y: 20 }
    • B: { x: 10, y: 20 }
    • C: { x: 100 }
    • D: ReferenceError
    Answer

    **Answer: B**

    Answer: B

    Object.freeze使得无法添加、删除或修改对象的属性(除非属性的值是另一个对象)。

    当我们创建变量shape并将其设置为等于冻结对象box时,shape指向的也是冻结对象。你可以使用Object.isFrozen检查一个对象是否被冻结,上述情况,Object.isFrozen(shape)将返回true

    由于shape被冻结,并且x的值不是对象,所以我们不能修改属性xx仍然等于10{x:10,y:20}被打印。

    注意,上述例子我们对属性x进行修改,可能会导致抛出 TypeError 异常(最常见但不仅限于严格模式下时)。

  13. Object.entries方法

    const person = {
      name: "Lydia",
      age: 21
    }
    
    for (const [x, y] of Object.entries(person)) {
      console.log(x, y)
    }
    • A: name Lydia and age 21
    • B: ["name", "Lydia"] and ["age", 21]
    • C: ["name", "age"] and undefined
    • D: Error
    Answer

    Answer: 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

  14. 日期函数的输出

    new Date(2020,12,1).getMonth() 的结果是()

    • 12
    • 11
    • 0
    • 13
    Answer

    Answer: C

    new Date() 的参数的带构造器的形式为 new Date(year, monthIndex, day),也就是月份索引从0开始,如果超过11,那么相当于到第二年,即12相应的索引为0。

    注意:如果直接 new Date().getMonth() 返回的结果为现实的月份 - 1。

  15. s

概念问题

  1. 事件传播的三个阶段顺序?

    • A: 目标阶段 > 捕获阶段 > 冒泡阶段
    • B: 冒泡阶段 > 目标阶段 > 捕获阶段
    • C: 目标阶段 > 冒泡阶段 > 捕获阶段
    • D: 捕获阶段 > 目标阶段 > 冒泡阶段
    Answer

    Answer: D

    在捕获阶段中,事件从祖先元素开始向下传播到目标元素。然后,事件到达目标元素并触发。接着,冒泡阶段开始,事件从目标元素开始向上冒泡到最外层的元素。因此,在事件传播的过程中,捕获阶段和冒泡阶段都是必要的,它们共同构成了事件传播的完整过程。

  2. 所有对象都有原型么?

    • A: 正确
    • B: 错误
    Answer

    Answer: B

    所有对象都有原型,除了基础对象。基础对象是由用户创建的对象,或使用new关键字创建的对象。基础对象可以访问一些方法和属性,例如.toString方法。这就是为什么可以使用内置的JavaScript方法的原因!所有类似的方法都在原型上可用。虽然JavaScript无法直接在对象上找到它,但它会沿着原型链向下查找并在那里找到它,这使得它对您可用。

  3. cool_secret 可以访问多长时间?

    sessionStorage.setItem('cool_secret', 123);
    • A: 永远,数据不会丢失。
    • B: 当用户关闭选项卡时。
    • C: 当用户关闭整个浏览器时,不仅仅是选项卡。
    • D: 当用户关闭他们的计算机时。
    Answer

    Answer: B

    存储在sessionStorage中的数据在关闭选项卡后会被删除。

    如果您使用了localStorage,除非例如调用localStorage.clear(),否则数据将永久存在。

  4. 全局执行上下文

    JavaScript全局执行上下文为您创建了两个东西:全局对象和“this”关键字。

    • A: 正确
    • B: 错误
    • C: 取决于环境
    Answer

    Answer: A

    基本执行上下文是全局执行上下文:它是您代码中任何地方都可以访问的内容。

  5. 事件循环

    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
    Answer

    **Answer: B**

    Answer: B

    事件循环相关知识。

  6. 点击按钮时哪一个是event.target?

    <div onclick="console.log('first div')">
      <div onclick="console.log('second div')">
        <button onclick="console.log('button')">
          Click!
        </button>
      </div>
    </div>
    • A: 外层的 div
    • B: 内层的 div
    • C: button
    • D: 所有嵌套元素的数组
    Answer

    Answer: C

    当点击一个元素时,事件会从该元素开始向上冒泡,直到达到文档根节点。在这个过程中,每个祖先元素都会收到该事件。事件的目标元素是最深层次的嵌套元素,它是直接触发事件的元素。您可以使用event.target属性来访问该元素。如果您想停止事件冒泡,可以使用event.stopPropagation()方法。这将阻止事件继续向上冒泡,从而只触发目标元素的事件处理程序。

  7. 判断为 false 的值

    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
    • D: All of them are falsy
    Answer

    **Answer: A**

    Answer: A

    有以下8种为false的数值:

    • undefined
    • null
    • NaN
    • false
    • '' (empty string)
    • 0
    • -0
    • 0n (BigInt(0))

    像new Number和new Boolean这样的函数构造器被视为真值

  8. 所有在JavaScript中的元素只属于?

    • A: 原始类型或对象
    • B: 函数或对象
    • C: 只有对象
    • D: 数字或对象
    Answer

    Answer: A

  9. setInterval 在浏览器中返回什么?

    setInterval(() => console.log('Hi'), 1000);
    • A: 一个唯一的id
    • B: 指定的毫秒数
    • C: 传递的函数
    • D: undefined
    Answer

    Answer: A

    它返回一个唯一的 ID。此 ID 可用于通过 clearInterval() 函数清除该间隔。

  10. 模块的导入与导出

    // 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
    Answer

    Answer: C

    导入的模块是只读的:你不能修改导入的模块。只有导出它们的模块可以改变它们的值。

    当我们尝试增加myCounter的值时,会抛出一个错误:myCounter是只读的,不能被修改。

  11. import和require的执行顺序

    // 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
    Answer

    Answer: B

    import命令是编译阶段执行的,在代码运行之前。因此这意味着被导入的模块会先运行,而导入模块的文件会后执行。

    这是 CommonJS 中require()import之间的区别。使用require(),您可以在运行代码时根据需要加载依赖项。 如果我们使用require而不是importrunning index.jsrunning sum.js3会被依次打印。

  12. 纯函数判断

    function sum(a, b) {
      return a + b;
    }
    • A: Yes
    • B: No
    Answer

    Answer: A

    纯函数在相同的输入值时,需产生相同的输出,其输出的结果,与输入值以外的其他隐藏信息或状态无关,也和由 I/O 设备产生的外部输出无关。 纯函数不会产生副作用。

    纯函数与副作用的定义可参考: https://zh.wikipedia.org/wiki/%E5%89%AF%E4%BD%9C%E7%94%A8_(%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6)

  13. 模块导入

    // module.js 
    export default () => "Hello world"
    export const name = "Lydia"
    
    // index.js 
    import * as data from "./module"
    
    console.log(data)
    • A: { default: function default(), name: "Lydia" }
    • B: { default: function default() }
    • C: { default: "Hello world", name: "Lydia" }
    • D: Global object of module.js
    Answer

    Answer: A

    使用import * as name语法,我们将module.js文件中所有export导入到index.js文件中,并且创建了一个名为data的新对象。 在module.js文件中,有两个导出:默认导出和命名导出。 默认导出是一个返回字符串 “Hello World” 的函数,命名导出是一个名为name的变量,其值为字符串"Lydia"

    data对象具有默认导出的default属性,其他属性具有指定 exports 的名称及其对应的值。

  14. 都是

  15. 都是

  16. 都是

  17. 都是

正则表达式

  1. 非捕获组

    下面能完全覆盖0~10000(不含10000)的整数或2位以内小数的正则表达式是:

    • A: /^-?\d{1,4}\.\d{1,2}?$/
    • B: /^-?\d{5}(?:\.\d{1,2})?$/
    • C: /^-?\d{1,4}\.\d{2}?$/
    • D: /^-?\d{1,4}(?:\.\d{1,2})?$/
    Answer

    Answer: D

    • 首先注意是0-9999,即一位数字到四位数字:d(1,4)
    • (?:) 是非捕获组,不进行存储供以后使用,这保证了正则表达式的性能,同时这在使用 “或” 字符 (|) 来组合一个模式的各个部分是很有用。例如, 'industr(?:y|ies)' 就是一个比 'industry|industries' 更简略的表达式。
    • \ .\d{1,2} 表示匹配一个小数点和一个一到二位的整数
    • (?: ...)? 末尾的 ? 表示或的意思,表示前面的内容可以出现0次或1次
    • -? 表示负号可以出现0次或1次

文章作者: QT-7274
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 QT-7274 !
评论
  目录