JS学习笔记——JavaScript继承的6种方法(原型链、借用构造函数、组合、原型式、寄生式、寄生组合式)
2017-05-18 23:03
1311 查看
JavaScript继承的6种方法
1.原型链继承.
特点:既继承了父类的模板,又继承了父类的原型对象。
缺点:只能在父类设置一些参数,子类不能灵活传参,不符合面向对象的思想,包含引用类型值的属性始终都会共享相应的值。
2.借用构造函数继承
特点:只继承了父类的模板,不继承父类的原型对象。
缺点:方法都在构造函数中定义,不能做到函数复用。
3.组合继承(原型+借用构造)最常用的继承模式
特点:既继承了父类的模板,又继承了父类的原型对象。
缺点:做了3件事,继承了父类两次模板,继承了一次原型对象
原型式继承解决了这个问题
4.原型式继承
创造的目的是基于已有的对象创建新的对象,同时还不必因此创建自定义类型。
包含引用类型值的属性始终都会共享相应的值,就像使用原型模式一样。
5.寄生式继承
与构造函数模式类似,不能做到函数复用会降低效率。
6.寄生组合式继承
寄生式组合继承解决了组合继承会调用两次父类构造函数,子类最终会包含父类的全部实例属性,父类的属性不是必须的,子类的属性会覆盖父类的属性。
寄生式组合继承只调用一次父类构造函数,原型链能保持不变,因此还能够正常使用instanceof和isPrototypeOf(),YUI的extend方法就使用的是寄生组合继承,是实现基于类型继承的最有效的方式。
1,原型链继承 2,借用构造函数继承 3,组合继承(原型+借用构造) 4,原型式继承 5,寄生式继承 6,寄生组合式继承
1.原型链继承.
<script type="text/javascript"> function Person(name,sex) { this.name=name; this.sex=sex; this.friends=['李四']; this.getName=function(){ alert(this.name); } } Person.prototype.id=1; function Boy(age) { this.age=age; this.getAge=function(){ alert(this.age); } } //继承 Boy.prototype=new Person("张三","男"); var boy=new Boy(16); alert(boy.name); //张三 boy.getAge(); //16 alert(boy.id); //1 //属性共享问题 console.log(boy.friends); //李四 var boy2=new Boy(17); boy2.friends.push('王五'); //修改boy2的friends属性的同时也影响了boy的属性 console.log(boy.friends); //李四 王五 //验证能否使用instanceof 和 isPrototypeof console.log(boy instanceof Person); //true console.log(Person.prototype.isPrototypeOf(boy)); //true </script>
特点:既继承了父类的模板,又继承了父类的原型对象。
缺点:只能在父类设置一些参数,子类不能灵活传参,不符合面向对象的思想,包含引用类型值的属性始终都会共享相应的值。
2.借用构造函数继承
<script type="text/javascript"> //父类 function Person(name,sex) { this.name=name; this.sex=sex; this.friends=['李四']; } Person.prototype.id=1; //子类 function Boy(name,sex,age) { //借用 Person.call(this,name,age); this.age=age; this.getAge=function(){ alert(this.age); } } var boy=new Boy("张三","男",16); alert(boy.name); //张三 boy.getAge(); //16 alert(boy.id); //undefined 没有继承父类的原型对象 //属性共享问题 ————不会有共享 //验证能否使用instanceof 和 isPrototypeof console.log(boy instanceof Person); //false console.log(Person.prototype.isPrototypeOf(boy)); //false </script>
特点:只继承了父类的模板,不继承父类的原型对象。
缺点:方法都在构造函数中定义,不能做到函数复用。
3.组合继承(原型+借用构造)最常用的继承模式
<script type="text/javascript"> //父类 function Person(name,sex) { this.name=name; this.sex=sex; } Person.prototype.id=1; //子类 function Boy(name,sex,age) { //借用构造函数 继承父类的模板 Person.call(this,name,age); this.age=age; this.getAge=function(){ alert(this.age); } } //不传递参数,继承父类的模板,继承父类的原型对象 id Boy.prototype=new Person(); var boy=new Boy("张三","男",16); alert(boy.name); //张三 boy.getAge(); //16 alert(boy.id); //1 //属性共享问题 ————除了父类的原型对象,不会有共享 //验证能否使用instanceof 和 isPrototypeof console.log(boy instanceof Person); //true console.log(Person.prototype.isPrototypeOf(boy)); //true </script>
特点:既继承了父类的模板,又继承了父类的原型对象。
缺点:做了3件事,继承了父类两次模板,继承了一次原型对象
原型式继承解决了这个问题
4.原型式继承
<script type="text/javascript"> var person={ name:'张三', sex:'男', friends:['李四'] } function object(obj) { function F(){} //创建一个空的构造函数 F.prototype=obj; //将传入的对象作为这个构造函数的原型 return new F(); //返回一个新实例 对传入的对象进行了一次浅复制 } var boy=object(person); //ECMAScript 5 新增了Object.create()方法 与本例 object 方法行为相同 //可改为 Object.create(person); alert(boy.name); //张三 //但是原型式同样存在属性共享的问题 //例如: var girl=object(person); girl.friends.push('王五'); alert(boy.friends); //李四 王五 alert(girl.friends);//李四 王五 //修改girl中的friends属性 boy 也会受到影响 //无法使用 instanceof 和 isPrototypeof </script>
创造的目的是基于已有的对象创建新的对象,同时还不必因此创建自定义类型。
包含引用类型值的属性始终都会共享相应的值,就像使用原型模式一样。
5.寄生式继承
<script type="text/javascript"> function object(obj) { function F(){} //创建一个空的构造函数 F.prototype=obj; //将传入的对象作为这个构造函数的原型 return new F(); //返回一个新实例 对传入的对象进行了一次浅复制 } function Person(person) { var clone=object(person); clone.getSex=function(){ alert(this.sex); } return clone; } var person={ name:'张三', sex:'男', friends:['李四'] } var boy=Person(person); boy.getSex(); //男 //属性共享问题————因为传入同一个实例,所以存在共享问题 var boy2=Person(person); boy2.friends.push('王五'); alert(boy.friends); //李四 王五 //验证能否使用instanceof 和 isPrototypeof console.log(boy instanceof Person); //false console.log(Person.prototype.isPrototypeOf(boy)); //false </script>
与构造函数模式类似,不能做到函数复用会降低效率。
6.寄生组合式继承
<script type="text/javascript"> function object(o) { function F(){} console.log(o); F.prototype=o; return new F(); } function extend(subType,superType) { var prototype=object(superType.prototype); //创建父类的一个副本 prototype.constructor=subType; //为创建的副本添加失去默认的构造函数 subType.prototype=prototype; //将新创建的对象赋值给子类的原型 } function Person(name) { this.name=name; this.friends=['李四']; } function Boy(name,sex) { Person.call(this,name); //借用构造函数 继承父类的模板 this.sex=sex; } extend(Boy,Person); //继承 var boy=new Boy('张三','男'); alert(boy.name); //张三 //属性共享问题————不会存在共享问题 var boy2=new Boy('张三','男'); boy2.friends.push('王五'); alert(boy.friends); //李四 //验证能否使用instanceof 和 isPrototypeof console.log(boy instanceof Person); //false console.log(Person.prototype.isPrototypeOf(boy)); //false </script>
寄生式组合继承解决了组合继承会调用两次父类构造函数,子类最终会包含父类的全部实例属性,父类的属性不是必须的,子类的属性会覆盖父类的属性。
寄生式组合继承只调用一次父类构造函数,原型链能保持不变,因此还能够正常使用instanceof和isPrototypeOf(),YUI的extend方法就使用的是寄生组合继承,是实现基于类型继承的最有效的方式。
相关文章推荐
- JavaScript继承基础讲解(原型链、借用构造函数、混合模式、原型式继承、寄生式继承、寄生组合式继承)
- JavaScript继承基础讲解(原型链、借用构造函数、混合模式、原型式继承、寄生式继承、寄生组合式继承)
- JavaScript继承基础讲解,原型链、借用构造函数、混合模式、原型式继承、寄生式继承、寄生组合式继承
- JavaScript继承基础讲解(原型链、借用构造函数、混合模式、原型式继承、寄生式继承、寄生组合式继承)
- Js面向对象漫谈(2) 继承--原型链,借用构造函数,组合式,寄生式, 寄生组合式
- js 继承 三种常用方法 原型链-借用构造函数-组合式继承
- js 组合继承(使用原型模式和构造函数模式)和原型式继承
- 【JavaScript学习】面向对象的程序设计(7):寄生式继承和寄生组合式继承
- JS原型链、继承的问题与解决:组合继承、借用构造函数(未完)
- JavaScript学习笔记(三十二) 经典继承模式二-借用构造方法
- javascript继承,原型链继承、借用构造函数、组合继承
- JavaScript高级程序设计(第2版) 学习笔记:(六)js基于构造函数与原型的继承
- javascript学习笔记(十) js对象 继承
- javascript 学习笔记3-构造函数、类和原型
- javascript继承之借用构造函数与原型
- JavaScript中的继承学习笔记(1):Crockford uber方法中的陷阱
- JavaScript学习笔记(四十) 借用方法
- Javascript学习笔记(二)Javascript核心之类,构造函数和原型
- js设计模式学习之面向对象的javascript(三)--原型式继承
- JavaScript学习笔记-原型继承