js继承的六种方案

今天谈谈js中六种继承方式,在介绍继承方式前我们先熟悉几个常用的函数
因为for循环默认会将实例的私有属性和它所属原型上扩展的属性和方法都可以遍历到
但是可以通过propertyIsEnumerable检测只打印私有的

1
2
3
4
5
6
7
8
9
for (var key in obj){
if(obj.propertyIsEnumerable(key)){
console.log(obj[key])
}

if(obj.hasOwnPropery(key)){
console.log(key)
}
}

上述代码会打印obj的私有属性和方法。
下面开始第一个继承,原型继承

原型继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function Fn(){

}

var obj={
constructor = Fn,
name: "zack",
age:7,
getX:function(){

}
}

Fn.prototype= obj

var f = new Fn()
console.log(f.name)
var obj3 = Object.create(obj)
console.log(obj3.name)

通过修改Fn.prototype指向obj,以后new Fn生成的实例都具有obj的属性
我们也可以通过Object.create(obj)创建一个新的对象,这个对象的原型为obj,
所以新对象也继承了obj的私有属性和公有属性
将原型继承简化下

1
2
3
4
5
6
7
8
9
10
11
12
 function Base(){
getX:function(){

}
}

function Derive(){

}

Derive.prototype= new Base()
var nNode = new Derive()

原型继承是我们js中最常用的一种继承方式
子类Base想要继承父类Derive中的所有属性和方法(私有+公有)
只需要让Derive.prototype=new Base; 即可
原型继承的特点,他是把父类中私有的+公有的都继承到了子类原型上(子类公有的)
核心:原型继承并不是把父类中的属性和方法克隆一份一模一样的给Derive
而是让Derive和Base之间增加了原型链的连接,以后Derive的实例nNode想要使用Base中的getX方法
需要一级级向上查找来使用

call继承

call继承,就是把父类私有的属性和方法克隆一份一模一样的给子类私有属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function A(){
this.x = 100
}

A.prototype.getX=function(){
console.log(this.x)
}

function B(){
A.call(this)
}

var n = new B
console.log(n.x)

call函数修改了调用者A的this为B,所以执行A.call(this),其实是执行A的构造函数,将this换为B,
B的x赋值为100。
call继承保证了把父类私有的属性和方法克隆一份一模一样的给子类私有属性

冒充对象继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function A(){
this.x = 100
}
A.prototype.getX=function(){
console.log(this.x)
}

function B(){
var temp = new A
for (var key in temp){
this[key] = temp[key]
}
temp = null
}
var n = new B
console.log(n.x)

冒充对象继承: 把父类私有的+公有的克隆一份一模一样的给子类私有的

混合继承模式:原型继承+call继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function A(){
this.x = 100
}

A.prototype.getX = function(){
console.log(this.x)
}

function B(){
A.call(this)
}

B.prototype = new A
B.prototype.constructor = B
var n = new B
n.getX()

混合继承,基础原理就是通过call继承将基类的私有属性和方法继承过来,然后通过原型继承,
将基类的私有和公有属性方法等全部继承过来。这样会造成私有属性的重复,不过也是很不错的
一种继承方式。

寄生继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function A(){
this.x = 100
}

A.prototype.getX=function(){
console.log(this.x)
}

function B(){
A.call(this)
}
B.prototype = Object.create(A.prototype)
B.prototype.constructor = B

var n = new B
n.getX()

通过call继承将A类的私有属性赋值给B,然后通过Object.create(A.prototype)将A的原型公有属性
赋值给B。我们可以自己实现一个类似于Object.create(pro)的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function CreateObj(obj){
function NewObj(){

}

NewObj.prototype = obj
return new NewObj()
}

unction A(){
this.x = 100
}

A.prototype.getX=function(){
console.log(this.x)
}

function B(){
A.call(this)
}
B.prototype = CreateObj(A.prototype)
B.prototype.constructor = B

var n = new B
n.getX()

中间件继承法

如果我们想对一个类数组arguments,但不是数组进行数组操作,比如排序, shift, pop, join等。
需要调用call方法将arguments,替代数组

1
2
3
4
5
6
7
8
9
function avgFn(){
Array.prototype.sort.call(arguments, function(a,b){
return a-b
})

Array.prototype.pop.call(arguments)
Array.prototype.shift.call(arguments)
return (eval(Array.prototype.join.call(arguments,"+"))/arguments.length).toFixed(2)
}

为了让arguments直接使用数组得方法,可以修改其__proto__方法

1
2
3
4
5
6
7
8
9
10
11
function avgFn(){
arguments.__proto__ = Array.prototype
arguments.sort(function (a, b){
return a -b
})

arguments.pop()
arguments.shift()
return eval(arguments.join("+"))/arguments.length
}
console.log(avgFn(10,20,30,10,30,40))

感谢关注

感谢关注我的公众号
wxgzh.jpg