call的实现
call的第一个参数是指向值,如果为null或者undefined则是,this指向window
第二个参数是以一个一个传入
Function.prototype.fancall=function(context,...arg){
//如果是null和undefined的时候就指向全局
if(context==null||context==undefined)
context=window
let tem=Symbol() //做一个唯一值 防止于原上下文对象属性冲突
context[tem]=this //函数隐试绑定到context上
let res = context[tem](...arg) //传参执行 就是function() 执行
delete context[tem] //删除临时属性
return res
}
apply实现
唯一不同就是传参方式不同
Function.prototype.fanapply=function(context){
//如果是null和undefined的时候就指向全局
if(context==null||context==undefined)
context=window
let arr=arguments[1] //获取数组参数 就是第二个
console.log(arr);
let tem=Symbol() //做一个唯一值 防止于原上下文对象属性冲突
context[tem]=this //函数隐试绑定到context上
let res
if(arr){
res = context[tem](arr) //传参执行 就是function() 执行
}
else{
res = context[tem]() //传参执行 就是function() 执行
}
delete context[tem] //删除临时属性
return res
}
bind实现
虽然bind和其余两个一样都是改变this的指向,但bind是返回一个新的函数,而不是直接执行
- 箭头函数的
this
永远指向它所在的作用域 - 函数作为构造函数用
new
关键字调用时,不应该改变其this
指向,因为new绑定
的优先级高于显示绑定
和硬绑定
Function.prototype.fanbind=function(context){
if(typeof this!=='function')
throw new TypeError(`Error`)
let _this =this
let arr=Array.prototype.slice.call(arguments,1) //获取参数
var profunction=function(){}//用于继承原型链
var F=function (){
if(this instanceof F){
//如果是被当做构造函数调用,第一个参数作废 当为构造函数的时候this指向实例
return _this.apply(this,arr.concat([...arguments]))
}
//否则就是原先的调用对象
return _this.apply(context,arr.concat([...arguments]))
}
profunction.prototype=this.prototype //继承原本函数的原型
F.prototype=new profunction()
return F
}
实例
var value = 2;
var foo = {
value: 1
};
function bar(name, age) {
this.habit = 'shopping';
console.log(this.value);
console.log(name);
console.log(age);
}
bar.prototype.friend = 'kevin';
var bindFoo = bar.fanbind(foo, 'daisy');
var obj = new bindFoo('18');
// undefined
// daisy
// 18
console.log(obj.habit);
console.log(obj.friend);
// shopping
// kevin