js原型与原型链
一、prototype与__proto__
1、prototype(显式原型):每一个函数在创建之后都会拥有一个名为prototype的属性,这个属性指向函数的原型对象。它只存在于函数里,例如下面的例子中:
function Person(name) { this.name = name; this.showMe = function() { alert(this.name); } }; Person.prototype.from = function() { alert('I come from prototype.'); } var p = new Person('js'); p.from();
Person拥有prototype对象,我们向对象中添加了一个from方法,构造函数中有一个prototype的属性,改属性是一个指针,指向对应的prototype对象(注意区分一个是属性一个是对象),这里还有一个重要的属性,就是prototype对象中有一个属性constructor,该属性指向对应的构造函数,是一种对应的关系。
p是Person构造函数新建的一个实例,new这个方法分为3个部分,最重要的一步是第2步,就本例子来说
<1> var p={}; 也就是说,初始化一个对象p。
<2> p.__proto__=Person.prototype;
<3> Person.call(p);也就是说构造p,也可以称之为初始化p。
p这个对象没有prototype属性,但是有__proto__属性,这个在下面会提到。
二、__proto__
隐式原型,每一个对象都拥有该属性,上面提到新建的实例p,在实例化的时候,可以得出p.__proto__=Person.prototype。那么当我们调用p.Say()时,首先p中没有Say这个属性, 于是,他就需要到他的__proto__中去找,也就是Person.prototype,而我们在上面定义了 Person.prototype.Say=function(){}; 于是,就找到了这个方法。
具体的例子如下图:
构造函数的原型属性Foo.prototype指向了原型对象,在原型对象里有共有的方法,所有构造函数声明的实例(这里是f1,f2)都可以共享这个方法。
2.原型对象Foo.prototype
Foo.prototype保存着实例共享的方法,有一个指针constructor指回构造函数。
3.实例
f1和f2是Foo这个对象的两个实例,这两个对象也有属性__proto__,指向构造函数的原型对象,这样子就可以像上面1所说的访问原型对象的所有方法。
另外:
构造函数Foo()也有__proto__属性,
指向它的构造函数的原型对象。函数的构造函数就是Function,因此这里的__proto__指向了Function.prototype。
原型对象的__proto__属性
指向它的构造函数的原型对象。这里是Object.prototype.
最后,Object.prototype的__proto__属性指向null。
function Person(name) { this.name = name; this.showMe = function() { alert(this.name); } }; Person.prototype.from = function() { alert('I come from prototype.'); } function SubPer() {} SubPer.prototype = new Person('js'); var son = new SubPer(); son.showMe(); //js son.from(); //I come from prototype. alert(son.constructor);
代码里Person具有原型方法,SubPer通过SubPer.prototype = new Person('js')这句代码实现了继承,new的新实例son可以获取Person的方法。
function Person(name) { this.name = name; this.showMe = function() { alert(this.name); } }; Person.prototype = { //重写原型 alertNum:function(){ alert(1111); } } function SubPer() {} SubPer.prototype = new Person('js'); var son = new SubPer();
我们运行代码,查看son.constructor的值,发现结果如下:
这两个对象的constructor的值都指向了Function,因为我们在这里重写了一个原型对象,每当新创建一个对象时,就会同时创建它的prototype对象,注意这里的对象是由__proto__指向的,这个对象也获得了constructor属性,对象字面量创建的对象其constructor指向Object,所以由Person new的实例,其constructor也指向了Object
代码做如下的修改:
function Person(name) { this.name = name; this.showMe = function() { alert(this.name); } }; Person.prototype = { alertNum:function(){ alert(1111); } } function SubPer() {} SubPer.prototype = new Person('js'); SubPer.prototype.constructor = SubPer; //修改constructor var son = new SubPer();
constructor的值被修改为Suber构造函数,constructor的值可以被修改覆盖。