热点面试题:JS 中 call, apply, bind 概念、用法、区别及实现?
概念:
function.call(thisArg, arg1, arg2, ...)
function.apply(thisArg, [arg1, arg2, ...])
function.bind(thisArg, arg1, arg2, ...)
- 三者都是改变
this
指向,通过一个参数或多个参数来调用一个函数的。
用法:
let obj = {
name: "哈哈",
sayName: function () {
console.log("sayName", this.name);
return this.name;
},
eat: function (food1, food2) {
console.log("eat", food1, food2);
},
};
let obj2 = {
name: "是的",
};
obj.sayName.call(obj2);
obj.eat.call(obj2, "鱼", "肉");
obj.eat.apply(obj2, ["鱼", "肉"]);
obj.eat.bind(obj2, "鱼", "肉");
let res = obj.eat.bind(obj2, "鱼", "肉");
res();
区别:
- call 与 bind 的区别?
call
会直接调用,而 bind
会创建一个新的函数作为一个返回值进行调用, 而其余参数将作为新函数的参数,供调用时使用
- call 与 apply 的区别?
- 主要区别在第二个参数中,
call
接受的是一个参数列表,也就是一个个参数,而 apply
接受的是一个包含多个参数的数组
实现:
function.call(thisArg, arg1, arg2, ...)
Function.prototype.myCall = function (context, ...args) {
if (Object.prototype.toString.call(this).slice(8, -1) != "Function")
throw new Error("type error");
if (!context || context === null) context = window;
let fn = Symbol();
context[fn] = this;
return context[fn](...args);
};
let obj = {
name: "哈哈",
sayName: function () {
console.log("sayName", this.name);
return this.name;
},
eat: function (food1, food2) {
console.log("eat", food1, food2);
},
};
let obj2 = {
name: "是的",
};
obj.sayName.myCall(obj2);
function.apply(thisArg, [arg1, arg2, ...])
Function.prototype.MyApply = function (context, args) {
if (Object.prototype.toString.call(this).slice(8, -1) != "Function")
throw new Error("type error");
if (!context || context === null) context = window;
let fn = Symbol();
context[fn] = this;
return context[fn](...args);
};
let obj = {
name: "哈哈",
sayName: function () {
console.log("sayName", this.name);
return this.name;
},
eat: function (food1, food2) {
console.log("eat", food1, food2);
},
};
let obj2 = {
name: "是的",
};
obj.sayName.MyApply(obj2, []);
function.bind(thisArg, arg1, arg2, ...)
Function.prototype.myBind = function (context, ...args) {
if (!context || context === null) {
context = window;
}
let fn = Symbol();
context[fn] = this;
let _this = this;
const result = function (...innerArgs) {
if (this instanceof _this === true) {
this[fn] = _this;
this[fn](...[...args, ...innerArgs]);
} else {
context[fn](...[...args, ...innerArgs]);
}
};
result.prototype = Object.create(this.prototype);
return result;
};
function Person(name, age) {
console.log(name);
console.log(age);
console.log(this);
}
Person.prototype.say = function () {
console.log(123);
};
let obj = {
objName: "我是obj传进来的name",
objAge: "我是obj传进来的age",
};
function normalFun(name, age) {
console.log(name);
console.log(age);
console.log(this);
console.log(this.objName);
console.log(this.objAge);
}
let bindFun = Person.myBind(obj, "我是参数传进来的name");
let a = new bindFun("我是参数传进来的age");
a.say();
文章特殊字符描述:
- 问题标注
Q:(question)
- 答案标注
R:(result)
- 注意事项标准:
A:(attention matters)
- 详情描述标注:
D:(detail info)
- 总结标注:
S:(summary)
- 分析标注:
Ana:(analysis)
- 提示标注:
T:(tips)