改变this指向
改变this指向的三大方法
- call
立即执行
参数传递为单个传递
- apply
立即执行
参数传递为数组
- bind
不立即执行,会返回一个函数,调用时才执行
参数传递可单个传递,也可传递数组
举例说明
<script> window.color = "red" document.color = "yellow" var obj = { color: "salmon" } function changeColor(newColor1,newColor2) { console.log(this.color) console.log(newColor1) console.log(newColor2) } changeColor.call(obj,"pink","grey") //salmon pink grey changeColor.apply(obj,["pink","grey"]) //salmon pink grey var bindColor=changeColor.bind(obj,"pink","grey") //salmon pink grey bindColor() var bindColor2=changeColor.bind(obj,'blue') bindColor2('green','pink') //salmon blue green </script>
手写解析
- 手写call
var obj = { color: "salmon" } function changeColor(newColor1,newColor2) { return{ color:this.color, newColor1,newColor1, newColor2:newColor2 } } var newCall=function(objarg){ //this指向调用的方法changeCOlor //objarg指向传递进来的第一个参数,为想要改变的this指向,必须为一个对象 objarg=objarg||window objarg.func=this //改变this指向 console.log(arguments)//第一个参数为改变this指向,后续参数为传的参数 var arr=[] for(let i=1;i<arguments.length;i++){ const elem=arguments[i] arr.push(elem) } var res=objarg.func(...arr) delete(objarg.func)//不能改变原对象,所以进行删除 return res //call有返回值,最终需要返回 } Function.prototype.newCall=newCall //绑定到原型上,所有函数都可以调用 console.log("===",changeColor.newCall(obj,'red','blue')) //{color:'salmon',newColor1:'red',newColor2:'blue'}
- 手写call实现了,实现手写apply就只用修改传参方式不通的问题
//不用去分析获取到arr,直接解构arguments的第1项 var res=objarg.func(...arguments[1])
var newApply=function(objarg){ objarg=objarg||window objarg.func=this //改变this指向 var res=objarg.func(...arguments[1]) delete(objarg.func) return res }
- 手写bind 在其中可用到手写的newCall或newApply
var newBind=function(obj){ var _this=this var arr1=Array.prototype.slice.newCall(arguments,1) //在此可能或获取到一部分参数 var newFunc=function(){ // 在此也可获取到一部分参数 var arr2=Array.prototype.slice.newCall(arguments) var list=arr1.concat(arr2) if(this instanceof newFunc){ return _this.newApply(this,list)// 返回的函数可以作为构造函数使用,实现作为构造函数时,this就失效了 }else{ return _this.newApply(obj,list) } } return newFunc }