JS继承理解

1、原型链继承:

共享父类(实例)属性方法


继承.jpg
function Child(){
    this.subproperty=false
}
function Person(name){
    this.property=true
    this.name=name
    this.child=[1,2,3,4]
}
Child.prototype=new Person("ming")//关键点
var x=new Child()
x.child.push(5)
console.log(x.child)//[1,2,3,4,5]
var y=new Child()
console.log(y.child)//[1,2,3,4,5]

关键代码:
Child.prototype=new Person("ming")//关键点
//执行Person构造函数,Person实例获得property,name,child属性,Child.prototype指向Person实例
Child:{
    prototype:Person{//Person实例也是Child的原型
                [[prototype]]:Person.prototype{//Person原型
                                  constructor:Person
                                           }
                 name:"ming",
                 property:true,
                 child:[1,2,3,4]
                    }
      }

var x=new Child()
x.t="huan"
//new关键字 x. [[prototype]]=Child.prototype,导致继承Person,执行Child构造函数,添加自身属性subproperty
x:{
    [[prototype]]:Person{
                    [[prototype]]:Person.prototype{
                                       constructor:Person
                                            },
                    name:"ming",//共享属性
                    property:true,//共享属性
                    child:[1,2,3,4]//共享属性
                         },
    t:"huan",
    subproperty:false
}

x.child.push(5)
//x实例访问并修改引用属性,原型搜索链:(1)x实例(无child属性)(2)Child.prototype(Person实例有Child属性,更改,实际也是在更改Person实例属性)停止搜索

var y=new Child()
//new关键字 y. [[prototype]]=Child.prototype,导致继承Person,执行Child构造函数,添加自身属性subproperty
y:{
    [[prototype]]:Person{
                    [[prototype]]:Person.prototype{
                                       constructor:Person
                                            },
                    name:"ming",//共享属性
                    property:true,//共享属性
                    child:[1,2,3,4,5]//共享属性
                         },
    subproperty:false
}

原型链继承:
优点:能够共享父类属性和方法,避免每个实例重新定义方法属性占内存
缺点:(1)共享属性如果是引用类型,容易被实例修改
(2)子类在创建实例时,不能动态的向父类构造函数传参,上述父类name值,在第一次使用Child.prototype=new Person("ming")时name值就固定了

2、借用构造函数继承:

(不使用Child.prototype=new Person("ming"),使用call为每个实力作用域复制其私有属性,非共享)

function Person(name){
    this.property=true
    this.name=name
    this.child=[1,2,3,4]
}
function Child(name){
   Person.call(this,name) 
}
var x=new Child()
x.t="huan"
x.child.push(5)
console.log(x.Child)//[1,2,3,4,5]
var y=new Child()
console.log(y.Child)//[1,2,3,4]

Person.call(this,name)
 //创建实例时执行代码,this指向实例对象,因此,这里的this其实是切换到Child实例作用域调用执行Person代码;
//call调用函数是在独立的特定作用域下执行的,每个实例调用后属性值互不干扰
因此,x.child.push(5)其实只作用于x作用域内

优点:能动态传值给父类构造函数,解决原型链的共享引用问题
缺点:相同的方法,不能共享,需要每个实例都声明解析,占内存

3、组合继承:

(原型链+借用构造函数):原型链定义公用方法和属性,借用构造函数定义实例独立方法和属性
个人理解:是因为每个实例在执行Person.call(this,name) 后屏蔽了Person实例中的相同属性,当实例中有了与原型同名的属性后,原型中的属性将会被屏蔽

function Person(name){
    this.property=true
    this.name=name
    this.child=[1,2,3,4]
}
function Child(name){
    Person.call(this,name)  
}
Person.prototype.class=2
Person.prototype.getName=function(){
    return this.name
}
Child.prototype=new Person()
var x=new Child("ming")
x.child.push(5)
console.log(x.child)//[1,2,3,4,5]
console.log(x.getName())//ming
var y=new Child("huan")
console.log(y.child)//[1,2,3,4]
解析:
Child.prototype=new Person()
Child:{
    prototype:Person{//Person实例也是Child的原型
                [[prototype]]:Person.prototype{//Person原型
                                  constructor:Person
                                           },
                 name:undefined,
                 property:true,
                 child:[1,2,3,4]
                    }
      }

var x=new Child("ming")
//执行Child构造函数->执行Person.call()获得实例属性
x:{
    [[prototype]]:Person{
                    [[prototype]]:Person.prototype{
                                       constructor:Person
                                            },
                    name:undefined,//共享属性
                    property:true,//共享属性
                    child:[1,2,3,4]//共享属性
                         },
    name:"ming",//实例属性
    property:true,//实例属性
    child:[1,2,3,4]//实例属性
}

x.child.push(5)
//实例属性child变化,因为通过原型搜索链在实例中搜索到chid属性,搜索停止
x:{
    [[prototype]]:Person{
                    [[prototype]]:Person.prototype{
                                       constructor:Person
                                            },
                    name:undefined,//共享属性
                    property:true,//共享属性
                    child:[1,2,3,4]//共享属性
                         },
    name:"ming",//实例属性
    property:true,//实例属性
    child:[1,2,3,4,5]//实例属性
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 什么是继承 js中的继承就是获取存在对象已有属性和方法的一种方式. 继承一 属性拷贝 就是将对象的成员复制一份给需...
    LiYajie阅读 10,670评论 1 7
  • 对象继承 什么是继承 继承可以使得子类具有父类的属性和方法或者重新定义、追加属性和方法 实现继承就需要完成两件事 ...
    槑小姐_1419阅读 3,514评论 0 0
  • 1.原型链继承  原型链继承所带来的问题:   ① 引用类型的属性被所有实例共享。  ② 在创建 Child 的实...
    Knight52033阅读 2,642评论 0 1
  • 其实要总结这几个概念已经很久了,只是之前一直都觉得自己还不算完全掌握,而且知识点还不够系统,所以一直拖着,但是最近...
    Katherine的小世界阅读 4,191评论 0 5
  • 前言 此篇文章的目的是让你搞懂这些继承到底是为什么?他们的优缺点的原理到底是什么?看了很多文章说的太抽象,怎么可能...
    沐雨芝录阅读 4,729评论 0 5

友情链接更多精彩内容