一、实现call
call 和 apply 和 bind其实就是改变函数的作用域。个人记忆法 叫的和绑定的只能一个个叫或者绑定,申请的话,可以一次申请多个。记这三个方法的 传参区别。bind函数调用,返回的是函数,并没有执行。
思路:整体的思路就是在调用的作用域下添加一个新函数并调用,然后删除。要处理context 为null时咋办,处理传参时候咋办,bind的时候还要想到返回的是个函数,并且可以被new,new了之后this的指向要变为 指向实例,还要用空函数来处理 prototype的继承。
call实现
Function.prototype.call2 = function (context) {
var context1 = context || window;
context1.fn = this;
console.log(arguments)
var result = context1.fn(...([...arguments].slice(1)));
delete context1.fn
return result;
}
// 测试一下
var value = 2;
var obj = {
value: 1
}
function bar1(name, age) {
console.log(this.value);
return {
value: this.value,
name: name,
age: age
}
}
bar1.call2(null); // 2
console.log(bar1.call2(obj, 'kevin', 18));
apply实现
Function.prototype.apply2 = function(context, arr) {
console.log(context);
let context1 = context || window;
console.log(this);
context1.fn = this;
let res;
if (!arr) {
context1.fn();
} else {
let args = Array.prototype.slice(arguments, 1);
res = eval('context1.fn(' + args + ')');
}
delete context1.fn;
return res;
};
let foo = {value: 21};
let bar = function() {
console.log(this.value);
}
bar();
bar.apply2(foo);
//undefined
//VM1169:2 {value: 21}
//VM1169:4 ƒ () {
// console.log(this.value);
//}
//VM1169:18 21
bind实现
Function.prototype.bind2 = function(context) {
if (typeof this !== "function") {
throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
}
let self = this;
let args = [...arguments].slice(1);
let fNop = function(){};
let fbind = function() {
let argBind = [...arguments].slice();
self.apply(this instanceof fNop ? this : context, args.concat(argBind));
}
fNop.prototype = this.prototype;
fbind.prototype = new fNop();
return fbind;
}
var value = 2;
var foo12 = {
value: 1
};
function bar12(name, age) {
this.habit = 'shopping';
console.log(this.value);
console.log(name);
console.log(age);
}
bar12.prototype.friend = 'kevin';
var bindFoo = bar12.bind2(foo12, 'daisy');
var obj = new bindFoo('18');
// undefined
// daisy
// 18
console.log(obj.habit);
console.log(obj.friend);