apply
Function.prototype.myApply = function(context, args) {
if (context == null) {
//排除context==''的情况
context = window;
} else if (typeof context != "object") {
context = Object(context); //// 值为原始值(数字,字符串,布尔值)的 this 会指向该原始值的实例对象
}
// 给context新增一个独一无二的属性以免覆盖原有属性
const key = Symbol();
context[key] = this; //这里的this是testFun
/*
context={
....context,
Symbol():this
}
=>context={
...context:
fun:this=>fun:function(){}
}
context[key]=>context[Symbol]=>context.Symbol()=>context.fun()
*/
const result = context[key](...args);
//带走产生的副作用
delete context[key]; //要删除给context新增的属性key
return result;
};
call
Function.prototype.myCall = function(context, ...args) {
if (context == null) {
context = window;
}
let key = Symbol();
context[key] = this;
let result = context[key](...args);
delete context[key];
return result;
};
bind
Function.prototype.myBind = function(objThis, ...args) {
const _this = this;
let newBind = function(...paras) {
const isNew = this instanceof newBind; // this是否是newBind的实例,也就是返回的newBind是否通过new调用
const context = isNew ? this : Object(objThis); //new调用的就绑定到this上,否则就绑定到传入的objThis上
return _this.call(context, ...args, ...paras);
};
if (this.prototype) {
newBind.prototype = Object.create(this.prototype);
}
return newBind;
};
测试代码
var name = 'window'
function testFun(...args){
console.log(this.name,...args);
}
const testObj = {
name:'testObj'
}
const test = testFun.myBind(testObj);
const t = new test(); //undefined
console.log(t.name); //undefined
function Animal(name, color) {
this.name = name;
this.color = color;
}
Animal.prototype.say = function() {
return `I'm a ${this.color} ${this.name}`;
};
const Cat = Animal.bind(null, "cat");
const cat = new Cat("white");
if (
cat.say() === "I'm a white cat" &&
cat instanceof Cat &&
cat instanceof Animal
) {
console.log("success");
}
参考链接
【THE LAST TIME】this:call、apply、bind