new,call,apply,bind方法的實現原理

javascript中new,call,apply,bind等方法是咱們常常要使用到,在僞數組轉數組、函數傳參、繼承等場景中,都離不開他們。這裏就不具體討論他們的使用方法,咱們將研究他們的實現方式,重寫屬於咱們本身的方法,讓你們從新認識他們的實現過程,使咱們在開發中知其然,知其因此然!javascript

new的實現

咱們用new實例化一個構造函數,生成一個實例對象,而new到底作了什麼呢,主要分爲如下五步:java

  • 1: 獲取構造函數
  • 2:建立一個新對象;
  • 3:將函數的做用域賦給新對象(這裏實際上就是生產了一個新的上下文)
  • 4:執行函數中的代碼(爲新對象添加屬性、方法)
  • 5:返回值,無返回值或者返回一個非對象值時,則將建立的新對象返回,不然會將返回值做爲新對象返回。(也就是說必定會返回一個對象回來,這一步能夠從下面的代碼得結論)
function MyNew() {
      let Constructor = Array.prototype.shift.call(arguments); // 1:取出構造函數

      let obj = {} // 2:執行會建立一個新對象

      obj.__proto__ = Constructor.prototype // 3:該對象的原型等於構造函數prototype

      var result = Constructor.apply(obj, arguments) // 4: 執行函數中的代碼

      return typeof result === 'object' ? result : obj // 5: 返回的值必須爲對象
    }
  • MyNew方法校驗
function Man(name, age) {
      this.name = name
      this.age = age
    }
    var tom = new Man('tom', 20)
    var mike = MyNew(Man, 'mike', 30)
    console.log(tom  instanceof Man, mike instanceof Man) // true true

call的實現

call方法的實現主要有如下三步,好比 fn.call(obj, a, b) 數組

  • 1: 把調用函數fn的上下文指向obj
  • 2: 形參a,b等是以逗號分隔傳進去
  • 3: 執行函數fn,並返回結果
Function.prototype.myCall = function (context) {
      context = context ? Object(context) : window 
      context.fn = this // 重置上下文
      let args = [...arguments].slice(1) // 截取參數a,b
      let r = context.fn(...args) // 執行函數
      delete context.fn // 刪除屬性,避免污染
      return r // 返回結果
    }
  • myCall方法校驗
// 瀏覽器環境下
    var a = 1, b = 2;
    var obj ={a: 10,  b: 20}
    function test(key1, key2){
      console.log(this[key1] + this[key2]) 
    }
    test('a', 'b') // 3
    test.myCall(obj, 'a', 'b') // 30

apply的實現

apply方法和call方法大同小異,惟一差異就是,apply傳入的參數是數組格式。瀏覽器

// apply 原理
    Function.prototype.myApply = function (context) {
      context = context ? Object(context) : window
      context.fn = this
      let args = [...arguments][1]
      if (!args) {
        return context.fn()
      }
      let r = context.fn(...args)
      delete context.fn;
      return r
    }
  • apply方法校驗
// 瀏覽器環境下
    var a = 1, b = 2;
    var obj ={a: 10,  b: 20}
    function test(key1, key2){
      console.log(this[key1] + this[key2]) 
    }
    test('a', 'b') // 3
    test.myCall(obj, ['a', 'b']) // 30  注意這裏是傳入數組 ['a', 'b']

bind方法實現

bind方法和call、apply方法的差異是,他們都改變了上下文,可是bind沒有當即執行函數。app

// bind 原理
    Function.prototype.Mybind = function (context) {
      let _me = this
      return function () {
        return _me.apply(context)
      }
    }
  • bind方法校驗
var a = 1, b = 2;
    var obj ={a: 10,  b: 20}
    function test(key1, key2){
      console.log(this[key1] + this[key2]) 
    }
    var fn = test.bind(obj)
    fn('a', 'b') // 30

好了,介紹完了,若是以爲對你有幫助,點個贊哈,嘿嘿!函數

參考文章來源:

相關文章
相關標籤/搜索