Implementation fn.apply() fn.call() And fn.bind()
why#
demo:
const name = "foo";
const obj = {
name: "bar",
say: function () {
console.log(this.name);
},
};
obj.say(); // output: bar // this => obj
const sayName = obj.say;
sayName(); // output: foo // this => window
函数作为 JavaScript 的一等公民,可以作为值任意传递;在不同执行上下文中,this 的值是被动态计算出来的。有时为了绑定函数的执行环境,fn.apply()
, fn.call()
,fn.bind()
就起到至关重要的作用
how?如何改变函数的 this 呢?看个例子:
var sData = "display() Wisen"; //not let
function display() {
console.log("sData value is %s ", this.sData);
}
display(); //sData value is display() Wisen // this => Window
object wrap:
let displayWrap = {
sData: "displayWrap() Wisen",
display() {
console.log("sData value is %s ", this.sData);
},
};
displayWrap.display(); //sData value is displayWrap() Wisen //this => displayWrap
没错正是利用:obj.fn()的 this 指向 obj 的特点
fn.apply()#
function fn(...args) {
console.log(this, args);
}
let obj = {};
fn(1, 2); // this => window
fn.apply(obj, [1, 2]); // this => obj
fn.apply(null, [1, 2]); // this => window
fn.apply(undefined, [1, 2]); // this => window
可以看出:
- apply 接受两个参数,第一个参数是 this 的指向,第二个参数是数组
- 当第一个参数为 null、undefined 的时候,默认指向 window(在浏览器中)
- 原函数会立即执行
fn.call()#
function fn(...args) {
console.log(this, args);
}
let obj = {};
fn(1, 2); // this => window
fn.call(obj, [1, 2]); // this => obj
fn.call(null, [1, 2]); // this => window
fn.call(undefined, [1, 2]); // this => window
可以看出:
- call 接受两个参数,第一个参数是 this 的指向,第二个参数是参数列表
- 当第一个参数为 null、undefined 的时候,默认指向 window(在浏览器中)
- 原函数会立即执行
和 apaly 唯一的区别就是 第二个参数不同
fn.bind()#
function fn(...args){
console.log(this,args);
}
let obj = {};
const bindFn = fn.bind(obj); // 需要执行依次 fn.bind()
fn(1,2) // this => window
bindFn.([1,2]); // this => obj
fn.bind()([1,2]); // this => window
fn.bind(null)([1,2]); // this => window
可以看出:
- bind 接受两个参数,第一个参数是 this 的指向,第二个参数是参数列表
- 当第一个参数为 null、undefined 的时候,默认指向 window(在浏览器中)
- 返回一个改变 this 指向的函数
implement#
fn.apply
Function.prototype.apply = function (thisArg, argsArray) {
if (thisArg === undefined || thisArg === null) {
thisArg = window;
} else {
thisArg = Object(thisArg);
}
const func = Symbol("func");
thisArg[func] = this;
let result;
if (argsArray && typeof argsArray === "object" && "length" in argsArray) {
result = thisArg[func](...Array.from(argsArray));
} else {
result = thisArg[func]();
}
delete thisArg[func];
return result;
};
fn.call
Function.prototype.call = function (thisArg, ...argsArray) {
if (thisArg === undefined || thisArg === null) {
thisArg = window;
} else {
thisArg = Object(thisArg);
}
const func = Symbol("func");
thisArg[func] = this;
let result;
if (argsArray.length) {
result = thisArg[func](...Array.from(argsArray));
} else {
result = thisArg[func]();
}
delete thisArg[func];
return result;
};
fn.bind()
Function.prototype.call = function (thisArg, ...argsArray) {
if (thisArg === undefined || thisArg === null) {
thisArg = window;
} else {
thisArg = Object(thisArg);
}
const func = this;
const bound = function (...boundArgsArray) {
return func.apply(
this instanceof func ? this : thisArg,
argsArray.concat(boundArgsArray)
);
};
return bound;
};
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix