原型
概念
- 无论什么时候,只要创建了一个函数,那么就会为之创建一个
prototype属性,这个属性指向了函数的原型对象。
- 在默认情况下,每个原型对象同样会创建一个
constructor属性,用于指向prototype属性所在函数的指针。
- 使用构造函数创建的对象,会创建一个名为
[[prototype]]的指针指向构造函数的原型对象。
三个属性
prototype:每一个函数都有一个prototype属性,指向原型对象。
- 例外:
Function.prototype.bind()没有prototype属性
[[prototype]:每一个实例对象都有一个[[prototype]]内部属性,指向构造函数的原型对象。
constructor:每一个原型对象都有一个constructor属性,指向关联的构造函数。
举个🌰
- 创建了一个函数后,默认情况下,其原型对象只获得一个
constructor属性,该属性指向Person函数。
function Person() {}
console.log(Person.prototype);
function Person() {}
Person.prototype.country = 'China';
Person.prototype.sex = 'man';
Person.prototype.age = 26;
Person.prototype.sayAge = function() {
console.log(this.age);
}
console.log(Person.prototype);
- 每个对象实例都有一个
__proto__属性去访问原型对象,这里的__proto__属性是浏览器提供用于访问实例对象内部属性[[prototype]]。ECMAScript5中增加了一个Object.getPrototypeOf()方法,用于对象访问其原型对象。
function Person() {}
Person.prototype.country = 'China';
Person.prototype.sex = 'man';
Person.prototype.age = 26;
Person.prototype.getAge = function() {
console.log(this.age);
}
var person1 = new Person();
person1.getAge();
console.log(person1);
var person2 = new Person();
person2.getAge();
console.log(person2);
- 它们之间的关系如下图:

- 由于原型对象会共享自身的属性和方法,因此这里创建的2个Person对象实例能够直接访问
getAge()
- 当调用
person1.getAge()时,会先在person1实例中搜索getAge(),若找到就返回;若没有找到,则到person1的原型对象中去搜索。这里进行了2次搜索工作。
- 若在实例对象中添加了原型对象中同名的属性,那么该属性并不会重写原型对象中的值,只是作为实例对象自己的属性,不会被共享。例如:
function Person() {}
Person.prototype.country = 'China';
Person.prototype.sex = 'man';
Person.prototype.age = 26;
Person.prototype.getAge = function() {
console.log(this.age);
}
var person1 = new Person();
person1.age = 28;
console.log(person1);
- 可以看出:只是为person1对象添加了一个
age属性,而原型对象中的age属性的值不改变。
console.log(person1.age)会输出28,而不是26。此时访问的是person1对象中的age属性。可以使用delete person1.age删除本对象上的属性,删除之后访问的就是原型对象上面的age属性了。
- 可以使用
hasOwnProperty()来检测一个属性是存在于对象实例中,还是原型对象中。
原型链
概念
- 当一个实例对象的原型对象是另一种类型的实例对象,且这个实例对象的原型对象同样又是另一种类型的实例对象,以此下去,最终会就形成了一个有限的原型链。
- 原型链是JavaScript中一种能够实现继承的方式。
举个🌰
function Animal() {}
Animal.prototype.category = 'Animal';
function Cat() {}
Cat.prototype = new Animal();
Cat.prototype.category = 'Cat';
function Tiger() {}
Tiger.prototype = new Cat();
Tiger.prototype.category = 'Tiger';
var tiger = new Tiger();
console.log(tiger);
- tiger指向Tiger的原型,Tiger的原型指向Cat的原型,Cat的原型指向Animal的原型,Animal的原型指向Object的原型。
- 简单来说:
__proto__属性连接每个对象,形成了原型链。任何原型链的最底层都是Object.prototype。
- 注意:Tiger实例对象和Cat实例对象的原型对象都没有
constructor属性,这是因为我们重写了原型对象,将其赋值为了使用new创建的新对象。