看一下.call
都做了些什么
let obj = {
age: 18
}
function fn(...params) {
console.log(this.age, ...params);// 18 "参数1" "参数2" "参数n"
return "返回值"
}
console.log(fn.call(obj, "参数1", "参数2", "参数n"))// "返回值"
- this指向了
.call()
的以一个参数。2. 从第二个参数到最后一个参数,会对 fn 进行传参。3. 执行函数 fn
模拟 call 方法,写一个 myCall 方法
let obj = {
age: 18
}
function fn(...params) {
console.log(this.age, ...params)
}
Function.prototype.myCall = function myCall(context, ...params) {
// 此时的 myCall 还仅仅是个函数,不能做任何事
}
// 将来要和原来的 call 方法一样使用。
fn.myCall(obj, "参数1", "参数2", "参数n")
第一步改变this指向
如果将 fn 变成 obj 的一个属性,并调用obj.fn()
,此时 fn 中的 this 自然指向 obj。
let obj = {
age: 18
}
function fn(...params) {
console.log(this.age, ...params)
}
obj.fn = fn
obj.fn("参数1", "参数2", "参数n") // 18 "参数1" "参数2" "参数n"
所以,myCall 中可以这样写:
let obj = {
age: 18
}
function fn(...params) {
console.log(this.age, ...params)
}
Function.prototype.myCall = function myCall(context, ...params) {
let fn = Symbol();
context[fn] = this; // 这里的 this 是.前面的主,即 fn,我们将 fn 当做一个属性赋值给 context
context[fn](); // 执行 context.fn(),之后 fn 中的 this,自然指向.前面的主,即 context
}
fn.myCall(obj, "参数1", "参数2", "参数n") // 18
可以看到,这一步,我们实现了函数 fn 中的 this 指向变为 obj 的功能,并执行了 fn 函数
第二步传递参数给 fn
这一步就简单了,我们可以用 arguments 从下标1开始截取需要传递的参数,也可以和上面的例子一样,用...params
来获取参数,进行传递
let obj = {
age: 18
}
function fn(...params) {
console.log(this.age, ...params)
}
Function.prototype.myCall = function myCall(context, ...params) {
let fn = Symbol();
context[fn] = this; // 这里的 this 是.前面的主,即 fn,我们将 fn 当做一个属性赋值给 context
context[fn](...params); // 执行 context.fn(),之后 fn 中的 this,自然指向.前面的主,即 context
}
fn.myCall(obj, "参数1", "参数2", "参数n") // 18 "参数1" "参数2" "参数n"
看到这一步,基本的 myCall 方法已经完成80%,还有两个小点要注意:
- this 参数可以传 null,当为 null 的时候,视为指向 window
Function.prototype.call = function call(context, ...params) {
// 做判断,context 应该为 this 需要指向的对象或者函数
if (context == null) context = window;
let type = typeof context;
if (type !== "object" && type !== "function") {
// 把传递的原始值类型变为对应的对象类型值
context = Object(context);
}
let fn = Symbol();
context[fn] = this;
context[fn](...params);
delete context[fn]; // 用完记得把新加的属性删除掉,不然会越来越。
};
- 函数 fn 是可以有返回值的!
Function.prototype.call = function call(context, ...params) {
if (context == null) context = window;
let type = typeof context;
if (type !== "object" && type !== "function") {
context = Object(context);
}
let fn = Symbol();
context[fn] = this;
let result = context[fn](...params); // 函数执行之后,获取到返回值。
delete context[fn];
return result // 将获取到的返回值,返回出去。
};
一个 模拟 call 方法的 myCall 方法完成。