1.apply(thisArg, [argsArray])
在實現之前,首先看一下MDN上關於apply函數的說明:
apply() 方法調用一個具有給定this值的函數,以及作爲一個數組(或類似數組對象)提供的參數。
apply函數會將當前調用函數的this綁定在thisArgs上,我們知道,在JavaScript中,常見的函數綁定this的方法除了apply,call之外,還會在函數被當做對象的屬性調用時被這個對象綁定,
例如:
obj.func() // 執行時func中的this指向obj
根據這個思路,就容易寫出代碼了:
// 爲了讓所有的函數都能調用,需要定義在Function的原型對象上
Function.prototype.myApply = function(thisArg) {
let fn = this;
let args = arguments[1];
thisArg.fn = fn; // 將函數添加到thisArgs的屬性上,通過屬性調用
thisArg.fn(...args);
}
const obj = {
name: 'oyy',
age: 23,
}
const func = function(a, b, c) {
console.log(this.name);
console.log(a + b + c)
}
func.myApply(obj, [1, 2, 3])
上面的代碼還有些問題,如果將obj打印出來,會發現obj多了一個fn屬性,爲了不污染源對象,需要在fn調用完之後手動將其刪除
Function.prototype.myApply = function(thisArg) {
let fn = this;
let args = arguments[1];
thisArg.fn = fn; // 將函數添加到thisArgs的屬性上,通過屬性調用
thisArg.fn(...args);
delete thisArg.fn;
}
另外,在thisArgs爲null或者undefined時,thisArg會自動替換爲指向全局對象。
Function.prototype.myApply = function(thisArgs) {
if (!thisArgs) thisArgs = window; // 這裏指向window
let fn = this;
let args = arguments[1] || [];
thisArgs.fn = fn;
thisArgs.fn(...args);
delete thisArgs.fn;
}
如此一來,就基本上實現了apply函數。
2.call(thisArg, arg1, arg2, …)
call() 方法使用一個指定的 this 值和單獨給出的一個或多個參數來調用一個函數。
與apply函數類似,call也能做到綁定函數的this,他們的區別在於傳參方式有些不一樣,call接受的是一個的參數列表
仍然使用上面的思路:
Function.prototype.myCall = function(thisArg) {
if (!thisArg) thisArg = window;
let fn = this;
let args = [];
for (let i = 1; i < arguments.length; i++) {
args.push(arguments[i]);
// args.push('arguments[' + i + ']');
}
thisArg.fn = fn;
thisArg.fn(...args);
// eval('thisArg.fn(' + args + ')');
delete thisArg.fn;
}
上面兩個函數都使用了擴展運算符’…’,如果不用這個的話,那麼通過eval的方式傳入一個構造好的參數字符串列表也可以達到一樣的效果(看註釋部分)