JavaScript继承和原型链的复习

JavaScript的原型和继承

原型

先看一段代码

function User(name) {
  this.name = name
}
let no= new User('不忘')

console.log(no);//User {name: "不忘"}
console.dir(User);//ƒ User(name)
console.dir(Function);//ƒ Function()   //function的构造函数
console.dir(Object);//ƒ Object()		//object的构造函数
复制代码

当你打开上面的输出时,你能看到一个prototype,或者__proto__属性,这就是他们的原型,打开原型你们会看到一个constructor属性,这个是该对象的构造函数,父级的属性靠这个传给子级,让子级有父级的属性,父级和子集的关系

子级._prop_===父级.prototype

子级._prop_.constructor===父级

由于父级也可能是别人的子级,所以

孙级._prop_._proto_===爷级.prototype

爷爷自然也可以有曾爷爷,原型链就是靠__prop__一直延续到最后

按照上述的条件,我把上面函数的四个输出画了一份关系图

1619067462046.png
没错JavaScript的家族关系就是如此错乱,要是有兴趣自己研究一下,

比如:

Function自己生了自己,所以Function._proto_===Function.prototypt

no的父级是user,user的父级是Function,但no的的爷爷是Object

Function的爷爷是Object,但Object的爸爸是Function等等

说实话知道他们家族的关系感觉没什么太大作用,关键要知道该对象和他的原型之间的关系,还有子级能靠这样可以直接调用父级的属性,JavaScript的继承就是利用了这个方法,让子级继承父级的属性。

function User(name) {
  this.name = name
  this.getName=function(){
    console.log(this.name);
  }
}
let no= new User('不忘')
no.getName()//不忘
//在父级User的prototype中添加的方法,子级no也可以调用
复制代码

有关原型属性的方法

create设置_proto_

let no={name:'不忘'}
let yes=Object.create(no,{
  name:{
    value:'回忆'
  }
})
console.log(yes);//{name: "回忆"}
//此时yes的__proto__为no,此方法不可查询


let ok={name:'好的'}
ok.__proto__ = no

console.log(ok);//{name: "好的"}
//此时yes的__proto__为no,可查询
复制代码

setPrototypeOf设置_proto_

let no={name:'不忘'}
let yes={name:'回忆'}
Object.setPrototypeOf(yes,no)
console.log(yes);//{name: "回忆"}    
//此时yes的__proto__为no,官方升级版

//__proto__是一个访问器,只能改成对象
复制代码

isPrototype判断是否在对方的__proto__上

let no={name:'不忘'}
let yes={name:'回忆'}
Object.setPrototypeOf(yes,no)
console.log(no.isPrototypeOf(yes));//true
//no在yes的__proto__上,返回true
复制代码

instanceof构造函数的prototype是否是该原型链上

function User(name) {
  this.name = name
}
let no= new User('不忘')
console.log(no instanceof User);//true
//当no的原型链上有User的prototype返回true
复制代码

hasOwnPrototype不会判断原型链上面的值是否存在

let no={Nname:'不忘'}
let yes={name:'回忆'}
Object.setPrototypeOf(yes,no)

console.log('Nname' in no);//true
console.log(yes.hasOwnProperty('Nname'));//false
//hasOwerProperty不会查询到原型链上
复制代码

可以用call和apply调用别的原型上的方法

function User(name) {
  this.name = name
}
User.prototype.getName=function(){
  console.log(this.name);
}
let no= new User('不忘')

let yes={name:'回忆'}

no.getName.call(yes)//回忆
复制代码

继承

我之前提到原型链是用来实现继承的,继承的重点在子级.prototype,给子级的prototype的值

基础

function User(name) {
  this.name = name
}
function Name() {}
Name.prototype.getName = function() {//给Name的prototype增加方法
  console.log(this.name);
}

User.prototype.__proto__=Name.prototype;//User继承Name的prototype
// User.prototype=Object.create(Name.prototype)//第二种写法,要写在在new之前,不然没有效果
let no=new User('不忘');
no.getName()//不忘  //由于继承了Name的prototype,所以可以调用getName方法
复制代码

加上construct

function User(name) {
  this.name = name
}
function Name() {}
Name.prototype.getName = function() {
  console.log(this.name);
}

User.prototype=Object.create(Name.prototype)
User.prototype.constructor = Name;//将构造函数指过去
Object.defineProperty(User.prototype,'constructor',{
  value:Name,
  enumerable:false
})//静止遍历
let no=new User('不忘');
no.getName()//不忘 

//这样就将Name变成了User的父级
复制代码

子级的方法和用父级的方法互相调用

function User(name) {
  this.name = name
}

function Name() {}
Name.prototype.getName = function() {
  return this.name
}
User.prototype=Object.create(Name.prototype)
User.prototype.show =function () {//这次添加要写在create后面
  console.log(this.getName()+'女朋友是冰冰');
}
User.prototype.constructor = Name;//将构造函数指过去
Object.defineProperty(User.prototype,'constructor',{
  value:Name,
  enumerable:false
})//静止遍历
let no=new User('不忘');
no.show()//不忘女朋友是冰冰
复制代码

父级初始属性

function User(name,age) {
  this.name = name
  this.age=age
}

Girl.prototype=Object.create(User.prototype)

function Girl(name,age) {
  User.call(this,name,age)//这里用call调用一下
}
User.prototype.show=function(){
  console.log(this.name+"今年"+this.age+'岁了');
}

let yes=new Girl('冰冰','18')

yes.show()//冰冰今年18岁了
复制代码

继承方法封装

 function extend(son,father) {//son为子级,father为父级
   son.prototype=Object.create(father.prototype);//设置prototy
   Object.defineProperty(son.prototype, 'constructor',{//设置constructor
     value: father,
     enumerable:false,
   })
 }


