JS继承

JS继承

//构造函数
function Person(name){
	this.name = name;
	this.sayName = function(){
		console.log(this.name)
	}
}
Person.prototype.age = 10

1.原型链继承

function Per(){
  this.name = ‘jack‘
}
Per.prototype = new Person()
var per1 = new Per()
console.log(per1.age,per1.name) //10 jack
//10 per1.age->per1.__proto__ === Per.prototype -> Per.prototype = new Person()->实例new Person()的构造函数是Person -> per1.__proto__ 从 Person.prototype中找age = 10
console.log(per1 instanceof Per,per1 instanceof Person,per1 instanceof Object) //true true true
//instanceof的判断逻辑是per的__proto__一层一层往上找
var per2 = new Per()
per2.__proto__.__proto__.age = 20
console.log(per1.age) //20

让新实例的原型等于父类的实例。
缺点:1、新实例无法向父类构造函数传参。2、继承单一。3、所有新实例都会共享父类实例的属性。(原型上的属性是共享的,一个实例修改了原型属性,另一个实例的原型属性也会被修改!)

2.借用构造函数继承

function Con(name){
  Person.call(this,name)
}
let con1 = new Con(‘jack‘)
console.log(con1.name,con1.age) // jack undefined
console.log(con1 instanceof Con,con1 instanceof Person)//true false

用.call()和.apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制))
缺点:1、只继承了父类构造函数的属性,没有继承父类原型的属性。2、无法实现构造函数的复用。3、每个新实例都有父类构造函数的副本,臃肿。
call(),apply(),bind()()用法

Fun().call(this,‘param1‘,‘param2‘)
Fun().apply(this,[‘param1‘,‘param2‘])
Fun().bind(this,‘param1‘,‘param2‘)()
//相同点第一个参数都是this的指向对象(一个是函数运行的作用域),上面继承:是把Person()中的this指向Con()中的this所在的作用域;后面是参数入参方式允许是各种类型,包括函数 、 object 等等

3.组合继承

function Con(name){
  Person.call(this,name)
}
Con.prototype = new Person()//替换Con的prototype为Person的实例
let con1 = new Con(‘Jack‘)
console.log(con1.name, con1.age)//Jack 10
console.log(con1 instanceof Con, con1 instanceof Person)//true true
//con1.age->con1.__proto__(Con.prototype中找)->Con.prototype = new Person(),Person实例中没有->去Person实例的__proto__找(Person.prototype中找)->10

结合了两种模式的优点,传参和复用
缺点:调用了两次父类构造函数(一次引用Person,一次引用Person实例),Con.prototype被替换

4.原型式继承

function content(obj){
  function F(){}
  F.prototype = obj
  return new F()
}
let per = new Person(‘jack‘),
con1 = content(per)
console.log(con1.name,con1.age,con1) //jack 10
console.log(con1 instanceof Person) //true
//函数content返回一个函数F的实例,函数F原型链继承Person

用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了个可以随意增添属性的实例或对象。object.create()就是这个原理。
缺点:1、所有实例都会继承原型上的属性。2、无法实现复用。(新实例属性都是后面添加的)3、无法向父类构造函数传参

5.寄生式继承

function content(obj) {
  function F() {}
  F.prototype = obj
  return new F()
}
let per = new Person()

function subobject(obj) {
  let sub = content(obj)
  sub.name = ‘jack‘
  return sub
}
let con1 = subobject(per)
console.log(con1.name, con1.age, con1) //jack 10
console.log(con1 instanceof Person) //true

给原型式继承外面套了个壳子
缺点:没用到原型,无法复用。

6.寄生组合式继承(常用)

function content(obj) {
  function F() {}
  F.prototype = obj
  return new F()
}
let per = content(Person.prototype) //F的实例继承了Person的原型

function Con(name) {
  Person.call(this,name)
}
Con.prototype = per //Con的原型为F的实例
per.constructor = Con //per的constructor指向构造函数F(),改为指向Con()
let con1 = new Con(‘jack‘)
console.log(con1.name, con1.age, con1) //jack 10
console.log(con1 instanceof Person) //true

修复组合继承的问题

7.ES6 Class 继承

class Person { // 定义了一个名字为Person的类
  constructor(x, y) { // constructor是一个构造方法,用来接收参数
    this.x = x;
    this.y = y;
    this.z = 1;
    this.a = 3;
  }
  toString() {
    return "toString";
  }
  static staticFun() {
    return "static";
  }
}

class Son extends Person {
  constructor(x, y, color) {
    super(x, y); //子类必须在 constructor 方法中调用 super 方法,否则新建实例时会报错。
    this.z = 2;
    this.a = 4;
    super.a = 5;
    this.color = color;
    console.log(super.a) //undefined
    console.log(this.a); // 5
  }
  // toString() { // 这是一个类的方法,注意前面没有function
  //   return this.color + ‘ ‘ + super.toString(); // 调用父类的toString()
  // }
}
let son1 = new Son(1, 1, "red");
console.log(son1.toString(),Son.staticFun())//toString,static
console.log(son1 instanceof Son, son1 instanceof Person) //true true

参考:(侵立删)
1、js继承的6种方式
2、js 总结ES6中Class以及继承

JS继承

上一篇:解决linux下 使用netcore生成图片报错的问题:The type initializer for 'Gdip' threw an exception


下一篇:css言行布局小记