隐式绑定关于这个,一般来说,谁调用了方法,方法的this就指向谁,如:functionfoo(){console.log(this.a)}vara=3;varobj={a:2,foo:foo};obj.foo();//输出2,因为是obj调用的foo,所以foo的this指向obj,如果obj.a=2存在多次调用,调用位置只有对象属性引用链的上一层或最后一层起作用,如:functionfoo(){console.log(this.a)}varobj2={a:42,foo:foo}varobj1={a:2,obj2:obj2}obj1.obj2.foo();//42隐式丢失this绑定最常见的问题之一是隐式绑定函数会丢失绑定的对象,也就是他用默认绑定来响应,从而将this绑定到全局对象或未定义,具体取决于它是否是严格模式。functionfoo(){console.log(this.a)}varobj1={a:2,foo:foo}varbar=obj1.foo;//函数别名!vara="oops,global";//a是全局对象的属性bar();//"oops,global"虽然bar是对obj.foo的引用,但实际上指的是foo函数本身,所以此时bar()实际上是一个没有任何修饰的函数调用,所以应用了默认绑定。传递回调函数时会出现更微妙、更常见、更意外的情况:functionfoo(){console.log(this.a)}functiondoFoo(fn){//fn其实是指foofn();//<--调用位置!}varobj={a:2,foo:foo}vara="oops,global";//a是全局对象的属性doFoo(obj.foo);//"oops,global"参数传递其实是隐式的赋值,所以当我们传入一个函数的时候,它也会被隐式赋值,所以结果和前面的例子一样。如果函数传入的是语言内置函数而不是自己声明的函数(比如setTimeout等),结果也是一样的,简单来说,显式绑定就是指定this,比如:call,apply,bind,newbinding,etc.hardbindingfunctionfoo(something){console.log(this.a,something)returnthis.a+something}varobj={a:2}varbar=function(){returnfoo.apply(obj,arguments)}varb=bar(3);//23console.log(b);//5这里简单说明一下:在bar函数中,foo使用apply函数绑定obj,也就是说,foo中的this会指向obj,同时使用arguments(传入参数个数不限)作为参数传入foo函数;所以当运行bar(3)时,先输出obj.a也就是2和传入的3,然后foo返回两者相加的值,所以b的值为5。同样,这个例子也可以使用bind:functionfoo(something){控制台。日志(这个.a,所以mething)returnthis.a+something}varobj={a:2}varbar=foo.bind(obj)varb=bar(3);//23console.log(b);//5newbindingsintraditionalclass-orientedlanguages中,当使用new初始化一个类时,会调用类中的构造函数,但是JS中的new机制其实和面向类和面向语言的函数完全不同。使用new调用函数,或者调用构造函数时,会自动执行以下操作:创建(或构造)一个全新的对象。新对象将被执行[[Prototype]]并且新对象将被绑定到函数调用的this上。如果函数没有返回另一个对象,new表达式中的函数将自动返回这个新对象如:functionfoo(a){this.a=a}varbar=newfoo(2);console.log(bar.a);//2在使用new调用foo(...)时,我们会构造一个新的对象,并在foo(...)调用中将其绑定到this上。new是调用函数时唯一可以影响thisbinding行为的方法,我们称它为newbinding。这个的优先级毫无疑问,默认绑定的优先级是四个规则中最高的,所以我们暂时可以忽略它。哪个优先级更高,隐式绑定还是显式绑定?我们来测试一下:functionfoo(a){console.log(this.a)}varobj1={a:2,foo:foo}varobj2={a:3,foo:foo}obj1.foo();//2obj2。foo();//3obj1.foo.call(obj2);//3obj2.foo.call(obj1);//2可以看出,display显式绑定的优先级更高,也就是说是否可以判断时首先要考虑是显式绑定。现在我们必须弄清楚谁拥有新绑定和隐式绑定的更高优先级:functionfoo(something){this.a=something}varobj1={foo:foo}varobj2={}obj1.foo(2);console.log(obj1.a);//2obj1.foo.call(obj2,3);console.log(obj2.a);//3varbar=newobj1.foo(4)console.log(obj1.a);//2console.log(bar.a);//4可以看到newbinding的优先级高于implicitbinding。但是谁有更高的优先级,新绑定还是显式绑定?functionfoo(something){this.a=something}varobj1={}varbar=foo.bind(obj1);bar(2);console.log(obj1.a);//2varbaz=newbar(3);控制台。log(obj1.a);//2console.log(baz.a);//3可以看到newbinding修改了hardbindingthis,所以newbinding的优先级高于显式绑定。在new中使用hard-boundfunctions的主要目的是预先设置函数的一些参数,这样在使用new进行初始化时就可以只传入其余的参数。bind(...)的一个功能是将除第一个参数(第一个参数用于绑定this)之外的所有参数传递给底层函数(这种技术称为“部分应用”,是一种“currying”)。例如:functionfoo(p1,p2){this.val=p1+p2;}//我们之所以使用null是因为在这个例子中我们不关心hard-boundthis是什么//无论如何,当使用new这将被修改varbar=foo.bind(null,'p1');varbaz=newbar('p2');baz.val;//p1p2}Currying:直觉上,currying声明“如果你修复这些参数,您将获得一个接受其余参数的函数”。所以对于一个有两个变量的函数yx,如果你固定y=2,你会得到一个有一个变量的函数2xThis。this在箭头函数中的应用并没有使用this的四个标准规则,而是根据外层(函数或全局)作用域来确定this。我们来看看箭头函数的词法作用域:functionfoo(){//返回一个箭头函数return(a)=>{//this继承自foo()console.log(this.a)};}varobj1={a:2};varobj2={a:3};varbar=foo.call(obj1);bar.call(obj2);//2,不是3!在foo()内部创建的箭头函数在调用时捕获foo()的this。由于foo()的this绑定了obj1,bar的this(指箭头函数)也会绑定到obj1,箭头函数的绑定不能修改。(new也不行!)综上所述,如果要确定一个正在运行的函数的this绑定,需要找到该函数的直接调用位置。找到后,可以应用以下四个规则来确定this的绑定对象。被新人召唤?绑定到新创建的对象。通过调用或应用(或绑定)调用?绑定到指定的对象。由上下文对象调用?绑定到该上下文对象。默认值:在严格模式下绑定到undefined,否则绑定到全局对象。
