Js中一道call函數的面試題

一道call()函數的面試題

call()函數能改變this指針的指向,能方便的爲對象擴展方法,在實際項目中屬於重度應用的方法。

下面來看題目:

    function fn1() {console.log(1);}
    function fn2() {console.log(2);}
    
    fn1.call(fn2);  
    fn1.call.call(fn2); 
    fn1.call.call.call.call(fn2); 
    fn2.call();
    
    Function.prototype.call(fn2); 
    Function.prototype.call.call.call(fn2); 
    Function.prototype.call.call.call(fn1); 
    //Array.prototype.call([1,2,3]); // 所以這樣調用會報 TypeError 錯誤,Array.prototype.call is not a function
  • fn1.call(fn2);
    這樣的調用方式大家應該比較熟悉。call()函數的第一個參數應該是對象,fn2是函數,在Js中函數的本質也是對象;所以就是在fn2對象上調用fn1方法(注意fn2上本來是沒有fn1這個方法的,調用call時會給fn2臨時添加一個屬性,它的值就是fn1方法的地址),等同的效果就是直接執行fn1();

  • fn2.call();

  1. call()可以不傳參,這時候默認的就是全局Global對象,web環境中全局Global對象就是window。這裏假定是web環境,所以相當於fn1.call(window);
  2. fn1.call(window);這個比較簡單啦,這就是call的普通用法,等價於window.fn1();,實際上就是調用fn1()函數。
  • Function.prototype.call(fn2);
    首先,Function的原型比較特殊,它的原型是匿名空函數,別的類型的原型對象都是對象。
    所以這行代碼表示在fn2上調用匿名空函數,所以就不會輸出內容。

  • Function.prototype.call.call.call(fn2);,實際上和 fn1.call.call(fn2) 類似

  1. 可以拆分一下,這樣容易說明問題 (Function.prototype.call.call).call(fn2);, 我們把Function.prototype.call.call給擴了起來。
  2. 來看Function.prototype.call.call,可以理解爲Function.prototype.call的call方法;Function.prototype.call本身也是一個函數,如果不重寫實際上所有函數的call方法都是 Function原型中的call方法, 即 Function.prototype.call
    也可以說Function.prototype.callFunction.prototype.call.callFunction.prototype.call.call.call...都是等價的,即Function原型上的call方法。
  3. 這樣 (Function.prototype.call.call).call(fn2); 就相當於在fn2對象(js中函數也是對象)上調用原型中的call方法,且沒有傳遞參數;實際上就是fn2.call();
    4)fn2.call(); 我們觀察下call函數中沒傳值,默認就是window對象,fn2.call(window);又等價於 window.fn2();

模擬call()函數實現

call()的內部原理是怎樣的?我們來模擬一下call函數:

    function call(context = window, ...args) {
      // this -> 指向調用call的那個函數(記住call前面必須是函數在調用)
      // 實際上就是執行 this(...args);
      // 是哪個對象要執行這個this函數?答案是context
      // 所以先把這個函數賦值給context的一個屬性
      // 然後調用context這個新屬性,接收傳入的參數
      context.$fn = this;
      // 模擬call要處理的問題
      let res = context.$fn(...args);
      delete context.$fn; // 移除我們私自添加的函數 $fn
      return res;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章