目錄
一、定義
1、call
call()
方法使用一個指定的 this
值和單獨給出的一個或多個參數來調用一個函數。
fuction.call(thisArg, arg1, arg2, ...)
參數:
thisArg
可選的。在 function
函數運行時使用的 this
值。請注意,this
可能不是該方法看到的實際值:如果這個函數處於非嚴格模式下,則指定爲 null
或 undefined
時會自動替換爲指向全局對象,原始值會被包裝。
arg1, arg2, ...
指定的參數列表。
2、apply
apply()
方法調用一個具有給定this
值的函數,以及作爲一個數組(或類似數組對象,ES5之後支持傳類數組,如dom中的一些類數組結果或者arguments)提供的參數。
function.apply(thisArg, [argsArray])
參數:
thisArg
必選的。在 func
函數運行時使用的 this
值。請注意,this
可能不是該方法看到的實際值:如果這個函數處於非嚴格模式下,則指定爲 null
或 undefined
時會自動替換爲指向全局對象,原始值會被包裝。
argsArray
可選的。一個數組或者類數組對象,其中的數組元素將作爲單獨的參數傳給 func
函數。如果該參數的值爲 null
或 undefined
,則表示不需要傳入任何參數。從ECMAScript 5 開始可以使用類數組對象。 瀏覽器兼容性 請參閱本文底部內容。
返回值
調用有指定this
值和參數的函數的結果。
注意:call()方法的作用和 apply() 方法類似,區別就是call()
方法接受的是參數列表,而apply()
方法接受的是一個參數數組。
3、bind
bind()
方法創建一個新的函數,在 bind()
被調用時,這個新函數的 this
被指定爲 bind()
的第一個參數,而其餘參數將作爲新函數的參數,供調用時使用。
function.bind(thisArg[, arg1[, arg2[, ...]]])
參數:
thisArg
調用綁定函數時作爲 this
參數傳遞給目標函數的值。 如果使用new
運算符構造綁定函數,則忽略該值。當使用 bind
在 setTimeout
中創建一個函數(作爲回調提供)時,作爲 thisArg
傳遞的任何原始值都將轉換爲 object
。如果 bind
函數的參數列表爲空,執行作用域的 this
將被視爲新函數的 thisArg
。
arg1, arg2, ...
當目標函數被調用時,被預置入綁定函數的參數列表中的參數。
bind是ES5新增的一個方法,不會執行對應的函數(call或apply會自動執行對應的函數),而是返回對綁定函數的引用。
二、 關於call、apply和bind
1、call
、apply
、bind
方法的共同點:
apply
、 call
、bind
三者都是Function原型(即Function.prototype)的方法apply
、 call
、bind
三者都是用來改變函數的this對象的指向的;apply
、 call
、bind
三者第一個參數都是this要指向的對象,也就是想指定的執行上下文環境;apply
、 call
、bind
三者都可以利用後續參數傳參;
2、call
、apply
、bind
方法的不同點:
bind
是返回對應函數,便於稍後調用;apply
、call
則是立即調用 。
call/apply的用法相同,區別在於傳參數方式不同,call接受一個參數列表,apply接受一個參數數組,call是apply的語法糖
三、拓展
1、模擬實現call
Function.prototype.myCall = function (ctx) {
//獲取上下文ctx
let ctx = ctx || window;
//獲取當前將要執行的函數
ctx.fn = this;
//截取參數
let args = [...arguments].slice(1);
//執行函數
let res = ctx.fn(...args);
//去除副作用
delete ctx.fn;
return res;
}
2、模擬實現apply,和call類似
Function.prototype.myApply = (ctx){
var ctx = ctx || window;
ctx.fn = this;
var res;
if (arguments[1]) {
re s = ctx.fn(...arguments[1]);
} else {
res = ctx.fn();
}
delete ctx.fn;
return res
}
3、模擬實現bind
//bind() 方法創建一個新的函數,在 bind() 被調用時,這個新函數的 this 被指定爲 bind() 的第一個參數,
//而其餘參數將作爲新函數的參數,供調用時使用。
Function.prototype.bind = Function.prototype.bind || function (context) {
if (typeof this !== "function") {
throw new Error("Function.prototype.bind is not a function")
}
var self = this;
var args = [...arguments].slice(1);
return function F() {
if (self instanceof F) {
return new self(...args, ...arguments);
}
return new self.apply(context, args.concat(...arguments));
}
};
4、應用
(1)call可以用作檢測數據類型
const getVarType = (target) => {
var classToType = {};
"Array Date RegExp Object Error".split(" ").forEach(function(item) {
classToType["[object " + item + "]"] = item.toLowerCase();
});
function type(target) {
if (target === null) {
return String(target);
}
return typeof target === "object"
? classToType[object.prototype.toString.call(target)] || "object"
: typeof target;
}
return type(target);
};
2、apply可以用作柯里化
函數柯里化是把接受多個參數的函數轉變成接受一個單一參數(最初函數的第一個參數),並且返回接受餘下的參數而且返回結果的新函數的技術。
柯里化其實本身是固定一個可以預期的參數,並返回一個特定的函數,處理批特定的需求。這增加了函數的適用性,但同時也降低了函數的適用範圍。
這是以前看《javascript設計模式與開發實踐》做的筆記,
var currying = function(fn) {
var args = [];
return function() {
if (arguments.length === 0) {
return fn.apply(this, args); // 沒傳參數時,調用這個函數
} else {
[].push.apply(args, arguments); // 傳入了參數,把參數保存下來
return arguments.callee; // 返回這個函數的引用
}
}
}
var cost = (function() {
var money = 0;
return function() {
for (var i = 0; i < arguments.length; i++) {
money += arguments[i];
}
return money;
}
})();
var cost = currying(cost);
cost(100); // 傳入了參數,不真正求值
cost(200); // 傳入了參數,不真正求值
cost(300); // 傳入了參數,不真正求值
console.log(cost()); // 求值並且輸出600
上面這種情況沒有考慮爲函數與傳參數情況,所以做了一點點修改
var currying = function(fn) {
var args = [...argumengts].slice(1);
return function() {
if (arguments.length === 0) {
return fn.apply(this, args); // 沒傳參數時,調用這個函數
} else {
[].push.apply(args, arguments); // 傳入了參數,把參數保存下來
return arguments.callee; // 返回這個函數的引用
}
}
}
3、apply函數可以用來實現bind(參見上面bind的實現)
四、瀏覽器兼容性
詳見參考資料1、2、3-對應call、apply和bind的MDN文檔
五、參考資料
1、https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/call
2、https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
3、https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind