js 面向对象 继承机制
根据w3cschool上的描述:共有3种继承方法(对象冒充,原型链,混合)
1、对象冒充:构造函数ClassA使用this关键字给所有属性和方法赋值,使ClassA构造函数成为ClassB的方法,调用。可实现多重继承。
注意:所有新属性和新方法都必须在删除新方法的代码行后定义,否则会覆盖父类的相关属性和方法,多重继承时存在同名问题。
原始:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | function ClassA(sColor){ this .color = sColor this .sayColor = function (){ alert( this .color); }; }; function ClassB(sColor, sName){ this .newMethod = ClassA; this .newMethod(sColor); delete this .newMethod; //新属性和方法 this .name = sName; this .sayName = function (){ alert( this .name); } } var objA = new ClassA( 'blue' ); var objB = new ClassB( 'red' , 'jack' ); |
call():function对象的一个方法,它是ECMASript把对象冒充规范化的结果
1 2 3 4 5 6 7 8 9 10 11 | function ClassB(sColor, sName) { //this.newMethod = ClassA; //this.newMethod(color); //delete this.newMethod; ClassA.call( this , sColor); this .name = sName; this .sayName = function () { alert( this .name); }; } |
apple():与call类似,第二个参数是数组或arguments(参数对象,两个类中的参数顺序完全一致的话,才可以)
1 2 3 4 5 6 7 8 9 10 11 | function ClassB(sColor, sName) { //this.newMethod = ClassA; //this.newMethod(color); //delete this.newMethod; ClassA.apply( this , new Array(sColor)); this .name = sName; this .sayName = function () { alert( this .name); }; } |
以上存在内存浪费的问题。那就是对于每个实例对象而言,属性和方法都是一样的,但是每次创建新的实例,都要为其分配新的内存空间,这样做就会降低性能,浪费空间,缺乏效率。
2、原型链:把ClassB的prototype属性设置成ClassA的实例。ClassA的构造函数不能传递参数。
注意:所有新属性和新方法都必须在删除新方法的代码行后定义,否则会覆盖父类的相关属性和方法:因为prototype属性被替换成了新对象,添加了新方法和属性的原始对象将被销毁。
对 ClassB 的所有实例,instanceof 为 ClassA 和 ClassB 都返回 true。对象冒充时不能这样(instanceof是讲类型的,而对象冒充是讲方法的。)。不支持多重继承。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | //确保构造函数没有任何参数 function ClassA(){ } //方法用原型链 ClassA.prototype.color = 'blue' ; ClassA.prototype.sayColor = function (){ alert( this .color); } function ClassB(){ } //把 ClassB 的 prototype 属性设置成 ClassA 的实例 ClassB.prototype = new ClassA(); //新方法和属性 ClassB.prototype.name = '' ; ClassB.prototype.sayName = function (){ alert( this .name); } |
3、混合方式:对象冒充的缺点,每个子类都有与父类相同的方法,这样很占空间;而原型链,子类只是指向父类的方法。但是不能多重继承。所以需要结合起来:对象冒充继承属性;原型链继承方法。
通过对象冒充方式继承时,所有的成员方法都是指向this的,也就是说new之后,每个实例将都会拥有这个成员方法,并不是共用的,这就造成了大量的内存浪费。并且通过对象冒充的方式,无法继承通过prototype方式定义的变量和方法(与我想的一样)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //父类属性用构造函数<br>function ClassA(sColor) { this .color = sColor; } //不变的用原型链 ClassA.prototype.sayColor = function () { alert( this .color); }; //子类构造函数用对象冒充继承 function ClassB(sColor, sName) { ClassA.call( this , sColor); this .name = sName; } //方法用原型链继承 ClassB.prototype = new ClassA();<br> //<br>ClassB.prototype.constructor = ClassB //新方法写在最后 ClassB.prototype.sayName = function () { alert( this .name); }; |
注意:所谓的新属性,在对象冒充中是this.name。在原型链中是prototype.name。
instanceof深入学习
(1)值类型:数值、布尔值、null、undefined。
(2)引用类型:对象、数组、函数。
instanceof为了弥补typeof的不足,作用:实例是否属于某种类型;实例是否属于它的父类型;
新概念:显示原型,隐式原型:新概念,哈哈
真难:http://www.ibm.com/developerworks/cn/web/1306_jiangjj_jsinstanceof/
http://www.alloyteam.com/2015/06/javascript-shu-ju-jie-gou-he-suan-fa-jian-shu-qian-yan/
继承有三种方式:
1、
之前提到的混合方式
2、YUI继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | function Animal() {} Animal.prototype.feeling = 'happy' ; function extend(Child, Parent) { var F = function(){}; F.prototype = Parent.prototype; Child.prototype = new F(); Child.prototype.constructor = Child; } extend(Dog, Animal); var dog = new Dog( '二狗' , '哈士奇' ); print(dog.feeling); // happy |
3、jquery继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | function Animal() {} Animal.prototype.feeling = 'happy' ; function deepCopy(Child, Parent) { var p = Parent.prototype; var c = Child.prototype; for ( var i in p) { if ( typeof p[i] === 'object' ) { c[i] = (p[i].constructor === Array) ? [] : {}; deepCopy(p[i], c[i]); } else { c[i] = p[i]; } } } deepCopy(Dog, Animal); var dog = new Dog( '二狗' , '哈士奇' ); print(dog.feeling); // happy |
看情况用吧。
明白了
混合继承时,为什么要加:ClassB.prototype.constructor = ClassB
这篇教程写的很好,自己现在记录一下:http://www.jb51.net/article/22334.htm
重新覆盖prototype后,这条链上的对象和方法的constructor都变为object,为了纠正,需要把constructor重新定义。
对象继承 一般用混合方式比较好,w3cschool上的例子很清楚。
YUI的更高效和简洁。
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步