- call
Function.prototype.myCall = function(context) {
if(typeof this !== 'function') {
return;
}
// context 不传入或为 null,可指向 window
context = Object(context) || window;
context.fn = this;
const args = [...arguments].slice(1);
const result = context.fn(...args);
delete context.fn;
return result;
}
- apply
Function.prototype.myApply = function(context, arr) {
context = Object(context) || window;
context.fn = this;
let result;
if(!arr) {
result = context.fn();
} else {
result = context.fn(...arguments[1]);
}
delete context.fn;
return result;
}
- bind
bind() 方法会创建一个新函数。当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this,之后的一序列参数将会在传递的实参前传入作为它的参数。
Function.prototype.myBind = function(context) {
const self = this;
// 获取 bind 函数从第二个参数到最后一个参数
const args = [...arguments].slice(1);
return function() {
return self.apply(context, args.concat(...arguments))
}
}
bind 还有一个特点,就是 一个绑定函数也能使用new操作符创建对象:这种行为就像把原函数当成构造器。提供的 this 值被忽略,同时调用时的参数被提供给模拟函数。
也就是说当 bind 返回的函数作为构造函数的时候,bind 时指定的 this 值会失效,但传入的参数依然生效。
Function.prototype.myBind2 = function(context) {
const self = this;
// 获取 bind 函数从第二个参数到最后一个参数
const args = [...arguments].slice(1);
return function Fn() {
// 可以当构造函数调用
if(this instanceof Fn) {
return new self(...args, ...arguments)
}
return self.apply(context, args.concat(...arguments))
}
}
分析:
bind 返回一个函数,函数有两种调用方式,一是直接调用,二是用 new 的方式当做构造函数调用
- 直接调用:因为 bind可以这样使用:
fn.bind(obj, 1, 2)(3, 4)
所以需要把参数拼接即args.concat(...arguments)
- new 调用:需忽略 this