对于普通函数在开始之前我们要明白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'
如果对你有帮助,麻烦点个赞 谢谢~~