JS中的原型与继承

原型:

Js所有的函数都有一个prototype属性,这个属性引用了一个对象,即原型对象,也简称原型。这个函数包括构造函数和普通函数,我们讲的更多是构造函数的原型,但是也不能否定普通函数也有原型。譬如普通函数:

function F(){
  ;
}
alert(F.prototype instanceof Object) //true

 

构造函数实例化对象的过程。

function A(x){
  this.x=x;
}
var obj=new A(1);

  实例化obj对象有三步:

  • 1. 创建obj对象:var obj=new A(1);
  • 2. 将obj的内部__proto__指向构造他的函数A的prototype.  类的实例对象的constructor属性永远指向"构造函数"的prototype.constructor.  obj是没有prototype属性的,但是有内部的__proto__,通过__proto__来取得原型链上的原型属性和原型方法
  • 3. 将obj作为this去调用构造函数A,从而设置成员(即对象属性和对象方法)并初始化。 (obj作为了this, 故  obj.x = x)

 

 

2种方式定义原型方法:

function A(x){
  this.x=x;
    this.say = function(){alert(‘hi‘)}  ;
}

另一种:

A.prototype.say=function(){alert("Hi")};

区别:

前者的话,每一个对象都有关于say方法的一个副本。

后者,这个原型对象的say方法是唯一的副本给大家共享的。(这是通过内部的_proto_链来实现的。)

 

 

类继承

简单的继承实现。(js没有类,这里只是指构造函数)

function A(x){
  this.x=x;
}

function B(x2,y){
  this.tmpObj=A;
  this.tmpObj(x2);
  delete this.tmpObj;
  this.y=y;
}

5、6、7行:(临时工角色)

创建临时属性tmpObj引用构造函数A,然后在B内部执行,执行完后删除。

B当然就拥有了x属性:  

function A(x){
  this.x=x;
}

function B(x2,y){
  this.x=x2;
  this.y=y;
}

  

当然B的x属性和A的x属性两者是独立,所以并不能算严格的继承。

第5、6、7行有更简单的实现:

A.call(this,x);

  

问题来了

B虽然继承了A构造对象的所有属性方法,但是不能继承A的原型对象的成员。

function A(x){
  this.x=x;
}
A.prototype.a = "a";

function B(x2,y){
  A.call(this, x);
  this.y=y;
}

这样子B里面是没有继承 A.prototype.a = "a"; 属性的!

 

 

原型继承

解决上面的问题:

function A(x){
   this.x = x;
 }
 A.prototype.a = "a";
 function B(x2,y){
   this.y = y;
   A.call(this,x2);
 }




B.prototype.b1 = function(){
   alert("b1");
}
B.prototype = new A();  //注意A里面没有带参数!
// B先是被“类继承”一次,又被“原型继承”一次
//故B里面有两个x属性,一个为"a",一个undefined!
//这时,"原型属性x"要让位于"实例对象属性x",还是"a"了。

// 还要注意:此时,B.prototype.constructor就是构造对象A了!
//alert(B.prototype.constructor)出来后就是"function A(x){...}"  下面有解决的

//设置了原型方法b1,但是上面一行,原型指向改变,原来具有b1的原型对象被抛弃,自然又没有b1了





//再来个b2
 B.prototype.b2 = function(){
   alert("b2");
 }
 B.prototype.constructor = B;
// 将B原型的构造器重新指向了B构造函数


// 实例化B一个
 var obj = new B(1,3);

类继承是这行:A.call(this.x);

原型继承是这行:B.prototype = new A();

 

如果没有

B.prototype.constructor = B;

那是不是obj = new B(1,3)会去调用A构造函数实例化呢?

答案是否定的:

你会发现obj.y=3,所以仍然是调用的B构造函数实例化的。

只是

obj.constructor===A  //true

对于new B()的行为来说,执行了上面所说的通过构造函数创建实例对象的3个步骤:

  • 第一步,创建空对象;
  • 第二步,obj.__proto__ === B.prototype;  (B.prototype是具有x,a,b2成员的。然后obj.constructor指向了B.prototype.constructor,即构造函数A;)
  • 第三步,调用的构造函数B去设置和初始化成员,具有了属性x,y。

 

 

原文出处:http://ljchow.cnblogs.com 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。