javascript 对象的 prototype

最近恰好有人问起关于 javascript 中的 prototype 相关的问题。特此简单地整理了一下,比较基础,希望能让有类型问题的同学,可以用这篇文章提供参考。

prototype 是通过调用构造函数而创建的对象实例的原型对象。

  • 每一个新的函数,都会拥有一个 prototype 属性,这个属性指向函数的原型对象。

  • 所有原型对象都有一个 constructor 属性,指向了 prototype 属性所在函数的指针,即 Cat.prototype.constructor == Cat

  • prototype 对象是通过构造函数所产生的实例对象的原型对象,Cat.prototype.loveThing 为 prototype 添加属性,组成了这个prototype 对象。

  • 实例对象拥有一个指针 [[prototype]] 指向了它的原型对象 prototype。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

function Cat(name){

    this.name = name; 

}

Cat.prototype.loveThing = ['apple'];

Cat.prototype.sayHi = function(){

    alert(this.name); 

}

var tomcat = new Cat('TOM');

tomcat.sayHi(); // TOM

tomcat.loveThing.push('orange');

alert(tomcat.loveThing); // apple,orange

var redcat = new Cat('RED');

tomcat.sayHi(); // RED

alert(redcat.loveThing); // apple,orange

可以看到,上面 tomcat 还有 redcat 作为 Cat 的实例,都 sayHi 出各自构造函数传入的 name。这并不奇怪。而 retcat 的loveThing 和 tomcat 一样,都是 apple,orange ?

当实例 tomcat 调用 tomcat.loveThing 的时候,由于实例中没有 loveThing 这个属性(与其原型对象相同),所以会继续向上搜索,读取到其原型对象的 loveThing 属性。此时执行的 tomcat.loveThing.push(‘orange’),相当于对原型对象进行操作,类似 Cat.prototype.loveThing.push(‘orange’);由于原型对象为所有对象实例 共用 。所以,后来执行了 redcat.loveThing,相当于执行了 Cat.prototype.loveThing;从而得到与 tomcat 相同的结果。

重写原型对象切断现有原型与任何之前已经存在的对象实例直接的联系,他们的引用仍然是最初的原型。

1

2

3

4

5

6

7

8

9

function Person(){};

var xiaoming = new Person();

Person.prototype = {

    constructor: Person,

    sayHi: function(){

        console.log('hi')

    }

}

xiaoming.sayHi(); // err

常用原型语法

1

2

3

4

5

6

7

8

9

10

11

12

function Cat(name){

    this.name = name;

}

Cat.prototype = {

    constructor: Cat,   //重新指向Cat

    sayHi: function(){

        console.log(this.name);

    }

}

var tomCat = new Cat();

console.log(tomCat instanceof Cat); // true

console.log(tomCat instanceof Object); //true 

上面代码重写了 Cat 的 prototype 属性,由于每一个 prototype 一个对应的 constructor 属性,所以此时 constructor 指向了 Object

1

console.log(tomCat.constructor == Cat);