call
const obj1 = {
name:'张三',
age:18,
sex:'男',
// 存储在对象obj1 中的函数 this指向默认是 对象obj1
// this.name , this.age , this.sex 调用的应该是 obj1 中的数据
fun:function(addr,phone){
console.log( this.name );
console.log( this.age );
console.log( this.sex );
console.log( addr );
console.log( phone );
}
}
obj1.fun('北京' , 12341);
const obj1 = {
name:'张三',
age:18,
sex:'男',
// 存储在对象obj1 中的函数 this指向默认是 对象obj1
// this.name , this.age , this.sex 调用的应该是 obj1 中的数据
fun:function(addr,phone){
console.log( this.name );
console.log( this.age );
console.log( this.sex );
console.log( addr );
console.log( phone );
}
}
const obj2 = {
name:'李四',
age:20,
sex:'女',
};
obj1.fun.call(obj2 , '天津' , 12345);
我们可以这样理解:把fun方法放到obj2 里面,然后我在obj2 的环境下执行fun(如果obj2 没有值,那就相当再window环境下执行fun,this是指向window的),相当obj2.fun( ‘天津’ , 12345)或者fun( ‘天津’ , 12345),然后我再obj2里面删除fun方法。知道原理了,那么我们按照上面的例子来自己封装下call方法:
手写call
// obj1.fun.newCall(obj2 , '天津' , 12345);
Function.prototype.newCall = function (context,...arg) {
// 当call的第一个参数没有或者是null的时候,this的指向是window
let ctx = context || window;
//this是谁?谁调用这个call,this就指向谁,所以this指向obj1.fun
//把obj1.fun 放到ctx里面,就是赋值给 ctx.fn,那么ctx.fn就与obj1.fun等价了
ctx.fn = this;
//用指定的上下文去执行当前调用newCall的函数
const res = ctx.fn(...arg);
//删除 避免污染全局
delete ctx.fn;
// 因为函数可能有返回值,所以把结果也返回出去给他们
return res
};
apply
const obj1 = {
name:'张三',
age:18,
sex:'男',
// 存储在对象obj1 中的函数 this指向默认是 对象obj1
// this.name , this.age , this.sex 调用的应该是 obj1 中的数据
fun:function(addr,phone){
console.log( this.name );
console.log( this.age );
console.log( this.sex );
console.log( addr );
console.log( phone );
}
}
const obj2 = {
name:'李四',
age:20,
sex:'女',
};
obj1.fun.apply(obj2 , [ '天津' , 12345 ])
手写apply
Function.prototype.newApply = function (context, arg) {
// 当call的第一个参数没有或者是null的时候,this的指向是window
let ctx = context || window;
//this是谁?谁调用这个call,this就指向谁,所以this指向obj1.fun
//把obj1.fun 放到ctx里面,就是赋值给 ctx.fn,那么ctx.fn就与obj1.fun等价了
ctx.fn = this;
//用指定的上下文去执行当前调用newCall的函数
const res = ctx.fn(...arg);
//删除 避免污染全局
delete ctx.fn;
// 因为函数可能有返回值,所以把结果也返回出去给他们
return res
};
bind
const obj1 = {
name:'张三',
age:18,
sex:'男',
// 存储在对象obj1 中的函数 this指向默认是 对象obj1
// this.name , this.age , this.sex 调用的应该是 obj1 中的数据
fun:function(addr,phone){
console.log( this.name );
console.log( this.age );
console.log( this.sex );
console.log( addr );
console.log( phone );
}
}
const obj2 = {
name:'李四',
age:20,
sex:'女',
};
obj1.fun.bind(obj2 , '天津' , 12345)();
手写bind
bind还支持另一种传参方法,所以需要修改下
obj1.fun.bind(obj2)( '天津', 12345);
Function.prototype.newBind = function (context, ...arg) {
// 当call的第一个参数没有或者是null的时候,this的指向是window
let ctx = context || window;
//this是谁?谁调用这个call,this就指向谁,所以this指向obj1.fun
//把obj1.fun 放到ctx里面,就是赋值给 ctx.fn,那么ctx.fn就与obj1.fun等价了
ctx.fn = this;
return (...argAgu)=>{
ctx.fn(...arg,...argAgu)
}
};
…arg
参考:
哔哩哔哩—JS中this指向以及手写call、apply、bind
[ES6] this指向 window 事件源 箭头函数的this指向 改变this指向 call apply bind