今天在學習js的時候想到個有趣的問題, 本身實現一個call方法🤔. 改變一個函數的this指向這種事聽起來真的很原生態. 第一步: 知己知彼,先從這個方法自己下手, 看看他到底有什麼神通. // 1:定義個舉例函數; function fn1(n){ console.log('我是fn1',n,this) } function fn2(n){ console.log('我是fn2',n,this) } let call = fn1.call // 2: 打印一下 他的call方法 // 既然是function, 自己也就確定也有call方法了,繼續 console.log(call) // ƒ call() { [native code] } console.log(call.call) // ƒ call() { [native code] } console.log(call.call.call) // ƒ call() { [native code] } // 3: 實際試試輸出 fn1.call.call(fn2,1) // 我是fn2 undefined Number {1} fn1.call.call.call(fn2,1) // 我是fn2 undefined Number {1} fn1.call.call.call.call(fn2,1) // 我是fn2 undefined Number {1} // 4: 看到這個結果的時候我蒙了, 這怎麼執行fn2了, n是未定義, this指向了1 // 感受總體日後移了一位, 😳呆滯. 第二步: 查資料,逐步實現. 真的很好奇,難道里面有什麼判斷規則?, 我找了幾篇文章, 也沒找到答案, 最後在曾經看過的視頻裏面找到了答案. // 1: 固然是定義在函數上了 Function.prototype.myCall = function(context) { // 2: 若是傳進來的第一個參數爲空,就把它當作window, 因此咱們平時想要指向window的時候纔會穿個undefined,''之類的, Object()一下這個數, 是爲了讓他自己能夠有對象的特性. context = context ? Object(context) : window; // 3: 這個this就是調用當前call方法的'.'前面的對象 // 至關於模擬了一個對象 // context === fn2 === { fn:fn1 } // 因此裏面的fn1的this指向也就是父級fn2了. context.fn = this; // 4: 參數要處理一下, 以便傳入到函數裏面. let as = []; // 要從1開始, 由於第一個要做爲this for (let i = 1; i < arguments.length; i++) { as.push(arguments[i]); } // 5: 執行context的fn方法, 也就是執行, 調用call的函數 // 數組的加法, 好比 [1,2,3]+'' 結果是 1,2,3 這樣就符合參數的樣子了 let r = eval('context.fn(' + as + ')'); // 6: 作完這些, 固然要好好善後啦 delete context.fn; return r }; // 實驗結果 fn1.call(fn2,1) // 我是fn1 1 fn2 第三步: 讓咱們來理解一下那個屢次調用的問題. 首先 :無論寫幾個call 都是call方法自己去調了一下call(fn2), 執行的時候,也就是至關於, 把call它的this指向變成 fn2, 並執行call這個方法, 而call這個方法一執行就會默再去認執行一下至關於fn2.call(後面的參數),由於fn2是他的this, 就至關於把後面的 1 當作要指定的this傳進去, 也就形成了日後竄了一位. 第四步: 總結 無論寫多少個call, 執行第一個參數, 第二個參數爲第一個參數this的指向, 第三個參數開始是傳參...哈哈挺有意思!