js原型与原型链

1、prototype与__proto__javascript

  一、prototype(显式原型):每个函数在建立以后都会拥有一个名为prototype的属性,这个属性指向函数的原型对象。它只存在于函数里,例以下面的例子中:java

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步,就本例子来讲 this

    <1> var p={}; 也就是说,初始化一个对象p。spa

    <2> p.__proto__=Person.prototype;prototype

    <3> Person.call(p);也就是说构造p,也能够称之为初始化p。3d

  p这个对象没有prototype属性,可是有__proto__属性,这个在下面会提到。指针

 

 

2、__proto__code

  隐式原型,每个对象都拥有该属性,上面提到新建的实例p,在实例化的时候,能够得出p.__proto__=Person.prototype。那么当咱们调用p.Say()时,首先p中没有Say这个属性, 因而,他就须要到他的__proto__中去找,也就是Person.prototype,而咱们在上面定义了 Person.prototype.Say=function(){}; 因而,就找到了这个方法。对象

  具体的例子以下图:

  

1.构造函数Foo()
构造函数的原型属性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。
 
所以,这几个属性的具体总结是:
  一、__proto__:指向其构造函数的原型对象,全部的对象都拥有该属性
  二、prototype:指向函数的原型对象,只有函数拥有
  三、constructor:这个属性从字面上来理解,就是指向它的构造函数,其本意也能够这么理解。实例的构造函数是Person,Person的构造函数是Function等等
 
3、原型链与继承
  继承实际是就是已原型链为基础,经过__proto__属性的一层层查找,来找到父对象原型中的方法,获取使用
  先看代码:
  
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的方法。

  

  继承实现的方法就是:把子类的 prototype设置为父类的一个(实例化)对象;
  SubPer.prototype = new Person();
  利用以前学到的new方法,能够转换为
  SubPer.prototype.__proto__ = Person.prototype;
  由图上能够看出   实例的__proto__指向prototype,因此
  p.__proto__.__proto__ = Person.prototype;
  这样就造成了一个已__proto__为链接的原型链。
 
  其实只从图上观察,也能够看到__proto__造成的一条线路,SubPer实例——SubPer的prototype(Person实例)——Person的prototype,这就一条原型链。
  
4、继承过程当中的constructor
  咱们知道构造函数的原型中有一个constructor值,指向其构造函数。在书写原型的过程当中,若是采用以下所示重写原型的方法,就可能会形成constructor值得异常
		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的值能够被修改覆盖。

相关文章
相关标签/搜索