zoukankan      html  css  js  c++  java
  • javascript对象继承

    实现继承主要是依靠原型链来实现的

    1、原型链

    基本思想就是利用原型让一个引用类型继承另一个引用类型的属性和方法
     1 function Parent(){
     2     this.surname = "li";
     3 }
     4 Parent.prototype.getSurname = function(){
     5     return this.surname;
     6 }
     7 function Child(){
     8     this.name = "kai wen";
     9 }
    10 Child.prototype = new Parent();
    11 Child.prototype.getName = function(){//继承之后再添加
    12     return this.name;
    13 }
    14 var child = new Child();
    15 alert(child.getSurname())
    16 alert(child.getName())
    分别定义了Partent和Child两个类型,Child继承了Partent,继承是通过创建Partent实例并将其赋给Child.prototype实现的,实现的本质是重写原型对象,随后又给原型添加的新的方法,若这里先添加新的方法,再继承Partent,由于原型被重写,添加的方法就无效
     1 function Parent(){
     2     this.surname = "li";
     3 }
     4 Parent.prototype.getSurname = function(){
     5     return this.surname;
     6 }
     7 function Child(){
     8     this.name = "kai wen";
     9 }
    10 
    11 Child.prototype = new Parent();
    12 
    13 Child.prototype = {
    14     getName:function(){
    15         return this.name;
    16     }
    17 }
    18 var child = new Child();
    19 alert(child.getSurname())//系统报错, Uncaught TypeError: child.getSurname is not a function
    通过原型链实现继承时,不能使用对象字面量方法创建原型,这样做会重写原型链,Partent的实例赋值给Child原型,紧接着又将原型替换成对象字面量,导致现在的Child原型是一个Object实例,而非Partent实例,因此Partent与Child之间已经没有关系
    原型链虽然很强大,但是也存在问题:
    1、包含引用类型值得原型会被所有实例共享,通过原型来实现继承时,原型实际上变成另一个类型的实例,于是实例属性也就变成了原型属性
    2、在创建子类型实例时,不能向超类型的构造函数中传递参数

    2、借用构造函数

    基本思想是在子类型构造函数的内部调用超类型构造函数
     1 function Parent(){
     2     this.color = ["red","blur"];
     3 }
     4 function Child(){
     5     Parent.call(this)
     6 }
     7 var child1 = new Child();
     8 child1.color.push("black");
     9 alert(child1.color)
    10 var child2 = new Child();
    11 alert(child2.color)
    这样每个新创建的Child实例都会有自己的color属性副本
    该方法还可以在子类型构造函数中向超类型构造函数传递参数
     1 function Parent(surname){
     2     this.surname = surname;
     3 }
     4 function Child(){
     5     Parent.call(this,"Li")
     6     this.name = "kai wen";
     7 }
     8 var child = new Child();
     9 alert(child.surname)
    10 alert(child.name)

     但是借用构造函数方法,也存在缺点,方法都在构造函数中定义,函数复用性无从谈起,而且在超类中定义的方法,对于子类而言是不可见的

    3、组合继承

    将原型链与借用构造函数组合到一块,基本思想是使用原型链实现对原型属性和方法的继承,而通过借用构造函数实现对实例属性的继承
     1 function Parent(surname){
     2     this.surname = surname;
     3     this.color = ["red","blue"]
     4 }
     5 Parent.prototype.saySurname = function(){
     6     alert(this.surname)
     7 }
     8 function Child(surname,name){
     9     //继承属性
    10     Parent.call(this,surname)
    11     this.name = name;
    12 }
    13 //继承方法
    14 Child.prototype = new Parent();
    15 Child.prototype.constructor = Child;
    16 Child.prototype.sayName = function(){
    17     alert(this.name);
    18 }
    19 
    20 var child1 = new Child("li","Kai wen");
    21 child1.color.push("black");
    22 alert(child1.color)
    23 child1.saySurname()
    24 child1.sayName()
    25 var child2 = new Child("wang","fangfang");
    26 alert(child2.color)
    27 child2.saySurname()
    28 child2.sayName() 

    4、原型式继承

    基本思想是借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型
     
     1 function object(o){
     2     function F(){}
     3     F.prototype = o;
     4     return new F()
     5 }
     6 var Parent = {
     7     surname: "li",
     8     color: ["red","blue"]
     9 }
    10 var child1 = object(Parent);
    11 child1.color.push("black");
    12 var child2 = object(Parent);
    13 child2.surname = "wang";
    14 child2.color.push("yellow");
    15 alert(child1.surname)
    16 alert(child1.color)
    17 alert(child2.surname)
    18 alert(child2.color)

     原型式继承要求必须有一个对象可以作为另一个对象的基础,包含引用类型值得属性始终都会共享相应的值 

    5、寄生式继承

    创建一个仅用于封装继承过程的函数
     1 function object(o){
     2     function F(){}
     3     F.prototype = o;
     4     return new F()
     5 }
     6 function createAnother(p){
     7     var clone = object(p);
     8     clone.sayHi = function(){
     9         alert("hi");
    10     }
    11     return clone;
    12 }
    13 var Parent = {
    14     surname: "li",
    15     color: ["red","blue"]
    16 }
    17 var child = createAnother(Parent);
    18 child.sayHi()

     缺点是做不到函数复用而降低效率

    6、寄生组合式继承

    通过借用构造函数来继承属性,通过原型链的混成形式来继承方法,基本思路是不必为了指定子类型的原型而调用超类型的构造函数,只需要超类型原型的副本而已,本质上就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型
     1 function object(o){
     2     function F(){}
     3     F.prototype = o;
     4     return new F()
     5 }
     6 function inheritPrototype(child,parent){
     7     //创建超类型原型的副本
     8     var prototype = object(parent.prototype);
     9     prototype.constructor = child;
    10     child.prototype = prototype;
    11 }
    12 var Parent = {
    13     surname: "li",
    14     color: ["red","blue"]
    15 }
    16 Parent.prototype.saySurname = function(){
    17     alert(this.surname)
    18 }
    19 function Child(surname,name){
    20     Parent.call(this,surname);
    21     this.name = name;
    22 }
    23 inheritPrototype(Child,Parent);
    24 Child.prototype.sayName = function(){
    25     alert(this.name)
    26 }

     只调用了一次Parent构造函数,避免了在Child.prototype上创建不必要的多余的属性,同时原型链不变

  • 相关阅读:
    tree-cli 自动生成项目目录结构
    按需导入vant-ui
    全局导入vant-ui
    mook使用流程
    axios使用流程
    Vuex使用流程
    vue-router使用流程
    img的complete和onload
    react-redux 如何在子组件里访问store对象
    ES6中的Export/import操作的是引用
  • 原文地址:https://www.cnblogs.com/lhyhappy365/p/5853240.html
Copyright © 2011-2022 走看看