📜  JavaScript 面试问题和答案(1)

📅  最后修改于: 2023-12-03 15:16:16.509000             🧑  作者: Mango

JavaScript 面试问题和答案

JavaScript 是当前最流行的编程语言之一,被广泛运用于 Web 开发、移动应用、桌面应用等领域。以下是一些常见的 JavaScript 面试问题及其答案。

数据类型问题
1. JavaScript 中有哪些数据类型?

JavaScript 中共有七个数据类型:number、string、boolean、null、undefined、symbol 和 object.

2. 如何判断一个变量的数据类型?

可以使用 typeof 操作符来判断变量的数据类型,例如:

typeof 3; // "number"
typeof "hello"; // "string"
typeof true; // "boolean"
typeof null; // "object" (这是一个历史遗留问题)
typeof undefined; // "undefined"
typeof Symbol(); // "symbol"
typeof {}; // "object"
3. 如何将一个字符串转换为数字?

可以使用 parseInt()parseFloat() 函数将一个字符串转换为数字。其中,parseInt() 函数将字符串转换为整数,parseFloat() 函数将字符串转换为浮点数。例如:

parseInt("123"); // 123
parseFloat("3.14"); // 3.14

注意,如果字符串不能被转换为数字,那么结果将为 NaN

原型与继承问题
1. JavaScript 中的原型是什么?

在 JavaScript 中,每个对象都有一个内部属性 [[Prototype]],它指向了对象的原型。原型可以被理解为一个对象的“模板”,它包含了该对象所拥有的属性和方法。如果访问一个对象的属性或方法时,发现该对象本身并没有这个属性或方法,那么 JavaScript 引擎会沿着原型链向上查找,直到找到该属性或方法为止。

2. 如何创建一个对象的原型?

可以使用 Object.create() 函数来创建一个对象的原型。该函数接受一个参数,即新对象的原型。例如:

const person = {
  name: "Tom",
  age: 30,
  greet() {
    console.log(`Hello, my name is ${this.name}, and I am ${this.age} years old.`);
  }
};

const me = Object.create(person);
me.name = "Jerry";
me.age = 25;
me.greet(); // "Hello, my name is Jerry, and I am 25 years old."

在上面的例子中,我们通过 Object.create() 函数创建了一个名为 person 的对象,并将其作为 me 对象的原型。因此,me 对象继承了 person 对象中的属性和方法。

3. JavaScript 支持哪些类型的继承?

JavaScript 支持原型继承、构造函数继承和组合继承。其中,原型继承和构造函数继承都是比较简单直接的继承方式,但它们各自存在一些缺点。组合继承是一种将原型继承和构造函数继承结合起来的继承方式,较为灵活。例如:

function Animal(name) {
  this.name = name;
}

Animal.prototype.greet = function() {
  console.log(`Hello, my name is ${this.name}.`);
}

function Dog(name) {
  Animal.call(this, name);
}

Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

Dog.prototype.bark = function() {
  console.log("Woof!");
}

const myDog = new Dog("Rover");
myDog.greet(); // "Hello, my name is Rover."
myDog.bark(); // "Woof!"

在上面的例子中,我们首先定义了一个 Animal 构造函数和一个 Dog 构造函数。Dog 构造函数继承了 Animal 构造函数,并添加了自己的方法 bark。通过 Object.create() 函数,我们将 Dog 对象的原型指向了 Animal 对象的原型,实现了原型继承。

作用域与闭包问题
1. 什么是作用域链?

作用域链指的是 JavaScript 中一个函数嵌套另一个函数时,内部函数可以访问外部函数中定义的变量的机制。具体来说,函数在被创建时就会创建一个作用域链,其中包含了该函数被定义时所处的外部函数或全局作用域,以及外部函数或全局作用域的外部函数或全局作用域,以此类推,直到顶层作用域为止。

2. 什么是闭包?

闭包是指一个函数可以“记住”并访问它所在的词法作用域,即使该函数在这个词法作用域之外执行。简单来说,闭包就是在一个函数中定义另一个函数,并返回这个函数,从而使得该函数可以访问它所在的词法作用域中的变量。例如:

function outer() {
  const name = "Tom";

  function inner() {
    console.log(`Hello, ${name}!`);
  }

  return inner;
}

const sayHello = outer();
sayHello(); // "Hello, Tom!"

在上面的例子中,函数 outer 中定义了一个局部变量 name 和一个内部函数 inner,并将 inner 函数返回。由于 inner 函数中使用了变量 name,所以 inner 函数可以访问 outer 函数的词法作用域中的变量 name。当我们执行 outer 函数并将其返回值赋给变量 sayHello 后,sayHello 就成为了一个闭包,可以在任何时候执行 inner 函数并访问变量 name

3. 如何使用闭包保护变量?

闭包可以将变量“隐藏”在函数的内部,防止外部代码直接访问和修改这些变量,从而提高了代码的安全性和可维护性。例如:

function createCounter() {
  let count = 0;

  return {
    increment() {
      count++;
      console.log(`Count: ${count}`);
    },

    decrement() {
      count--;
      console.log(`Count: ${count}`);
    }
  };
}

const counter = createCounter();
counter.increment(); // "Count: 1"
counter.increment(); // "Count: 2"
counter.decrement(); // "Count: 1"

在上面的例子中,我们使用闭包创建了一个计数器对象 counter,它包含了两个方法 incrementdecrement,分别实现了计数器加一和减一的功能。由于变量 count 只能在创建 counter 对象的闭包中被访问和修改,所以我们可以通过 counter 对象来间接地访问和修改变量 count。这种方式提高了代码的安全性和可维护性。