问题:为什么要继承?js中继承的方式有哪些?
1为什么要继承?原则是什么?
总的原则:减少重复代码,减少耦合
2继承的方式 ?
2.1类式继承,一步一步来改进
2.11继承最简单的方式。
A1.prototype={}
function A2(){}
A2.prototype=new A1;
2.12 继承常用的方式—组合继承
这时: var a1=new A2; a1.colors.push("yellow")
var a2=new A2; a2.colors;
这时,a2.colors的值是什么?
这时a2.colors也一起改变了。所以改进为以下方式
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
最终代码如下
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 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类有这个函数
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设计模式》