面试题答案
一键面试JavaScript 中 prototype 链的形成过程
- 构造函数与 prototype 属性
- 在 JavaScript 中,每个函数(当它被用作构造函数时)都有一个
prototype
属性。这个prototype
属性是一个对象,它默认有一个constructor
属性,该属性指向构造函数本身。例如:
function Person() {} console.log(Person.prototype.constructor === Person); // true
- 在 JavaScript 中,每个函数(当它被用作构造函数时)都有一个
- 实例对象与
__proto__
- 当使用
new
关键字调用构造函数创建一个实例对象时,这个实例对象会有一个内部属性[[Prototype]]
,在 JavaScript 中可以通过__proto__
来访问(虽然__proto__
不是标准属性,但在大多数浏览器环境中可用)。这个__proto__
指向构造函数的prototype
对象。例如:
function Person() {} let person = new Person(); console.log(person.__proto__ === Person.prototype); // true
- 当使用
- 原型链的形成
- 由于
prototype
是一个对象,它也有自己的[[Prototype]]
(即__proto__
)。这样就形成了一条链,从实例对象开始,通过__proto__
不断向上查找,直到找到Object.prototype
,而Object.prototype.__proto__
为null
,这就是原型链的终点。例如:
function Animal() {} function Dog() {} Dog.prototype = new Animal(); let myDog = new Dog(); // myDog -> Dog.prototype -> Animal.prototype -> Object.prototype -> null
- 由于
通过 prototype 链实现属性和方法的查找
- 属性查找
- 当访问一个对象的属性时,JavaScript 首先会在对象本身查找该属性。如果找不到,就会沿着原型链向上查找,直到找到该属性或者到达原型链的终点(
Object.prototype
,其__proto__
为null
)。例如:
function Person(name) { this.name = name; } Person.prototype.sayHello = function() { console.log(`Hello, I'm ${this.name}`); }; let person = new Person('John'); console.log(person.name); // 'John',在实例对象本身找到 person.sayHello(); // 'Hello, I'm John',在 Person.prototype 中找到
- 当访问一个对象的属性时,JavaScript 首先会在对象本身查找该属性。如果找不到,就会沿着原型链向上查找,直到找到该属性或者到达原型链的终点(
- 方法查找
- 方法的查找过程与属性查找类似。当调用一个对象的方法时,首先在对象本身查找该方法,如果不存在,就会沿着原型链查找。例如:
function Shape() { this.color = 'black'; } Shape.prototype.getColor = function() { return this.color; }; function Rectangle() { Shape.call(this); this.width = 10; this.height = 5; } Rectangle.prototype = Object.create(Shape.prototype); Rectangle.prototype.constructor = Rectangle; let rect = new Rectangle(); console.log(rect.getColor()); // 'black',在 Shape.prototype 中找到 getColor 方法
- 在这个例子中,
Rectangle
构造函数创建的实例rect
本身没有getColor
方法,但是通过原型链,它可以找到Shape.prototype
上的getColor
方法并调用。