原型继承是js中最通用的继承方式,不用实例化对象,通过直接定义对象,并被其他对象引用,这样形成的一种继承关系,其中引用对象被称为原型对象。
function A(){ this.color = 'red'; } function B(){} function C(){} B.prototype = new A(); C.prototype = new B(); // 测试原型继承 var c = new C(); console.log(c.color); // red
原型继承显得很简单,不需要每次构造都调用父类的构造函数,也不需要通过复制属性的方式就能快速实现继承。但它也存在一些缺点:
① 每个类型只有一个原型,所以不支持多重继承
② 不能很好的支持多参数或动态参数的父类,显得不够灵活。
③ 占用内存多,每次继承都需要实例化一个父类,这样会存在内存占用过多的问题。
实例继承
实例化类可创建新的实例对象,这个实例对象将继承类的所有特征。
function Arr() { var a = new Array(); return a; } var arr = new Arr(); arr[0] = 1; arr[1] = 2; console.log(arr); // [1,2] console.log(Array.isArray(arr)); // true console.log(arr instanceof Array); // true console.log(arr instanceof Arr); // false
通过构造函数中完成对类的实例化操作,然后返回实例对象,这就是实例继承的由来。实例继承可实现对所有对象的继承,包括自定义类,核心对象和DOM对象。但是也有一些缺点
① 实例继承无法传递动态参数,它是封闭在函数体内试下你,不能通过call和apply来实现动态传参。
② 实例继承只返回一个对象,不支持多重继承
③ 实例继承对象它仍然保持与原对象的实例关系,无法实现继承对象是封装类的实例。如:console.log(arr instanceof Arr); // false
复制继承
复制继承就是利用for in 遍历对象成员,逐一复制给另一个对象。通过这种方式来实现继承。
function A(){ this.color = 'red'; } A.prototype.say = function() { console.log(this.color); } var a = new A(); var b = {}; // 开始拷贝 for(var item in a) { b[item] = a[item]; } // 开始测试 console.log(b.color); // red b.say(); // red.
我们把它封装一下:
Function.prototype.extend = function(obj){ for(item in obj){ this.constructor.prototype[item] = obj[item]; } } function A(){ this.color = 'green'; } A.prototype.say = function(){ console.log(this.color); } // 测试 var b = function(){}; b.extend(new A()); b.say(); // green
复制继承实际上是通过反射机制复制类对象中的可枚举属性和方法来模拟继承。这种可以实现多继承。但也有缺点:
① 由于是反射机制,不能继承非枚举类型的属性和方法。对于系统核心对象的只读方法和属性也无法继承。
② 执行效率差,这样的结构越庞大,低效就越明显。
③ 如果当前类型包含同名成员,这些成员会被父类的动态复制给覆盖。
④ 多重继承中,复制继承不能清晰描述父类和子类的相关性。
⑤ 在实例化后才能遍历成员,不够灵活,也不支持动态参数
⑥ 复制继承仅仅是简单的引用赋值,如果父类成员包含引用类型,那么也会带来很多副作用,如不安全,容易遭受污染等。
克隆继承
通过对象克隆方式继承,可以避免赋值对象成员带来的低效。
为Function对象扩展一个clone方法。该方法可把参数对象赋值给一个空的构造函数的原型对象,然后返回实例化后的对象,这样该对象就拥有构造哈数包含的所有成员了。
Function.prototype.clone = function(obj){ function Temp(){}; Temp.prototype = obj; return new Temp(); } function A(){ this.color = 'purple'; } var o = Function.clone(new A()); console.log(o.color); // purple
混合继承
混合继承是把多种继承方式一起使用,发挥各个优势,来实现各种复杂的应用。最常见的就是把类继承和原型继承一起使用。