面试题答案
一键面试构造函数、原型对象、实例之间的关系
- 构造函数:在JavaScript中,构造函数是用于创建对象的函数。当使用
new
关键字调用构造函数时,会创建一个新的对象实例。构造函数内部通过this
关键字来引用新创建的实例对象,并可以为其添加属性和方法。例如:
function Person(name, age) {
this.name = name;
this.age = age;
}
- 原型对象:每个函数都有一个
prototype
属性,该属性指向一个对象,这个对象就是原型对象。原型对象的作用是为通过该构造函数创建的所有实例对象共享属性和方法。当访问实例对象的属性或方法时,如果实例对象本身没有该属性或方法,JavaScript会沿着原型链查找原型对象上是否存在该属性或方法。例如,上面Person
构造函数的原型对象可以添加方法:
Person.prototype.sayHello = function() {
console.log(`Hello, I'm ${this.name} and I'm ${this.age} years old.`);
};
- 实例:通过使用
new
关键字调用构造函数创建的对象就是实例。实例对象可以访问构造函数内部定义的属性,也可以访问原型对象上定义的属性和方法。例如:
const person1 = new Person('John', 30);
person1.sayHello();
实例对象有一个 __proto__
属性,它指向构造函数的原型对象。这就建立了实例与原型对象之间的联系,多个实例对象共享原型对象上的属性和方法,从而节省内存。
通过原型链实现继承
- 经典继承方式:
// 父构造函数
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
console.log(this.name + ' makes a sound.');
};
// 子构造函数
function Dog(name, breed) {
// 借用父构造函数初始化属性
Animal.call(this, name);
this.breed = breed;
}
// 设置原型链,实现继承
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
// 为子构造函数的原型添加新方法
Dog.prototype.bark = function() {
console.log(this.name + ' barks.');
};
const myDog = new Dog('Buddy', 'Golden Retriever');
myDog.speak();
myDog.bark();
在上述代码中:
- 通过
Animal.call(this, name)
在Dog
构造函数内部调用Animal
构造函数,这样Dog
实例就拥有了Animal
构造函数定义的属性。 - 使用
Object.create(Animal.prototype)
创建一个新对象,该对象的原型是Animal.prototype
,然后将其赋值给Dog.prototype
,从而建立了Dog
实例到Animal
原型对象的原型链。 - 由于修改了
Dog.prototype
,需要重新设置Dog.prototype.constructor
为Dog
,以确保构造函数的引用正确。
- ES6 类继承方式:
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a sound.');
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name);
this.breed = breed;
}
bark() {
console.log(this.name + ' barks.');
}
}
const myDog = new Dog('Buddy', 'Golden Retriever');
myDog.speak();
myDog.bark();
在ES6 类继承中:
class
关键字定义类,extends
关键字实现继承。- 在
Dog
构造函数中,super(name)
调用父类Animal
的构造函数,以初始化从父类继承的属性。 Dog
类可以直接定义新方法,如bark
,同时也继承了Animal
类的方法,如speak
。