「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」。
call
call 方法的作用是改变函数内部的this指向
传入参数分两部分,第一个参数是需要指向的this,后面的参数是实参列表 arg1,arg2,arg3...
我们要实现call方法的话,需要一步一步来处理
首先,我们先来看一下call是怎么用的
// 我们有一个函数
function getName() {
return this.name;
}
// 还有一个对象
const obj = {
name: "张三",
};
// 最终输出
getName.call(obj);
//张三
这个方法要怎么来实现呢?写代码和吃饭一样不能贪心,我们先来实现this指向的变更
我们可以为call增加一个this的方法
// 直接使用symbal方式了,原理和正常对象一样
Function.prototype.call = function (context) {
const symbol = Symbol("fn");
context[symbol] = this;
context[symbol]();
delete context[symbol];
};
再来实现参数的传递
Function.prototype.call = function () {
const [ctx, args] = arguments;
const symbol = Symbol("fn");
ctx[symbol] = this || window;
const result = ctx[symbol](args);
delete ctx[symbol];
return result;
};
apply
apply的实现和call基本一致,唯一的区别就是参数传入的区分,我们借助上面的call来直接实现
Function.prototype.apply = function () {
const [ctx, args] = arguments;
const symbol = Symbol();
ctx[symbol] = this || window;
const result = ctx[symbol](args);
delete ctx[symbol];
return result;
};
bind
bind和上面两个不太一样,但是可以借用apply来实现,我们先来分析bind的特性,并对应进行代码实现输出
bind会返回一个新函数,新函数执行时this是bind方法的第一个参数
Function.prototype.bind = function () {
const [ctx, ...args] = arguments;
const self = this;
return function () {
self.apply(args);
};
};
上面的方法就将this绑定的功能实现了,我们要来继续处理这个方法
其实bind也是可以传递参数的,bind在返回的时候可以传递参数,并且调用bind方法也是有返回值的
因此我们需要来对其做以下处理
Function.prototype.bind = function () {
const [ctx, ...args] = arguments;
const self = this;
return function () {
// arguments调用bind会返回函数,此函数被调用时被传瑞的参数需要一起连接在一起
// 以下代码来进行处理
return self.apply(ctx, args.concat(arguments));
};
};
由于bind返回的函数时可以作为构造函数,作为构造函数的函数,之前绑定的this会被忽略。
我们在下面的处理中需要保证bind返回的函数可以继承道调用函数的原型
因此,我们需要修改bind返回的函数的原型是this的原型
以下进行代码实现
Function.prototype.bind = function () {
const [ctx, args] = arguments;
const self = this;
const newFunc = function () {
// 此处this会被变更为 调用bind之后的方法的this
// 即this = func.bind(this);
return self.apply(
this instanceof newFunc ? this : (ctx, args.concat(arguments))
);
};
newFunc.prototype = self.prototype;
return newFunc;
};
接下来我们发现,bind对于函数的原型也不会修改,我们要怎么处理呢?
我们可以使用中间函数来继承,方案如下
Function.prototype.bind = function () {
if (typeof this !== "function") {
throw new Error("Must be function to call bind");
}
const [ctx, args] = arguments;
const self = this;
var centerFunc = function () {};
const newFunc = function () {
// 此处this会被变更为 调用bind之后的方法的this
// 即this = func.bind(this);
return self.apply(
this instanceof newFunc ? this : (ctx, args.concat(arguments))
);
};
centerFunc.prototype = self.prototype;
newFunc.prototype = new centerFunc();
return newFunc;
};
以上,我们就将bind方方法相对比较完整的实现了一遍。
同时bind的四个特性也梳理出来了
-
bind会返回一个新函数,新函数执行时的this是bind方法的第一个参数
-
bind返回的时候也是可以传递参数的,同时调用bind方法是有返回值的
-
bind可以作为构造函数
-
bind不会修改函数的原型
你学废了么~~~