function User(name,age) {
  this.name = name
  this.age=age
}

extend(Girl,User)

function Girl(name,age) {
  User.call(this,name,age)
}
User.prototype.show=function(){
  console.log(this.name+"今年"+this.age+'岁了');
}

let yes=new Girl('冰冰','18')

yes.show()//冰冰今年18岁了
复制代码

对象工厂继承

function User(name,age) {
  this.name = name
  this.age=age
}


function girl(name,age) {
  const gproto=Object.create(User.prototype)//创建一个对象继承prototype
  User.call(gproto,name,age)
  return gproto
}
User.prototype.show=function(){
  console.log(this.name+"今年"+this.age+'岁了');
}

let yes=girl('冰冰','18')

yes.show()
复制代码

多继承

function extend(son,father) {
   son.prototype=Object.create(father.prototype);
   Object.defineProperty(son.prototype, 'constructor',{
     value: father,
     enumerable:false,
   })
 }

function Boy(name,age) {
  this.name = name;
  this.age = age;
}

function Sound() {}
Sound.prototype.a=function(){
  console.log(this.name+'会伪音');
}
function Mackeup() {}
Mackeup.prototype.b=function(){
  console.log(this.name+'会化妆');
}
function Wear() {}
Wear.prototype.c=function(){
  console.log(this.name+'会女装');
}

extend(Mackeup,Wear)
extend(Sound,Mackeup)
extend(Boy,Sound)
let yes=new Boy('冰冰','18')
yes.a()//冰冰会伪音
yes.b()//冰冰会化妆
yes.c()//冰冰会女装

//当需要继承不同的父级时,由于只能有一个爸爸,那就变成爷爷,曾爷爷,这样一直链接下去会导致链接太长
复制代码

mixin升级版

function Boy(name,age) {
  this.name = name;
  this.age = age;
}

Sound={
  a:function(){
    console.log(this.name+'会伪音');
  }
 }
Mackeup={
  b:function(){
    console.log(this.name+'会化妆');
  }
 }
Wear={
  c:function(){
    console.log(this.name+'会女装');
  }
}
Boy.prototype=Object.assign(Boy.prototype,Sound,Mackeup,Wear);

let yes=new Boy('冰冰','18')
yes.a()//冰冰会伪音
yes.b()//冰冰会化妆
yes.c()//冰冰会女装
//这样就不需要一直延长原型链了
复制代码

mixin可以内部继承和super关键字

function Boy(name,age) {
  this.name = name;
  this.age = age;
}

let Run={
  go:function(){
    return '跑的很快'
  }

 }

 let Mackeup={
  __proto__:Run,
  make(){//这里方法要这么写才可以用super
    // console.log(this.__proto__.go()+'去化妆');
    console.log(super.go()+'去化妆');
  }
 }

Boy.prototype=Object.assign(Boy.prototype,Mackeup,Run);

let yes=new Boy('冰冰','18')
yes.make()
复制代码

class

继承的语法糖

class User {
  constructor(name){
    this.name = name;
  }
  girlfriend(){
    console.log(this.name+'有很多女朋友');
  }
}

let no=new User('不忘');
no.girlfriend()//不忘有很多女朋友

//class的继承用法,创建对象在严格模式下进行,不可遍历
复制代码

静态属性

class User {
  static from='中国'
  where(){
    console.log(User.from);
  }
}

let no=new User();
let yes=new User();
no.where()//中国
yes.where()//中国
//公用的数据就是静态属性
复制代码

静态方法

class User {
  static show(){
    console.log('直接调用的方法');
  }
}

User.show()//直接调用的方法
//不用实例化对象,直接调用
复制代码

class的访问器

class User {
  constructor(name,age){
    this.name = name;
    this.age = age;
  }
  set age(nub){
    if(nub<=18){
      throw new Error("未成年不能进入")
    }
  }

  get age(){
    return this.age
  }
}

let no=new User('不忘',18)//Uncaught Error: 未成年不能进入   //和对象一样
复制代码

class继承

class Change {
  constructor(age){
   this.age=age;
  }
  code(){
    console.log(this.name+'代码越敲越强');
  }
  see(){
    console.log(this.age);
  }
}

class User extends Change{
  constructor(name,age){
    super(age)
    this.name = name;
  }
}
let no=new User('不忘',18)
no.code()//不忘代码越敲越强
no.see()//18
复制代码

私有属性

class Change {
  #characteristics="屁股上有胎记"
  constructor(age){
   this.age=age;
  }
  #code(){
    console.log(this.name+'代码越敲越强');
  }
  see(){
    console.log(this.age);
  }
}

class User extends Change{
  constructor(name,age){
    super(age)
    this.name = name;
  }
}
let no=new User('不忘',18)
// no.#code()//Uncaught SyntaxError: Private field '#code' must be declared in an enclosing class
console.log(no.#characteristics);//Uncaught SyntaxError: Private field '#characteristics' must be declared in an enclosing class
            
 //外面无法访问该属性,和该方法,方法也不能继承
复制代码

多继承

class Boy{
  constructor(name,age){
    this.name = name;
    this.age = age;
  }
  
}

Sound={
  a:function(){
    console.log(this.name+'会伪音');
  }
 }
Mackeup={
  b:function(){
    console.log(this.name+'会化妆');
  }
 }
Wear={
  c:function(){
    console.log(this.name+'会女装');
  }
}
Boy.prototype=Object.assign(Boy.prototype,Sound,Mackeup,Wear);

let yes=new Boy('冰冰','18')
yes.a()//冰冰会伪音
yes.b()//冰冰会化妆
yes.c()//冰冰会女装
//和构造函数一样
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享