1. 程式人生 > 資訊 >時刻乾爽無懼汗,駱駝速幹短袖 T 恤/短褲 39 元、2 件 68 元

時刻乾爽無懼汗,駱駝速幹短袖 T 恤/短褲 39 元、2 件 68 元

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以及繼承