原型(prototype)
在 JavaScript 中,每一个对象都有一个内部属性 [[prototype]]
,也可以称之为原型。原型是一个对象或 null
。当我们访问一个对象的属性或方法时,如果对象本身没有这个属性或方法,那么 JavaScript 引擎会去对象的原型链上查找。也就是说,对象的原型链上的对象都可以为该对象提供属性和方法。
每一个构造函数(除了箭头函数)都有一个原型对象。我们可以通过构造函数的 prototype
属性来访问该原型对象。因此,所有通过该构造函数创建的对象都共享该原型对象。
示例代码:
function Person(name) {this.name = name;
}Person.prototype.sayHello = function() {console.log("Hello, I'm " + this.name);
}const person1 = new Person("Alice");
person1.sayHello(); // "Hello, I'm Alice"const person2 = new Person("Bob");
person2.sayHello(); // "Hello, I'm Bob"
在上面的代码中:
Person
是一个构造函数,它有一个原型对象Person.prototype
。Person.prototype
中定义了一个方法sayHello
。- 通过
new
关键字使用Person
构造函数创建了两个对象person1
和person2
。 person1
和person2
都可以调用sayHello
方法,因为它们都从Person.prototype
原型对象上继承了该方法。
原型链(prototype chain)
JavaScript 中的原型链是一种对象间的委托关系。当我们访问一个对象的属性或方法时,如果该对象本身没有该属性或方法,那么 JavaScript 引擎会沿着该对象的原型链依次查找,直到找到该属性或方法或找到原型链的顶端 Object.prototype
(Object.prototype
是所有对象的根原型对象,它的 [[prototype]]
属性为 null
)为止。
示例代码:
function Person(name) {this.name = name;
}Person.prototype.sayHello = function() {console.log("Hello, I'm " + this.name);
}const person = new Person("Alice");console.log(person.hasOwnProperty("name")); // true
console.log(person.hasOwnProperty("sayHello")); // false
console.log(Person.prototype.hasOwnProperty("sayHello")); // true
console.log(person.__proto__ === Person.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__); // null
在上面的代码中:
person
对象的name
属性是它自己的属性,因此person.hasOwnProperty("name")
返回true
。person
对象的sayHello
方法不是它自己的属性,而是它的原型对象Person.prototype
的属性,因此person.hasOwnProperty("sayHello")
返回false
。Person.prototype
的sayHello
方法是它自己的属性,因此Person.prototype.hasOwnProperty("sayHello")
返回true
。person.__proto__
指向Person.prototype
,因此person.__proto__ === Person.prototype
返回true
。Person.prototype.__proto__
指向Object.prototype
,因此Person.prototype.__proto__ === Object.prototype
返回true
。Object.prototype.__proto__
为null
,因为它没有更高层的原型对象,所以Object.prototype.__proto__
返回null
。