每个类有 3 部分,
第一部分是构造函数内的,供实例化对象复制用的
第二部分是构造函数外的,直接通过点语法添加,这是供类使用的,实例化对象访问不到
第三部分是类的原型中,实例化对象可以通过其原型链间接访问到,也是供所有实例化对象共用的。
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;};
类的原型对象是为类的原型添加共有方法,但类不能直接访问这些属性和方法,必须通过原型 prototype 来访问。通过改变原型,新创建的对象不仅可以访问父类原型的属性和方法,也可以访问从父类构造函数中复制的属性和方法。
- var instance = new SubClass();
- console.log(instance.getSuperValue()); //trueconsole.log(instance.getSubValue());//false
instanceof 是通过判断对象的 prototype 链来来检测某个对象是否是某个类的实例,而不关心对象和类的自身结构。
- console.log(instance instanceof SuperClass); //trueconsole.log(instance instanceof SubClass);//trueconsole.log(SubClass instance SuperClass);//false
subclass 继承 superclass 是通过将 superclass 的实例赋值给 subclass 的原型 prototype,所以 SubClass.prototype 继承了 superClass
- console.log(SubClass.prototype instanceof SuperClass); //true
类式继承的缺点:
(1)子类通过原型继承了父类,父类中的共有属性要是引用类型,就会在子类中被所有实例共用。因此一个子类的实例更改子类原型从父类构造函数中继承来的共有属性就会直接影响其他子类。
- function SuperClass() {
- this.books = ['js', 'html', 'CSS'];
- }
- function SubClass() {}
- SubClass.prototype = new SuperClass();
- var instance1 = new SubClass();
- var instance2 = new SubClass();
- console.log(instance2.books); // js html cssinstance1.books.push('设计模式');console.log(instance2.books);// js html css 设计模式
(2)子类实现的继承是靠其原型 prototype 对父类的实例化实现的,因此在创建父类的时候,是无法向父类传递参数的,因而在实例化父类的时候也无法对父类构造函数内的属性初始化
2. 构造函数继承
- //声明父类function SuperClass(id){ //引用类型共有属性 this.books=['js','html','css']; //值类型共有属性 this.id=id;}//父类声明原型方法SuperClass.prototype.showBooks=function(){ console.log(this.books);}//声明子类function SubClass(id){ //继承父类 SuperClass.call(this,id);}//创建第一个子类的实例var instance1=new SubClass(10);//创建第二个子类的实例var instance2=new SubClass(11);instance1.books.push('设计模式');console.log(instance1.books);//js html css 设计模式console.log(instance1.id);//10console.log(instance2.books);// js html cssconsole.log(instance2.id)//11isntance1.showBooks();//TypeError
由于更改了函数的作用环境,因此在子类中,对 superclass 调用这个方法就是将子类中的变量在父类中执行一遍,由于父类中是给 this 绑定属性的,因此子类自然也就继承了父类的共有属性。
由于继承时没有涉及原型 prototype,所以父类原型的方法不会被继承。要想被子类继承必须放在构造函数中,这样创建出来的每个实例都会单独拥有一份而不能共用,这就违背了代码复用的原则。
3. 组合继承
类式继承是通过子类的原型 prototype 对父类实例化实现的
构造函数式继承是通过在子类的构造函数作用环境中执行一次父类的构造函数来实现的
- //声明父类function SuperClass(name){ //值类型共有属性 this.name=name; //引用类型共有属性 this.books=['html','css','js']; }//父类原型共有方法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.name);};
这样,子类的实例中更改父类继承下来的引用类型属性如 books,根本不会影响其他实例,并且在子类实例化过程中又能将参数传递到父类的构造函数中 name。
- var instance1 = new SubClass('js', 2014);
- instance1.books.push('设计模式');console.log(instance1.books); //html css js 设计模式instance1.getName();//jsisntance1.getTime();//2014var instance2=new SubClass('css',2013);console.log(instance2.books);//html css jsinstance2.getName();//cssinstance2.getTime();//2013
4. 原型式继承
- //原型式继承function inheritObject(o){ //声明一个过渡函数对象 function F(){} //过渡对象的原型继承父对象 F.prototype=o; //返回过渡对象的一个实例,该实例的原型继承了父对象 return new F();}
对类式继承的一个封装,由于 F 过渡类的构造函数中无内容,所以开销较小,使用起来也比较方便。跟类式继承一样,父类对象的 book 中的值类型属性被复制,引用类型的属性被共用
- var book = {
- name: "js book",
- alikeBook: ["css", "html"]
- };
- var newBook = inheritObject(book);
- newBook.name = "ajax";
- newBook.alikeBook.push("xml");
- var otherBook = inheritObject(book);
- otherBook.name = "flash";
- otherBook.alikeBook.push("as book");
- console.log(newBook.name); //ajaxconsole.log(newBook.alikeBook);//css html xmlconsole.log(otherBook.name);//flashconsole.log(otherBook.alikeBook);// css html xml as bookconsole.log(book.name);//js bookconsole.log(book.alikeBook); //css html xml as book
5. 寄生式继承
- //声明基对象var book={ name:"js", alikeBook:["css","html"]};function createBook(obj){ //通过原型继承方式创建新对象 var o=new inheritObject(obj); //拓展新对象 o.getName=function(){ console.log(name); };//返回拓展后的新对象return o;}
寄生式继承是对原型继承的第二次封装,并且在第二次封装的过程中对继承的对象进行了拓展,这样先创建的对象不仅仅有父类的属性和方法而且添加了新的属性和方法。
6. 寄生组合式继承
- function inheritPrototype(subClass, superClass) { //复制一份父类的原型副本保存在变量中 var p=inheritObject(superClass.prototype); //修正因为重写子类原型导致子类的constructor属性被修改 p.constructor=subClass; //设置子类的原型 subClass.prototype=p;}
就爱阅读 www.92to.com 网友整理上传, 为您提供最全的知识大全, 期待您的分享,转载请注明出处。
来源: