利用prototype实现JavaScript继承

本文主要是讲解如何通过prototype实现JavaScript继承,并逐步循序渐进,最终实现一个继承的通用函数。

1.首先我们定义一个父类Father,如下所示:

function Father(){
				this.name = "姓名";
				this.age = "20";
				this.setName = function(str){this.name=str};
				this.getName = function(){return this.name;};
			}
			Father.prototype.setAge = function(age){this.age = age;};
			Father.prototype.getAge = function(){return this.age;};
			console.log(new Father());
运行结果如下:
Father
  1. age"20"
  2. getNamefunction (){return this.name;}
  3. name"姓名"
  4. setNamefunction (str){this.name=str}
  5. __proto__Father
    1. constructorfunction Father(){
    2. getAgefunction (){return this.age;}
    3. setAgefunction (age){this.age = age;}
    4. __proto__Object

可以看到Father具有age、name两个属性以及getName、setName、getAge、setAge四个方法,但是要注意的是setAge、getAge方法是放在Father.prototype中的,prototype中的方法是公共方法,也就是说在创建新的实例时,prototype中的内容不会随着新实例的创建而占用更多的内存,所以公共方法最好放到prototype中。而实例中的setName与getName方法是在实例中的,每当新实例创建时,每个新实例都会额外占用内存来存储这两个方法。


2.使用call(context,para1...)尝试实现继承

代码如下:

function Sun1(){
				Father.call(this);
			}
			console.log(new Sun1())

运行结果如下:

Sun1
  1. age"20"
  2. getNamefunction (){return this.name;}
  3. name"姓名"
  4. setNamefunction (str){this.name=str}
  5. __proto__Sun1
    1. constructorfunction Sun1(){
    2. __proto__Object
由上可知,在子类的构造函数中通过调用Father.call(this)只能使得子类具有父类构造器中写明的属性与方法,但是不能继承父类的prototype中的内容getAge与setAge。


3.尝试使用apply(context,arguments)尝试实现继承

代码如下:

function Sun2(){
				Father.apply(this,arguments);
			}
			console.log(new Sun2());

运行结果如下:

Sun2
  1. age"20"
  2. getNamefunction (){return this.name;}
  3. name"姓名"
  4. setNamefunction (str){this.name=str}
  5. __proto__Sun2
    1. constructorfunction Sun2(){
    2. __proto__Object
由上可知,在子类的构造函数中通过调用Father.apply(this,arguments)也只能使得子类具有父类构造器中写明的属性与方法,但是不能继承父类的prototype中的内容getAge与setAge。


4.通过更改prototype实现继承

代码如下:

function Sun3(){}
			Sun3.prototype = new Father();
			Sun3.prototype.constructor = Sun3;
			console.log(new Sun3());

运行结果如下:

Sun3
  1. __proto__Father
    1. age"20"
    2. constructorfunction Sun3(){}
    3. getNamefunction (){return this.name;}
    4. name"姓名"
    5. setNamefunction (str){this.name=str}
    6. __proto__Father
      1. constructorfunction Father(){
      2. getAgefunction (){return this.age;}
      3. setAgefunction (age){this.age = age;}
      4. __proto__Object
由上可知,我们将子类的prototype属性的值设置为父类的一个实例,就可以使得子类继承了父类的所有属性与方法,需要注意的是,代码Sun3.prototype.constructor = Sun3的意思是将子类的prototype.constructor重新设置为子类的构造器函数。任何一个prototype对象都有一个constructor属性,指向它的构造函数。也就是说,Sun3.prototype 这个对象的constructor属性,是指向Sun3的。代码Sun3.prototype = new Father()删除了这个Sun3.prototype对象原来的值,所以新的prototype对象没有constructor属性,所以我们必须手动加上去,否则后面的"继承链"会出问题。这一点很重要,要切记。


5.继承函数的实现

既然我们知道了如何通过prototype来实现继承,那么我们就可以将该实现封装成一个函数,使得代码可重用,代码如下:

function inherit(child,parent){
				child.prototype = new parent();
				child.prototype.constructor = child;
			}
			function Sun4(){}
			inherit(Sun4,Father);
			console.log(new Sun4());
运行结果如下:

  1. __proto__Father
    1. age"20"
    2. constructorfunction Sun4(){}
    3. getNamefunction (){return this.name;}
    4. name"姓名"
    5. setNamefunction (str){this.name=str}
    6. __proto__Father
      1. constructorfunction Father(){
      2. getAgefunction (){return this.age;}
      3. setAgefunction (age){this.age = age;}
      4. __proto__Object
我们将继承封装成inherit函数,要想实现两个类的继承关系时,把这两个类作为参数传递进去即可。


6.面向对象的通用继承的实现

虽然上文已经通过inherit函数实现了继承函数,但是在使用时每次都要把父子两个类传递进去,还不够面向对象,为了更好的模拟面向对象的特性,我们再进一步进行改进,代码如下:

Function.prototype.method = function(funcName,func){
				this.prototype[funcName] = func;
			};
			
			Function.prototype.inherit = function(parent){
				this.prototype = new parent();
				this.prototype.constructor = this;
			};
			
			function Sun5(){}			
			Sun5.inherit(Father);			
			console.log(new Sun5());

运行结果如下:

Sun5
  1. __proto__Father
    1. age"20"
    2. constructorfunction Sun5(){}
    3. getNamefunction (){return this.name;}
    4. name"姓名"
    5. setNamefunction (str){this.name=str}
    6. __proto__Father
      1. constructorfunction Father(){
      2. getAgefunction (){return this.age;}
      3. setAgefunction (age){this.age = age;}
      4. __proto__Object
Function.prototype.method:此函数是为构造器的prototype附加函数的简单方式。这一特殊的子句能够工作是因为所有的构造器都是函数,故能获得新的方法"method"。 

Function.prototype.inherit:这一函数能用来实现单父继承。由于inherit方法是在Function的原型中的,所以使得所有的子类都能有原生的使用该inherit方法,只需要传递父类的构造函数即可。

注意:在inherit函数中调用parent 的构造函数,没有给它传递参数。这在原型链中是标准做法。要确保构造函数没有任何参数。

如果父类的构造函数中有参数,那该怎么办呢?可以这样实现,代码如下:

function Father(name,age){
				this.name = name;
				this.age = age;
				this.setName = function(str){this.name=str};
				this.getName = function(){return this.name;};
			}
			Father.prototype.setAge = function(age){this.age = age;};
			Father.prototype.getAge = function(){return this.age;};
			console.log(new Father());
			
			
			Function.prototype.method = function(funcName,func){
				this.prototype[funcName] = func;
			};			
			Function.prototype.inherit = function(parent){
				this.prototype = new parent();
				this.prototype.constructor = this;
			};
			
			function Sun6(name,age){
				Father.call(this,name,age);
			}
			Sun6.inherit(Father);			
			console.log(new Sun6("姓名",20));

运行结果如下:

Sun6
  1. age20
  2. getNamefunction (){return this.name;}
  3. name"姓名"
  4. setNamefunction (str){this.name=str}
  5. __proto__Father
    1. ageundefined
    2. constructorfunction Sun6(name,age){
    3. getNamefunction (){return this.name;}
    4. nameundefined
    5. setNamefunction (str){this.name=str}
    6. __proto__Father

这里通过call与prototype的共同使用才实现了继承。

参考:

http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html

http://www.w3school.com.cn/js/pro_js_inheritance_implementing.asp

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值