Appearance
Apply & Call & Bind
Apply
用法
js
const info = { name: "ice", age: 25 };
function bar(city, country) {
// info: ice 25 Hangzhou China
console.log(`info: ${this.name} ${this.age} ${city} ${country}`);
}
// 传递一个对象,作为 bar 的 this
bar.apply(info, ["Hangzhou", "China"]);- 函数
bar调用了apply方法,故 apply 方法是在 Function 的显示原型上 - 当我们利用 apply 方法调用,传入的第一个参数是函数内部的 this
- 第二个参数,传入一个数组,会以此展开给 bar 函数接受
实现
js
Function.prototype.MyApply = function (context, arrayArgs) {
// 1. 如果不是这些类型,把它包装为 Obj 类型
if (typeof context !== "object" || typeof context !== "function") {
context = Object(context);
}
// 2. 创建一个 symbol 属性,防止重复
const fn = Symbol("fn");
// 3. x.myApply() 隐式绑定,函数体内的 this 指向 x
context[fn] = this;
// 4. x 函数挂在了 context 上,所以内部的 this 指向已经变为 ctx
const result = context[fn](...arrayArgs);
// 5. 删除附加的 symbol
delete context[fn];
// 6. 返回返回值
return result;
};
const info = { name: "ice", age: 25 };
function bar(city, country) {
console.log(`info: ${this.name} ${this.age} ${city} ${country}`);
}
bar.MyApply(info, ["Hangzhou", "China"]);Call
用法
- 用法上与 apply 相似, 一个依次传递,一个传递数组
js
x.call(this, "a", "b", "c");
x.apply(this, ["a", "b", "c"]);实现
js
Function.prototype.MyCall = function (context, ...thisArgs) {
// 1. 不等于该类型,包装成对象类型
if (typeof context !== "object" || typeof context !== "function") {
context = Object(context);
}
// 2. 创建唯一的key
const fn = Symbol("fn");
// 3. x.MyCall(), x 挂载到 context 上
context[fn] = this;
// 4. 调用函数,并且展开参数
const result = context[fn](...thisArgs);
// 5. 删除属性
delete context[fn];
// 6. 返回
return result;
};
function bar(city, country) {
console.log(`info: ${this.name} ${this.age} ${city} ${country}`);
}
bar.MyCall({ name: "ice", age: 25 }, "Hangzhou", "China");Bind
用法
js
function bar(city, country) {
console.log(`info: ${this.name} ${this.age} ${city} ${country}`);
}
const bindBar = bar.bind({ name: "ice", age: 25 }, "Hangzhou");
bindBar("China");- x.bind(this, args) 第一个参数为 this,后面可选填参数, 返回一个新的函数 -> 携带了 this / 参数
- 调用新的函数,也可以再次传递参数
实现
js
Function.prototype.MyBind = function (context, ...thisArgs1) {
if (typeof context !== "object" || typeof context !== "function") {
context = Object(context);
}
const fn = Symbol("fn");
context[fn] = this;
// 返回了一个新的函数
return (...thisArgs2) => {
const result = context[fn](...thisArgs1, ...thisArgs2);
delete context[fn];
return result;
};
};
function bar(city, country) {
console.log(`info: ${this.name} ${this.age} ${city} ${country}`);
}
const bindBar = bar.MyBind({ name: "ice", age: 25 }, "Hangzhou", "China");
bindBar();- 与 call/apply 不同的是
- 它是返回了一个已经 bind this 的 fn 函数
- 函数的传递可以分批或者一次性传入