自定义改变this指向方法,call/apply/bind

对于普通函数在开始之前我们要明白js中this的指向是如何定义的:就是谁调用指向谁,是动态的。明白这一点,自定义改变this的指向方法就很简单,开始吧:

首先定义一个对象

var obj1 = {
name: 'obj对象name',
getName:function (arg1, arg2) {
console.log('this指向====', this)    
return this.name + arg1 + arg2
}
}
obj1.getName('str1', 'str2')

 
再定义另外一个对象

let obj2 = {
  name: 'obj2对象name'
}

现在我们想让obj1对象中getName方法里面的this指向obj2,  自定义个call/apply 方法来实现
首先定义一个 custCall 方法:

function custCall() {
console.log('this====' , this)
console.log('arguemts====' , arguments)
let context = arguments[0] || window// 新的指向
context.fn = this // obj.getName 要调用的方法
var arr = [...arguments]
arr.splice(0,1)
console.log('arr', arr)
context.fn(...arr)// 利用谁调用指向谁 最终指向context 也就是新的指向
}

应该是这样调用 obj1.getName.custCall(obj2, 'custStr1', 'custStr2')
但是我们发现 直接这样调用会报错 obj1.getName 上没有这个custCall 属性; 所以我们应该把这个custCall方法 设置到Function的原型对象上,这样Function的实例对象都可以访问到了,
多说一句:所有的方法都是Function的实例对象

Function.prototype.custCall = function (context=window, ...rest) {

if(typeof this != 'function') {
   throw new Error(`${this} is not a function`)
}
context.fn = this // obj.getName 要调用的方法
console.log('arr', arr)
let result = context.fn(...rest)// 利用谁调用指向谁 最终指向context 也就是新的指向
delete context.fn //删除绑定的函数
return result // 返回函数执行结果

}

然后再次调用obj1.getName.custCall(obj2, 'custStr1', 'custStr2')

 成功改变指向 

总结:

1.自定一个函数,两个参数 ,第一个参数接收指向的对象context,默认是window,   第二个参数用剩余参数接收所有的字符串参数;

2. 判断是否是函数调用,即this 的数据类型

3.   给对象绑定一个属性fn,指向this

4. 执行 context.fn , 传入参数,接收函数执行结果

5. 删除绑定的函数

6. 返回函数执行结果

apply 同理 ,只不过参数是数组 

bind  是返回一个函数,需要我们手动去执行

var name = 'window上的name'
function sayName(age) {
   

   return this.name + age

}

let obj = {
  name: 'obj上的name'
}

let result = sayName.bind(obj, '22') // ƒ fn() {return this.name}
result() // 'obj上的name'


自定义 bind

Function.prototype.custBind = function (context=window, ...rest) {

let self = this
let params = rest // 

if(typeof self != 'function') {
   throw new Error(`${this} is not a function`)
}

return function (...args)  {
       context.fn = self // 要改变指向的构造函数
       let data = params || args
       let result = context.fn(...rest) // 如果rest传入值了,必包接收的值args无效; 否则  使用 args
       return result    
}

}

var name = 'window上的name'
function sayName(age) {

   return this.name + age

}

let obj = {
  name: 'obj上的name'
}

let result1 = sayName.custBind(obj, '22')() // 'obj上的name22'
let result2 = sayName.custBind(obj)('33') // 'obj上的name33'

如果对你有帮助,麻烦点个赞 谢谢~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值