call 函數(shù)
語(yǔ)法
obj.call(thisObj,arg[,arg2[,arg3[,...agr]]]);
簡(jiǎn)介
修改obj的this指向?yàn)閠hisObj,后面的參數(shù)會(huì)當(dāng)成obj的參數(shù)安裝順序傳遞進(jìn)去。
我們先來(lái)看一下下面這段代碼會(huì)輸出什么:
function say(arg1, arg2) {
? console.log(this.name, arg1, arg2);
}
const obj = {
? name: "tom",
? say: function () {
? ? console.log(this.name);
? }
};
say();
輸出結(jié)果:

我們發(fā)現(xiàn)報(bào)錯(cuò)了,程序并沒(méi)有找到name;
現(xiàn)在我們來(lái)改動(dòng)一下,使用call函數(shù)來(lái)改變this的指向,看看會(huì)發(fā)生什么:
say.call(obj, "1", "2");
發(fā)現(xiàn)輸出的結(jié)果變成了:

call把say函數(shù)的this變?yōu)榱薿bj。
下面我們來(lái)實(shí)現(xiàn)一個(gè)call函數(shù)
Function.prototype._call = function (context) {
? // 判斷是否是一個(gè)函數(shù)
? // this指的是調(diào)用的函數(shù)
? if (typeof this !== "function") {
????????throw new TypeError("Error");
? }
? context = context || window;
? context.fn = this;
? const args = [...arguments].slice(1);
? const result = context.fn(...args);
? delete context.fn;
? return result;
};
驗(yàn)證一下:
say._call(obj, "1", "2");
發(fā)現(xiàn)輸出結(jié)果與期望的相同
apply函數(shù)
語(yǔ)法
obj.call(thisObj[,argArray]);
簡(jiǎn)介
apply與call函數(shù)的用法相同,只是參數(shù)的傳遞變成了數(shù)組形式。
say.apply(obj, ["1", "2"]);
輸出的結(jié)果與調(diào)用call相同:

與call的實(shí)現(xiàn)相比,只需要修改一下參數(shù)的傳遞:
Function.prototype._apply = function (context, args) {
? // 判斷是否是一個(gè)函數(shù)
? // this指的是調(diào)用的函數(shù)
? if (typeof this !== "function") {
? ? throw new TypeError("Error");
? }
? context = context || window;
? context.fn = this;
? let result = null;
? if (args) {
? ? result = context.fn(...args);
? } else {
? ? result = context.fn();
? }
? delete context.fn;
? return result;
};
bind 函數(shù)
語(yǔ)法
obj.bind(thisObj,arg[,arg2[,arg3[,...agr]]]);
簡(jiǎn)介
bind函數(shù)會(huì)返回一個(gè)新函數(shù),但是不會(huì)像call和apply一樣立即執(zhí)行函數(shù),bind后面的參數(shù)會(huì)當(dāng)成obj的參數(shù)安裝順序傳遞進(jìn)去。
我們先來(lái)看兩段代碼
const s = say.bind(obj, "1", "2");
s()
const s = say.bind(obj);
s("1", "2");
發(fā)現(xiàn)這兩段代碼輸出的結(jié)果是一樣的。
我們來(lái)簡(jiǎn)單實(shí)現(xiàn)一下bind函數(shù):
Function.prototype._bind = function (context) {
? // 判斷是否是一個(gè)函數(shù)
? if (typeof this !== "function") {
? ? throw new TypeError("Error");
? }
? const args = [...arguments].slice(1);
? const fn = this;
? const F = function () {},
? ? fBound = function () {
? ? ? return fn.apply(
? ? ? ? this instanceof F && context ? this : context || window,
? ? ? ? args.concat(...arguments)
? ? ? );
? ? };
? F.prototype = this.prototype;
? fBound.prototype = new F();
? return fBound;
};