Javascript实现继承的6种方式
2016-08-06 16:37
627 查看
一.类式继承
简介:将父类对象的实例赋值给子类的原型,则子类的原型可以访问父类原型上的属性和方法,以及父类构造函数中复制的属性和方法。
instanceof SuperClass)才会打印出true。
类式继承有两个缺点:
1.子类通过其原型prototype对父类实例化,继承了父类。但当父类中的共有属性是引用类型时,会在子类中被所有的实例共用,如此在一个子类实例中更改从父类中继承过来的公有属性时,会影响到其他子类。
2.由于子类是通过原型prototype实例化父类实现继承的,所以在创建父类的时候,无法向父类传递参数,因而在实例化父类的时候无法对父类构造函数内的属性初始化。
二.构造函数式继承
简介:通过在子类的构造函数中执行一次父类的构造函数实现。
缺点:
这种类型的继承没有涉及原型prototype,所以父类的原型方法不会被子类继承。如想被子类继承就必须放在构造函数中,这样创造的每个实例都会单独拥有一份而不能共用,违背了代码复用原则。
三.组合式继承
简介:综合以上两种模式的优点,在子类原型上实例化父类,在子类构造函数中执行一遍父类的构造函数。这样融合了类式继承和构造式继承的优点,过滤了缺点。
父类的构造函数执行了两遍:一次在子类的构造函数中call方法执行一遍,一次在子类原型实例化父类的时候执行一遍。
四.原型式继承
简介:对类式继承的封装,过渡对象相当于子类。
和类式继承一样,父类对象的引用类型值被共用。
五.寄生式继承
简介:寄生式继承其实是对原型继承的第二次封装,并且在第二次封装的过程中对继承的对象进行了拓展。
六.寄生组合式继承
简介:寄生式继承和构造函数式继承结合使用。
注:本文知识点参考《JavaScript设计模式》张荣铭 著 人民邮电出版社
简介:将父类对象的实例赋值给子类的原型,则子类的原型可以访问父类原型上的属性和方法,以及父类构造函数中复制的属性和方法。
//1.类式继承 //声明父类 function SuperClass() { this.superValue = true; } //为父类添加公有方法 SuperClass.prototype.getSuperValue = function () { return this.superValue; }; //声明子类 function SubClass() { this.subValue = false; } //继承父类 SubClass.prototype = new SuperClass();//将父类对象赋值给子类原型,子类原型可访问父类原型上的属性和方法--类式继承原理 //子类添加公有方法 SubClass.prototype.getSubValue = function() { return this.subValue; }; //测试 var instance = new SubClass(); console.log(instance.getSuperValue());//t console.log(instance.getSubValue());//f // console.log(instance instanceof SuperClass);//t console.log(instance instanceof SubClass);//t console.log(SubClass instanceof SuperClass);//f console.log(SubClass.prototype instanceof SuperClass);//t通过instanceof来检测某个对象是否是某个类的实例,或者某个对象是否继承了某个类,这样可以判断对象和类之间的继承关系。instanceof通过判断对象的prototype链来确定这个对象是否是某个类的实例。需要注意的是,inatanceof是判断前面的对象是否是后面类(对象)的实例,并不表示两者的继承。所以console.log(SubCass instanceof SuperClass)会打印出false,而console.log(SubClass.prototype
instanceof SuperClass)才会打印出true。
类式继承有两个缺点:
1.子类通过其原型prototype对父类实例化,继承了父类。但当父类中的共有属性是引用类型时,会在子类中被所有的实例共用,如此在一个子类实例中更改从父类中继承过来的公有属性时,会影响到其他子类。
function SuperClass() { this.book = ['javascript','html','css']; } function SubClass() {} SubClass.prototype = new SuperClass(); var ins1 = new SubClass(); var ins2 = new SubClass(); console.log(ins1.book); console.log(ins2.book); ins1.book.push("Node"); console.log("after"); //引用类型在子类中被所有实例共用 console.log(ins1.book);//[ 'javascript', 'html', 'css', 'Node' ] console.log(ins2.book);//[ 'javascript', 'html', 'css', 'Node' ]
2.由于子类是通过原型prototype实例化父类实现继承的,所以在创建父类的时候,无法向父类传递参数,因而在实例化父类的时候无法对父类构造函数内的属性初始化。
二.构造函数式继承
简介:通过在子类的构造函数中执行一次父类的构造函数实现。
//2.构造函数式继承 //声明父类 function SuperClass(id) { this.book = ['javascript','html','css'];//引用类型共有属性 this.id = id;//值类型公有属性 } //父类声明原型方法 SuperClass.prototype.showBooks = function() { console.log(this.books); } //声明子类 function SubClass(id) { //继承父类 SuperClass.call(this,id); } //测试 var ins1 = new SubClass(1); var ins2 = new SubClass(2); ins1.book.push("Node"); console.log(ins1.id);//1 console.log(ins1.book);//['javascript', 'html', 'css', 'Node'] console.log(ins2.id);//2 console.log(ins2.book);//['javascript', 'html', 'css'] ins1.showBooks();//TypeError: ins1.showBooks is not a functionSuperClass.call(this,id)是构造函数式继承的中心。call方法可以改变函数的作用环境,在子类中调用这个方法就是将子类中的变量在父类中执行,父类中给this绑定属性,因而子类继承了父类的共有属性。
缺点:
这种类型的继承没有涉及原型prototype,所以父类的原型方法不会被子类继承。如想被子类继承就必须放在构造函数中,这样创造的每个实例都会单独拥有一份而不能共用,违背了代码复用原则。
三.组合式继承
简介:综合以上两种模式的优点,在子类原型上实例化父类,在子类构造函数中执行一遍父类的构造函数。这样融合了类式继承和构造式继承的优点,过滤了缺点。
//3.组合式继承 function SuperClass(name) { this.name = name; this.book = ['javascript','html','css']; } SuperClass.prototype.getName = function () { console.log(this.name); }; function SubClass(name,time) { //构造函数式继承,继承父类name属性 SuperClass.call(this,name); this.time = time; } //类式继承,子类原型继承 SubClass.prototype = new SuperClass(); //子类原型方法 SubClass.prototype.getTime = function () { console.log(this.time); }; //测试 var ins1 = new SubClass('Node',2016); ins1.book.push("Node"); console.log(ins1.book); ins1.getName(); ins1.getTime(); var ins2 = new SubClass('React',2015); console.log(ins2.book); ins2.getName(); ins2.getTime();缺点:
父类的构造函数执行了两遍:一次在子类的构造函数中call方法执行一遍,一次在子类原型实例化父类的时候执行一遍。
四.原型式继承
简介:对类式继承的封装,过渡对象相当于子类。
//4.原型式继承 function inheritObject(o) { //声明过渡函数对象 function F() {} //过渡对象的原型继承父类 F.prototype = o; return new F(); } //测试 var book = { name : "javascript", book : ['js','css'] }; var newbook = inheritObject(book); newbook.name = "ajax"; newbook.book.push("Node"); var otherbook = inheritObject(book); otherbook.name = "xml"; otherbook.book.push("React"); console.log(newbook.name);//ajax console.log(newbook.book);//[ 'js', 'css', 'Node', 'React' ] console.log(otherbook.name);//xml console.log(otherbook.book);//[ 'js', 'css', 'Node', 'React' ] console.log(book.name);//javascript console.log(book.book);//[ 'js', 'css', 'Node', 'React' ]缺点:
和类式继承一样,父类对象的引用类型值被共用。
五.寄生式继承
简介:寄生式继承其实是对原型继承的第二次封装,并且在第二次封装的过程中对继承的对象进行了拓展。
//5.寄生式继承 function inheritObject(o) { //声明过渡函数对象 function F() {} //过渡对象的原型继承父类 F.prototype = o; return new F(); } //声明基对象 var book = { name : "javascript", book : ['js','css'] }; function createBook(obj) { //通过原型继承方式创建新对象 var o = new inheritObject(obj); //拓展新对象 o.getName = function() { console.log(name); } //返回拓展后的新对象 return o; } var newbook = createBook(book); newbook.name = "ajax"; newbook.book.push("Node"); var otherbook = createBook(book); otherbook.name = "xml"; otherbook.book.push("React"); console.log(newbook.name);//ajax console.log(newbook.book);//[ 'js', 'css', 'Node', 'React' ] console.log(otherbook.name);//xml console.log(otherbook.book);//[ 'js', 'css', 'Node', 'React' ] console.log(book.name);//javascript console.log(book.book);//[ 'js', 'css', 'Node', 'React' ]
六.寄生组合式继承
简介:寄生式继承和构造函数式继承结合使用。
//寄生组合式继承 function inheritObject(o) { //声明过渡函数对象 function F() {} //过渡对象的原型继承父类 F.prototype = o; return new F(); } //寄生式继承 继承原型 function inheritPrototype(subClass,superClass) { //复制一份父类的原型副本保存在变量中 var p = inheritObject(superClass.prototype); //修正因为重写子类原型导致子类的constructor属性被修改 p.constructor = subClass; //设置子类的原型 subClass.prototype = p; } function SuperClass(name) { this.name = name; this.colors = ["red","blue","green"]; } //定义父类原型方法 SuperClass.prototype.getName = function() { console.log(this.name); } function SubClass(name,time) { SuperClass.call(this,name); this.time = time; } //寄生式继承父类原型 inheritPrototype(SubClass,SuperClass); //子类新增原型方法 SubClass.prototype.getTime = function() { console.log(this.time); } //测试 var ins1 = new SubClass("js",2014); var ins2 = new SubClass("css",2015); ins1.colors.push("black"); console.log(ins1.colors); console.log(ins2.colors); ins2.getName(); ins2.getTime();
注:本文知识点参考《JavaScript设计模式》张荣铭 著 人民邮电出版社
相关文章推荐
- Javascript实现继承的6种方式
- Javascript学习笔记:6种实现继承的方式
- javascript——实现继承的6种方式
- 面向对象的JavaScript 五 ----- Javascript实现继承的方式(2)
- javascript 继承实现方式
- javascript使用call方式实现对象继承
- 从继承方式的实现看javascript语言的设计初衷
- javascript实现继承的多种方式
- JavaScript继承实现方式一览
- 基于JavaScript实现继承机制之构造函数+原型链混合方式的使用详解
- JavaScript实现继承机制(3)——通过原型链(prototype chaining)方式
- Javascript继承实现方式
- 实现JavaScript中继承的三种方式
- javascript中实现对象继承的五种方式详解
- javascript实现继承的方式
- JavaScript继承实现方式一览 - winter-cn - 博客园
- 实现JavaScript中继承的三种方式
- 讲述Javascript 实现继承的方式(基础知识)
- javascript 继承实现方式
- 使用混合方式实现javascript中对象的继承(推荐使用)