Javascript 继承

javascript是基于对象(又说是面向对象)的编程语言,继承很自然的成了重要的知识点。本文主要探讨几种常见的继承方式。

首先定义一个父类 Super

function Super(){

this.name = 'hale';

this.age = 25;

this.friend = ['aaa','bbb'];

}

Super.prototype.getName = function(){

console.log(this.name);

}

在实现一个继承Super的子类Sub时,有下面几种方式:

1 使用call/apply实现继承

function Sub(){

Super.call(this);

}

var s1 = new Sub();

var s2 = new Sub();

s1.friend.push('ccc');

console.log(s1.friend.join(',')); // aaa,bbb,ccc

console.log(s2.friend.join(',')); //aaa,bbb  属性不共享

s1.getName(); // error  

使用call可以继承类属性或者方法,但是不能继承prototype定义的方法,同时父类Super的类属性(friend,这里只讨论引用类型)继承到子类Sub之后,依然是类属性,而类属性在每个实例中都保存了一份副本,所以不存在引用类型的共享问题。

2 使用prototype实现继承

function Sub(){

}

Sub.prototype = new Super();

var s1 = new Sub();

var s2 = new Sub();

s1.friend.push('ccc');

console.log(s1.friend.join(',')); // aaa,bbb,ccc

console.log(s2.friend.join(',')); //aaa,bbb,ccc   属性共享了

s1.getName(); 

使用prototype继承可以继承父类Super中的属性和方法,但是有下面两个问题:

a. Sub.prototype.constructor的变了,现在指向Super了。

b. Super中的类属性(friend)变成了Sub中的prototype属性了,就这以为了Sub的实例将共享friend。所以会出现上面的结果。

3 使用组合方式继承

function Sub(){

Super.call(this);

}

Sub.prototype = new Super();

Sub.prototype.constructor = Sub;

这种方式可以算是一个比较完美的解决方法,但是看看下面的结果。

var s1 = new Sub();

console.log(s1.name); // hale

delete s1.name;

console.log(s1.name); //hale

两次都会输出结果,正常情况下,delete对象的属性之后,属性就不存在了。那么这里唯一的解释是类属性继承了2次。实际上,使用call的时候,已经在类Sub中继承了一次,而使用Sub.prototype = new Super();时又在原型中继承了一次,这样就导致类属性继承了两次,s1.name访问name是,变量的查找顺序首先会查找类属性,然后查找原型属性。所以上面的结果,第一次s1.name查找的是类属性,第二次s1.name首先查找类属性,发现不存在,然后查找原型属性。关于这一点的验证可以按照下面的思路修改:

将父类改成带参数传递  function Super(name){this.name = name;},然后再继承的时候call和prototype分别传递不同的参数 Super.call(this,'aaa'),Sub.prototype = new Super('bbb');然后再次查看上面的结果。

4 使用链式继承

这是最近才发现的一种继承方式,使用有局限,仅限于继承一次,比如有两次或者更多的继承就不太适用,比如B extends A; C extends B,这种情况下就不太适合了。

Sub.prototype.superClass = Super;

function Sub(){

this.superClass(); // 和call方式类似,将Super()挂在当前的作用域链下执行。

}

使用这种方式,子类可以访问父类的类属性和原型发放,但是问题来了:

var child = new Child();
child.superClass.prototype.getName();

运行下面的代码的时候,发现有问题,笔者马上想到了应该是getName函数中this指向的问题,现在的this没有指向child,而是指向了Super.prototype;那么this.name这时就是Super.prototype.name,显然not found.

于是考虑了下面的这种调用方式,使用call强制将this指向了child

child.superClass.prototype.getName.call(child); // this == child

运行结果正常。

5 拷贝

这一种严格意义上来说,并不属于继承,它将父类中的属性和方法copy到子类中,最简单的原型时

for(var i in super){

sub[i] = super[i];

}

当然读者可以在赋值之前,加上一些if来做判断,比如方法重复之类的。





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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值