js的繼承方法小結(prototype、call、apply)

js的原型繼承 -- prototype數組

先說下什麼是prorotype?bash

  1. js中,俗話說「一切皆對象」。用new 出來的都是函數對象;不然就是普通對象
  2. 函數對象都有prototype(原型對象);而普通對象則只有__proto__(原型指針)
  3. 函數對象的一個特色:能夠實現不一樣類之間的方法繼承
  4. 函數的子類能夠共享父類的方法,而父類不能想用子類的方法
eg: (prototype的繼承)
 
 //建立父類函數對象    
  function Personal(name, age) {
    this.name = name;     //父類的私有屬性
    this.age = age;
    this.house = ['北京', '上海']
  }
  Personal.prototype.run = function() {   //給父類原型動態添加方法
    alert('原型方法:' + this.name + ' is running!');
  }
  var per = new Personal('小白', 24)
  per.run() //打印 --> 原型方法:小白 is running!
  
 //建立子類函數對象
  function Boy() {}
  Boy.prototype = new Personal('小黑', 19) //子類繼承父類的全部屬性和方法
  Boy.prototype.source = 100            //給子類添加原型屬性
  Boy.prototype.printSource = function() {  //給子類添加方法
    alert(this.name + '的原型方法printSouce打印成績爲:' + this.source) //小黑的原型方法printSouce打印成績爲:100
  }
  Boy.prototype.run()   //打印 --> 原型方法:小黑 is running!
  var boys = new Boy()
  boys.printSource()
  console.log(boys, '--boys---') //打印 -->19, 小黑, 100 (這裏會沿着prototype向上查找到Personal的屬性)
複製代碼

如下是關於prototype繼承須要注意的點:微信

  1. 若是父類中有引用類型的屬性:Array,Object等。子類繼承了這些屬性,並嘗試改變的話,會影響到父類的屬性。
//建立另一個實例1:
      var boys1 = new Boy()
      boys1.house.push('深圳')
//打印這兩個實例:
      console.log(boys, boys1)
複製代碼

能夠看出來,當屬性爲引用類型時,只要有一個實例的屬性作了操做,全部的實例都會受到影響。app

  1. 該方式致使 Boy.prototype.constructor 被重寫,它指向的是 Personal 而非 Boy。所以你須要手動將 Boy.prototype.constructor 指回 Boy。
Boy.prototype = new Personal();
Boy.prototype.constructor === Personal; // true

// 重寫 Boy.prototype 中的 constructor 屬性,指向本身的構造函數 Boy
Boy.prototype.constructor = Boy;
複製代碼
  1. 由於 Boy.prototype = new Personal(); 重寫了 Boy 的原型對象,因此 printSource 放在重寫原型對象以前會被覆蓋掉,所以給子類添加原型方法必須在替換原型以後(eg是沒有被覆蓋的)。
function Boy() {}
Boy.prototype = new Personal();

// 給子類添加原型方法必須在替換原型以後
Boy.prototype.printSource = function() {
  console.log('printSource~');
};

複製代碼
  1. 建立 boys 實例時沒法向父類的構造函數傳參,也就是沒法初始化 source屬性。所以:只能建立實例以後再修改父類的屬性。
const boys = new Boy();

// 只能建立實例以後再修改父類的屬性
boys.source = 100;
複製代碼

apply()、call()方法的繼承函數

瞭解下apply()、call()方法this

  1. apply()、call()的用法:
obj.call(thisObj, arg1, arg2, ...);
obj.apply(thisObj, [arg1, arg2, ...]);
複製代碼

obj是父級,thisObj是子級;第二個參數apply能夠接收一個數組,而call只能是每項逐個接收。spa

  1. apply和call 原本就是爲了擴展函數的做用域而生的,換句話說就是爲了改變this的指向存在的。
  2. 當一個object沒有某種方法,可是其餘的有,咱們能夠藉助call和apply來用其餘對象的方法來作操做,也能夠傳參數。
//eg:
function Personal(name, sex) {
      this.name = name;
      this.sex = sex;
      this.say = function (){
        alert('姓名:' + this.name + ';性別:' + this.sex)
      }
    }
    const per = new Personal('Allan', '男')
    per.say();
    
//apply()方法實現:
    function Girls(name, sex) {
      Personal.apply(this, [name, sex]);
      //Person.apply(this,arguments); //跟上句同樣的效果,arguments  
      //Print.apply(this,arguments);  //還能夠實現繼承多個父類,可是原型 prototype只能繼承一個父類!!!切記
    }
    const girls1 = new Girls('Lucy', '女')
    girls1.say();
    
//call()實現:
    function Boy(name, sex) {
      Personal.call(this, name, sex);
    }
    const boys = new Boy('Barry', '男');
    boys.say() //
複製代碼

總結prototype

  1. prototype能夠動態的給對象增長屬性和方法。
  2. 能夠實現子類繼承父類,擁有父類的屬性和方法。
  3. call和apply的區別,在於參數的不一樣。
  4. call和apply,理解爲在子類的運行環境中執行父類的方法和屬性。
  5. call和apply能夠實現一個子類繼承多個父類,可是prototype只能有一個父類。

若是以爲對你有幫助,請給做者一點小小的鼓勵,點個贊或者收藏吧。
(有須要溝通的請聯繫我:微信( wx9456d ) 郵箱( allan_liu986@163.com )
指針

相關文章
相關標籤/搜索