当前位置: 首页 > 科技观察

JavaScript对this

时间:2023-03-20 13:31:34 科技观察

的深入理解将this定义为函数运行时自动生成的内部对象,即调用函数的对象。(不一定是很精确的定义,但还是很容易理解)在大多数情况下,this的值是由函数的调用方式决定的,在执行时不能通过赋值来设置,在每次执行时值可能不同.全局执行环境(函数外)在全局执行环境中,无论是严格模式还是非严格模式,this总是指向全局对象(globalobject)。代码1console.log(this.document===document);//true//在浏览器中,window对象也是全局对象(globalobject)console.log(this===window);//truethis.a=37;console.log(window.a);//37函数执行环境(insidefunction)在函数执行环境中,this的值取决于函数的调用方式。调用函数主要有四种方式:函数直接调用对象方法调用构造函数调用call/apply/bind箭头函数(ES6)函数直接调用如下代码在非严格模式下执行时,this的值会指向全局目的;在严格模式下,this的值将默认为undefined。代码2/*非严格模式*/functionf1(){returnthis;}console.log(f1()===window);//true//innode;console.log(f1()===global);//true/*strictmode*/functionf2(){'usestrict'returnthis;}console.log(f1()===undefined);//truecall/apply/bind改变this点为call/applycall和applyusage很像,只是后面参数的输入形式不同。代码3functionadd(c,d){returnthis.a+this.b+c+d;}varo={a:1,b:3};//call的第一个参数是对象,也就是指向的对象以此来。下面的参数是函数argumentsobject的成员add.call(o,5,7);//1+3+5+7=16//call的第一个参数是object,也就是指向的对象这。下面的参数是数组,数组中的成员是函数参数对象成员add.apply(o,[10,20]);//1+3+10+20=34使用call和apply时,应该需要注意的是,当传入的第一个参数的值不是对象时,JavaScript会尝试使用ToObject操作将其转换为对象。代码4functionbar(){console.log(Object.prototype.toString.call(this));}bar.call(7);//[objectNumber]bind方法ECMAScript5引入了Function.prototype.bind。调用f.bind(someObject)将创建一个函数体和范围与f相同的函数,但在这个新函数中,无论函数如何调用,this都将永久绑定到bind的第一个参数。叫。https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind代码5functionf(){returnthis.a;}varg=f.bind({a:'azerty'});//生成绑定函数gconsole.log(g());//azertyvaro={a:10,f:f,g:g};console.log(o.f(),o.g());//10,azerty//需要注意的是绑定函数不能再bindvarh=g.bind({a:'foo'});console.log(h());//azerty,不会变成foo对象方法调用当调用函数作为对象中的方法时,它们的this是调用函数的对象。在下面的示例中,当调用o.f()时,函数内部的this将绑定到o对象。varprop=36;varo={prop:37,bar:function(){returnthis.prop;}};console.log(o.bar());//37构造函数调用代码6functionPerson(name,age){this.name=name;this.age=age;this.introduce=function(){console.log('Mynameis'+this.name+',I\'m'+this.age);};}varJoseph=newPerson('约瑟夫',19);Joseph.introduce();//"MynameisJoseph,I'm19"从上面的代码可以明显看出this是绑定到新建的对象上的。注意:当构造函数返回的默认值是this引用的对象时,可以手动设置返回其他对象。如果返回值不是对象,则返回this。(这句话好像不好理解,我们看下一个例子)。代码7functionFn2(){this.a=9;//deadcodereturn{a:10};}varo=newFn2();console.log(o.a);//10这个例子说明了构造函数什么时候返回一个对象,在thistimethis的值将成为此时返回的对象。'this.a=9'变成了僵尸代码。箭头函数在箭头函数(Arrowfunctions)中,this的值由封闭的执行环境决定。在全局环境中,它被分配了全局对象。https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functionsvarglobalObject=this;varfoo=(()=>this);console.log(foo()===globalObject);//true更重要的是,它和其他情况不同,不管函数怎么调用,上面this的值始终是全局对象。call/bind也不能改变它的值。代码8//作为对象方法调用varobj={foo:foo};console.log(obj.foo()===globalObject);//true//尝试通过调用console.log更改this的值(foo.call(obj)===globalObject);//true//this的值还没有变成obj//尝试使用bind改变this的值foofoo=foo.bind(obj);console.log(foo()===globalObject);//真实案例本文知识点已阅读。下面通过几个案例来检验一下自己的掌握程度。示例1varprop=36;varo={prop:37,bar1:function(){functionfoo1(){returnthis.prop;}returnfoo1;},bar2:function(){varfoo2=(()=>this.prop);//ES6箭头函数returnfoo2;}};console.log('result1:'+o.bar1()());//result1?console.log('result2:'+o.bar2()());//result2?varfn2=o.bar2;console.log('result3:'+fn2()());//result3?先揭秘答案:例子1result1=36,result2=37,result3=36我的理解是在result1中,o.bar1()的执行导致foo函数返回全局环境,然后执行变成在全局环境中执行,所以得到的值在全局环境中是36。结果2呢?因为这是在箭头函数中。它的值不会改变。所以this还是指向o。那为什么result3又变了呢?因为此时'varfn2=o.bar2'相当于重新定义了一个函数,this的值当然就变成了全局对象了。//相当于这个varfn2=function(){functionfoo1(){returnthis.prop;}returnfoo1;}fn2()();例2functionsum(a,b){returna+b;};varo={num:1,fn:function(){functionhandle(){returnthis.num=sum(this.num,this.num);}handle();}};console.log('result:'+o.fn());//结果?同样先揭晓答案:result=undefined,可以看到此时this指向的是window,不是o。这是一个比较容易掉进去的坑(一般认为是原语言设计的错误,被诟病很多)。看起来函数是通过对象方法调用的,但是细心的话还是可以看出来的。句柄函数的执行前面没有对象。在这种情况下,this指的是全局对象。解决方法也很简单。//1。取消handle函数的定义,直接使用thisfn2:function(){this.value=sum(this.value,this.value);//2},///2。使用变量保存外部函数的this。fn3:function(){varthat=this;//that==ofunctionhandle(){that.value=add(that.value,that.value);}handle();}