问题:为什么要继承?js中继承的方式有哪些?
1为什么要继承?原则是什么?
1 reduce the amount of duplicate code
2 make your objects as loosely coupled as possible
总的原则:减少重复代码,减少耦合
2继承的方式 ?
2.1类式继承,一步一步来改进
2.11继承最简单的方式。
function
A1(){}
A1.prototype
=
{}
function
A2(){}
A2.prototype
=
new
A1;
2.12 继承常用的方式—组合继承
如果上面的代码中, function A1(this.colors=["red"])
这时: var a1=new A2; a1.colors.push("yellow")
var a2=new A2; a2.colors;
这时,a2.colors的值是什么?
这时a2.colors也一起改变了。所以改进为以下方式
function
A1(){}
A1.prototype
=
{}
function
A2(){A1.call(
this
)}
A2.prototype
=
new
A1;
2.13 继承的完美方式—寄生式组合继承(高级2上的名字有点长,我把它叫做完美继承)
如果这样,A1.call(this)就覆盖了new A1中的值。这样是没有问题了。但是A1执行了2次!new了一次,call又执行了一次!
所以,考虑让A2.prototype的值只继承A1.prototype。A1中的内容通过A1.call来继承。这样就完美了。
那该怎么做呢?
考虑1:如果直接尝试直接将 A2.prototype=A1.prototype .这样直接引用.这样会产生问题。如果更改A2的prototype,那么A1的prototype也会改变
考虑2:如果浅拷贝:for(var i in A1.prototype) A2.prototype[i]=A1.prototype[i].这样的话1:prototype中方法不能太多。2:A1的prototype如果改动的话,A2就没法继承了。
考虑3:如果深拷贝:A2.prototype=深拷贝A1.prototype.这样还是上面的问题。
继承总结:A1的prototype中的值是可改变的,并且A1的改动会影响到A2;A2的prototype是可改变的,A2的改动不能影响到A1.
A2.prototype=new A1 其实就需要 A2.prototype.__proto__=A1.prototype 也就是
var temp={};temp.__proto__=A1.prototype;A2.prototype=temp 因为__proto__是隐藏属性,所以改成下面
var temp=function(){}; temp.prototype=A1.prototype; A2.prototype=new temp
最终代码如下
function
extend(A2,A1){
var
F
=
function
(){};
F.prototype
=
A1.prototype;
A2.prototype
=
new
F;
A2.prototype.constructor
=
A2;
//
重建
A2.super
=
A1.prototype;
//
新建
}
function
A1(a){
this
.a
=
a}
A1.prototype.say
=
function
(){}
function
A2(a){A1.call(
this
,a)}
extend(A1,A2)
A2.prototype.say2
=
function
(){}
这里指定一个super属性,这样可以减少耦合,因为在不知道A1.prototype的情况下,可以通过A2.super来访问A1.prototype
类式继承总结:A中的值是任意的值,不管是数组引用,或者是对象包含对象。A.prototype中的必须是方法,不能是引用,也不能是对象包含对象。
2.2 原型式继承
类似继承要求我们必须创建构造函数,而原型继承则可以直接使用对象字面量形式.
var
clone
=
function
(a){
function
F(){};F.prototype
=
a;
return
new
F;}
var
g1
=
{name:
""
,colors:[
"
yellow
"
]}
var
g2
=
clone(g1)
g2.name
=
"
free
"
;g2.colors.push(
"
red
"
)
var
g3
=
clone(g1)
g3.name
=
"
riyue
"
;g3.colors.push(
"
green
"
)
//
这样,name被覆盖了,但是colors是引用。colors需要被深拷贝覆盖。
//
以上就等于
function
f1(){};f1.prototype
=
{name:
""
,colors:[
"
yellow
"
],constructor:Object}
//
下面是一个改进的原型式继承,在有数组引用,或者对象中包含对象的情况下。使用函数返回值。
var
b
=
{name:
function
(){
return
[
"
free
"
]},age:
22
}
var
b2
=
clone(b)
var
b3
=
clone(b)
b2.name
=
b2.name()
b2.name.push(
"
free2
"
)
console.info(b2.name,b3.name())
2.3 掺元类
实现把一个函数用到多个类中。
加入我现在有一个函数M。现在要让A1和A2类有这个函数
var
M
=
function
(){}
M.prototype.serialize
=
function
(){
var
o
=
[];
for
(
var
i
in
this
) o.push(i
+
"
:
"
+
this
[i]);
return
o.join(
"
,
"
);}
//
一个函数。用于返回对象的每个属性
function
augment(r,g){
for
(
var
i
in
g.prototype){
if
(
!
r.prototype[i])r.prototype[i]
=
g.prototype[i]}}
//
实现函数
function A2(){this.a=1}
augment(A2,M)
//
实现方式
var a2=new A2
document.write(a2.serialize())
//
这个类的对象可以使用和这个函数了
参考资料:《js高级程序设计2》,《js设计模式》