一、什么是劫持?
再JS中劫持是this关键字的劫持,也就是改变this指向。
再之前的this的文章中,谈到this指向的就是它的调用者。
再这里this的劫持用的是call方法和apply方法来实现的。
二、call方法
call() 方法用来调用所有者对象作为参数的方法。
通过 call(),能够使用属于另一个对象的方法。
call方法的第一个参数代表指定的调用者,后面的参数代表传递的实参,它是分别接受参数。
案例:
var obj={name:"karen",say:function(str,arg2){console.log(this.name,str,arg2)}}
var obj2={name:"jack"}
var obj3={name:"marry"}
obj.say.call(obj2,100,200) //相当于是obj2在调用say方法
obj.say.call(obj3,80,10)
三、apply方法
apply() 方法跟call方法一样所不同的是参数,apply()方法接受数组形式的参数。
如果要使用数组而不是参数列表,则 apply() 方法非常方便。
案例1:
var obj={name:"karen",say:function(arg1,arg2){console.log(this.name,arg1,arg2,arguments)}}
var obj2={name:"jack"}
var obj3={name:"marry"}
obj.say.apply(obj2,['ljy',100])
obj.say.apply(obj3,['ljy',200])
obj.say.apply(obj3,['ljy',300])
案例2求数组中的最大值和最小值:
var arr=[90,50,30,80,40,70,100]
var max=Math.max.apply(arr,arr)
var min=Math.min.apply(arr,arr)
console.log(max,min)
四、解决方法bind()
定义式的函数可以在设计的时候就指定this
例如:fn.bind(obj)
案例:
var obj2={name:"karen"}
var obj={
name:"ljy",
say:function(){
console.log(this)
}.bind(obj2)
}
obj.say()
var obj3={name:"marry"}
obj.say.call(obj3)
obj.say.apply(obj3,[])
五、拓展
call连用的案例
function fn () {
console.log(1)
}
function fn2 () {
console.log(2)
}
fn.call.call(fn2)
fn.call.call.call(fn2)
分析:
1.所有的函数对象都有call方法—Function.prototype有call方法
2.调用call方法是调用者运行
3.也就是fn.call.call(fn2)等价于fn2.call(), call(fn2)相对于把调用它的调用者改成了fn2, 然后调用它的函数运行也就是前面那个call运行所以就等价于fn2.call() ==>fn2()
设计call函数的代码
var obj={name:"ljy",say:function(a,b){console.log(this.name,a,b)},age:10}
var obj2={name:'karen',age:30}
Function.prototype.mycall=function(That,...args) { //...args代表多个参数
var name1="ljy_"+new Date()
That[name1]=this
var re=That[name1](...args)//让传进来的对象去调用this函数
delete That[name1]
return re
}
obj.say.mycall(obj2,100,200)
设计思路:
从call函数实现的两个功能入手:
一、调用call方法是调用者运行==>this()
二、改变调用者的this对象:设置形参接受传入的设置的调用者;
然后给其设置一个方法保存this,也就是保存原先调用它的函数。
方法名用个绝不会重名的,比如:加个当前时间
然后运行接受的调用者的这个方法,就实现了改变call调用者的this指向
最后删除这个方法,用delete来删除,就不会导致传入的对象里面多了个这个方法。