call()
經過指定this
的指向來實現函數的間接調用,而且能夠傳入函數調用的參數
數組
舉個例子:bash
var foo = {
value: 1
};
function bar() {
console.log(this.value)
}
bar.call(foo); // 1
複製代碼
首先咱們要知道call()
在這裏起的做用:
閉包
咱們能夠模擬一下這兩個效果:app
var foo = {
value: 1,
bar: function() {
console.log(this.value)
}
};
foo.bar(); // 1
複製代碼
能夠看到將bar
設爲foo
的屬性,便實現了將this
指向foo
。可是這樣作給foo
對象無緣無故的添加了一個屬性,所以咱們還要經過delete
刪除它。
所以主要實現思路以下:
函數
// 1.將函數設爲對象的屬性
foo.fn = bar
// 2.執行該函數
foo.fn()
// 3.從對象中刪除該函數
delete foo.fn
複製代碼
根據這個思路先實現一個簡易版的:post
Function.prototype.call2 = function(context) {
// 首先要獲取調用call的函數,用this能夠獲取
context.fn = this;
context.fn();
delete context.fn;
}
複製代碼
接下來實現call
給定參數執行函數:
要注意傳入的參數個數是不肯定的,咱們能夠從arguments
對象中取值,即第二個到最後一個參數即是要傳入的參數。測試
Function.prototype.call2 = function(context) {
context.fn = this;
var args = [];
// 遍歷arguments類數組對象,取得第二個開始的參數,放到數組裏面去
for(var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
// 執行後 args爲 [arguments[1], arguments[2], arguments[3]]
// 這裏 args 會自動調用Array.toString()方法
eval('context.fn(' + args +')');
delete context.fn;
}
複製代碼
此時call()
方法的核心已經實現了,下面要完善call()
的功能:
ui
window
完整實現this
Function.prototype.call2 = function(context) {
var context = context || window;
context.fn = this;
var args = [];
for(var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
var result = eval('context.fn(' + args + ')');
delete context.fn
return result;
}
複製代碼
// 測試
var value = 2;
var obj = {
value: 1
}
function bar(name, age) {
console.log(this.value);
return {
value: this.value,
name: name,
age: age
}
}
bar.call2(null); // 2
console.log(bar.call2(obj, 'kevin', 18));
// 1
// Object {
// value: 1,
// name: 'kevin',
// age: 18
// }
複製代碼
apply的實現跟call相似,區別在於apply第二個參數傳入的是一個參數數組spa
Function.prototype.apply = function (context, arr) {
var context = Object(context) || window;
context.fn = this;
var result;
if (!arr) {
result = context.fn();
}
else {
var args = [];
for (var i = 0, len = arr.length; i < len; i++) {
args.push('arr[' + i + ']');
}
result = eval('context.fn(' + args + ')')
}
delete context.fn
return result;
}
複製代碼
結尾
系列文章: