1.前言this关键字是JavaScript中最复杂的机制之一。它是一个特殊的关键字,自动定义在所有函数的范围内。对于没有花时间学习this机制的JavaScript开发者来说,this指向什么一直是一件很迷惑的事情。2.理解this学习this的第一步是理解this既不指向函数本身也不指向函数的词法作用域。你可能会被这样的解释误导,但它们都是错误的。this的值将根据函数的使用位置而变化。但是总有一个原则,就是JS中的this代表当前行为执行的主体。在JS中,主要研究的是函数中的this,但并不代表this只存在于函数中。这实际上是在功能上。调用时发生的绑定,它指向的内容完全取决于调用函数的位置。这个怎么区分呢?3、具体是谁,要分情况讨论。常见的有五种情况:1、函数执行时,先检查是否有“.”。在函数名前。如果有,谁在“.”前面,这就是谁;如果这是windowfunctionfn(){console.log(this);}varobj={fn:fn};fn();//this->windowobj.fn();//this->objfunctionsum(){fn();//this->window}sum();varoo={sum:function(){console.log(this);//this->oofn();//this->window}};oo.sum();2。自执行函数中的this永远是window(function(){//this->window})();~function(){//this->window}();3.将方法绑定到元素的事件。当事件被触发时,执行相应的方法。方法中的this是当前元素。除了IE6~8下的attachEvent(IE著名bug),DOM零级事件绑定SetoDiv.onclick=function(){//this->oDiv};DOM二级事件绑定oDiv.addEventListener("click",function(){//this->oDiv},false);在IE6~8下使用attachEvent,默认this指的是window对象oDiv.attachEvent("click",function(){//this->window});很多时候,我们都会遇到事件绑定,比如下面这个例子,在IE6~8下使用attachEvent,不必太实在functionfn(){console.log(this);}document.getElementById("div1").onclick=fn;//fn中的这个是#divldocument.getElementById("div1").onclick=function(){console.log(this);//this->#div1fn();//this->window};4.在构造函数模式下,类中(函数体中)出现的this.xxx=xxxthis是当前类函数的实例CreateJsPerson(name,age){//浏览器默认创建的对象是我们的实例p1->thisthis.name=name;//->p1.name=namethis.age=age;this.writeJs=function(){console.log("我的名字是"+this.name+",我会写Js");};//浏览器默认返回创建的实例}varp1=newCreateJsPerson("殷华志",48);必须注意一点:类中的某个属性值(方法),方法中的this取决于是否有“.”。在方法执行的时候放在方法前面,这样就可以知道这是谁了。查看以下示例以了解其含义。functionFn(){this.x=100;//this->f1this.getX=function(){console.log(this.x);//this->需要知道getX什么时候执行}}varf1=newFn;f1.getX();//->方法中的this是f1,所以f1.x=100varss=f1.getX;ss();//->方法中的this是window->undefined5。call、apply和bind我们先来看一个问题,下面的例子中如何将this绑定到obj上?varobj={name:"boatinthewaves"};functionfn(){console.log(this);//this=>window}fn();obj.fn();//->UncaughtTypeError:obj.fn不是函数如果直接绑定obj.fn(),程序会报错。这里我们应该使用fn.call(obj)来实现这个绑定obj。下面详细介绍call方法:call方法的作用:①首先我们让原型上的call方法执行。当call方法执行时,我们让fn方法中的this变为第一个参数值obj;然后执行fn函数。②call也可以传值。在严格模式和非严格模式下,得到的值是不同的。//非严格模式下varobj={name:"boatinthewaves"};functionfn(num1,num2){console.log(num1+num2);console.log(this);}fn.call(100,200);//this->100num1=200num2=undefinedfn.call(obj,100,200);//this->objnum1=100num2=200fn.call();//this->windowfn.call(null);//this->windowfn.call(undefined);//this->window//严格模式下的fn.call();//严格模式下this->undefinedfn.call(null);//严格模式下modeInstrictmodethis->nullfn.call(undefined);//Instrictmodethis->undefined**apply和call方法功能相同,都是用来改变方法的this关键字,执行方法,而第一个参数为null/undefined的规则在严格模式和非严格模式下是一样的。**两者唯一的区别:call给fn传参时,是一个一个传值,而apply不是一个一个传,而是把要传给fn的参数值放在一个中大批。操作。但是也相当于给fn的形参一个一个赋值。总结一句话:call的第二个参数开始接受一个参数列表,apply的第二个参数开始接受一个参数数组fn.call(obj,100,200);fn.apply(obj,[100,200]);在IE6~8下不兼容。和call/apply类似,用来改变this关键字,但是和两者有明显区别:fn.call(obj,1,2);//->改变this和执行fn函数一起完成fn.bind(obj,1,2);//->只是把fn中的this改成了obj,并且传了两个参数值1、2给fn,但是此时并没有执行fn函数vartempFn=fn.bind(obj,1,2);tempFn();//这样,函数fn被执行了,bind体现了预处理的思想:预先把fn的this改成我们想要的结果,并准备好相应的参数值,以后会用到,执行即可它直接。call和apply直接执行函数,而bind需要再次调用。vara={name:"Cherry",fn:function(a,b){console.log(a+b)}}varb=a.fn;b.bind(a,1,2)上面的代码没有执行,bind返回一个改变上下文的函数,我们要手动调用:b.bind(a,1,2)()//3必须声明a点:遇到第五种情况(调用apply和bind),前四种都是让步。4.箭头函数this指向箭头函数。顾名思义,一个“箭头”(=>)用于定义函数的新语法,但它优于传统函数。主要体现了两点:更短的函数和不绑定this。varobj={birth:1990,getAge:function(){varb=this.birth;//1990varfn=function(){returnnewDate().getFullYear()-this.birth;//this指向window或undefined};返回fn();}};现在,箭头函数彻底固定了this的指向,箭头函数没有自己的this,箭头函数的this在调用的时候也没有确定,而是在定义的时候对象就是它的this。也就是说,箭头函数的this取决于外层是否有函数。如果有,则外层函数的this就是内层箭头函数的this。如果没有,这就是窗口。
