call apply 原生實現
call() 和 apply() 類似於借用,相當於 A 對象內部有了 B 對象的方法,實質是函數在運行時指定 this 值,打破瞭解析器在函數調用時創建執行環境時this綁定的規則。
call 源碼
例子:
const val = {
a:1
}
function add(b,c){
return this.a + b + c
}
console.log(add.call(val,2,3)) //6
相當於:
1.給 val 對象增加方法 add
2.執行 val 對象的方法 add
3.刪除 add 方法
val.add = function(b,c){...}
console.log(val.add(2,3)) //6
delete val.add
call 原生實現:
Function.prototype.callFunc = function(context){
var context = context || window //undefined 時 this 綁定在全局
context.fn = this
var args = []
for(var i = 1, len = arguments.length; i < len; i++){
args.push('arguments[' + i + ']') //i 爲1,除去第一個參數
}
var result = eval('context.fn(' + args + ')') //eval 執行字符串內容
// es6 的 rest 寫法: var result = context.fn(...args)
delete context.fn
return result
}
es6 的 rest 寫法:
Function.prototype.callFunc = function(context){
var context = context || window //undefined 時 this 綁定在全局
context.fn = this
var args = []
for(var i = 1, len = arguments.length; i < len; i++){
args.push(arguments[i]) //i 爲1,除去第一個參數
}
var result = context.fn(...args)
delete context.fn
return result
}
通過在第一個參數 context 的屬性中存儲了調用 callFunc 函數的方法,然後再在 context 的執行環境中調用該屬性(即執行該方法)
apply 源碼
和 call 發生的過程一樣,不過需要判斷第二個參數是否是數組
apply 原生實現:
Function.prototype.applyFn = function(context,arr){
var context = context || window
context.fn = this
var result
if(!arr){ 不輸入第二個參數時
result = context.fn();
}else{
if(!(arr instanceof Array))
throw new Error('params must be array');
else
result = eval('context.fn('+arr+')');
// es6 的 rest 寫法: var result = context.fn(...args)
}
delete context.fn
return result
}