'this' 关键字如何工作?何时使用?
我正在寻找一个清晰的解释,说明 \'this\' 关键字的作用以及如何正确使用它。它似乎表现得很奇怪,我不完全明白为什么。它是如何工作的,
我正在寻找对“this”关键字的作用以及如何正确使用它的清晰解释。
它的行为似乎很奇怪,我不完全明白为什么。
如何 this
工作以及何时使用?
下载声明: 本站所有软件和资料均为软件作者提供或网友推荐发布而来,仅供学习和研究使用,不得用于任何商业用途。如本站不慎侵犯你的版权请联系我,我将及时处理,并撤下相关内容!
-
引用 5楼
关键字
this
在 JavaScript 中的行为有所不同。在面向对象语言中,this
关键字指的是类的当前实例。在 JavaScript 中,的值this
由函数的调用上下文(context.function()
)及其调用位置决定。1. 在全球范围内使用时
当在全局上下文中使用时
this
,它绑定到全局对象(window
在浏览器中)document.write(this); //[object Window]
当您
this
在全局上下文中定义的函数内使用它时,this
仍然绑定到全局对象,因为该函数实际上是全局上下文的方法。function f1() { return this; } document.write(f1()); //[object Window]
以上
f1
是作为全局对象的方法。因此我们也可以在window
对象上调用它,如下所示:function f() { return this; } document.write(window.f()); //[object Window]
2. 在对象方法中使用时
在对象方法内部
this
使用this
将绑定到\'immediate\'封闭对象。var obj = { name: "obj", f: function () { return this + ":" + this.name; } }; document.write(obj.f()); //[object Object]:obj
上面我将“直接”一词放在双引号中。这是为了说明,如果您将对象嵌套在另一个对象中,则
this
它将绑定到直接父级。var obj = { name: "obj1", nestedobj: { name:"nestedobj", f: function () { return this + ":" + this.name; } } } document.write(obj.nestedobj.f()); //[object Object]:nestedobj
即使你将函数明确地作为方法添加到对象中,它仍然遵循上述规则,即
this
仍然指向直接父对象。var obj1 = { name: "obj1", } function returnName() { return this + ":" + this.name; } obj1.f = returnName; //add method to object document.write(obj1.f()); //[object Object]:obj1
3. 调用无上下文函数时
当您使用在
this
没有任何上下文(即不在任何对象上)调用的内部函数时,它将绑定到全局对象(window
在浏览器中)(即使该函数是在对象内部定义的)。var context = "global"; var obj = { context: "object", method: function () { function f() { var context = "function"; return this + ":" +this.context; }; return f(); //invoked without context } }; document.write(obj.method()); //[object Window]:global
使用函数尝试一切
我们也可以用函数来尝试上述方法。不过还是有一些区别。
-
上面我们使用对象字面量表示法向对象添加成员。我们可以通过使用
this
. 来指定函数,从而向函数添加成员。 -
对象字面量表示法会创建一个可以立即使用的对象实例。使用函数时,我们可能需要先使用
new
运算符创建其实例。 - 此外,在对象字面量方法中,我们可以使用点运算符显式地将成员添加到已定义的对象中。这只会添加到特定实例中。但是,我已将变量添加到函数原型中,以便它反映在函数的所有实例中。
下面我尝试了使用 Object 及上面所做的所有事情
this
,但首先创建函数而不是直接编写对象。/********************************************************************* 1. When you add variable to the function using this keyword, it gets added to the function prototype, thus allowing all function instances to have their own copy of the variables added. *********************************************************************/ function functionDef() { this.name = "ObjDefinition"; this.getName = function(){ return this+":"+this.name; } } obj1 = new functionDef(); document.write(obj1.getName() + "<br />"); //[object Object]:ObjDefinition /********************************************************************* 2. Members explicitly added to the function protorype also behave as above: all function instances have their own copy of the variable added. *********************************************************************/ functionDef.prototype.version = 1; functionDef.prototype.getVersion = function(){ return "v"+this.version; //see how this.version refers to the //version variable added through //prototype } document.write(obj1.getVersion() + "<br />"); //v1 /********************************************************************* 3. Illustrating that the function variables added by both above ways have their own copies across function instances *********************************************************************/ functionDef.prototype.incrementVersion = function(){ this.version = this.version + 1; } var obj2 = new functionDef(); document.write(obj2.getVersion() + "<br />"); //v1 obj2.incrementVersion(); //incrementing version in obj2 //does not affect obj1 version document.write(obj2.getVersion() + "<br />"); //v2 document.write(obj1.getVersion() + "<br />"); //v1 /********************************************************************* 4. `this` keyword refers to the immediate parent object. If you nest the object through function prototype, then `this` inside object refers to the nested object not the function instance *********************************************************************/ functionDef.prototype.nestedObj = { name: 'nestedObj', getName1 : function(){ return this+":"+this.name; } }; document.write(obj2.nestedObj.getName1() + "<br />"); //[object Object]:nestedObj /********************************************************************* 5. If the method is on an object's prototype chain, `this` refers to the object the method was called on, as if the method was on the object. *********************************************************************/ var ProtoObj = { fun: function () { return this.a } }; var obj3 = Object.create(ProtoObj); //creating an object setting ProtoObj //as its prototype obj3.a = 999; //adding instance member to obj3 document.write(obj3.fun()+"<br />");//999 //calling obj3.fun() makes //ProtoObj.fun() to access obj3.a as //if fun() is defined on obj3
4. 在构造函数中使用时
当函数作为构造函数使用时(即用
new
关键字调用时),this
函数体内部指向正在构造的新对象。var myname = "global context"; function SimpleFun() { this.myname = "simple function"; } var obj1 = new SimpleFun(); //adds myname to obj1 //1. `new` causes `this` inside the SimpleFun() to point to the // object being constructed thus adding any member // created inside SimipleFun() using this.membername to the // object being constructed //2. And by default `new` makes function to return newly // constructed object if no explicit return value is specified document.write(obj1.myname); //simple function
5. 在原型链上定义的函数内部使用时
如果该方法位于对象的原型链上,则
this
该方法内部引用调用该方法的对象,就好像该方法是在对象上定义的一样。var ProtoObj = { fun: function () { return this.a; } }; //Object.create() creates object with ProtoObj as its //prototype and assigns it to obj3, thus making fun() //to be the method on its prototype chain var obj3 = Object.create(ProtoObj); obj3.a = 999; document.write(obj3.fun()); //999 //Notice that fun() is defined on obj3's prototype but //`this.a` inside fun() retrieves obj3.a
6. call()、apply() 和 bind() 函数内部
-
所有这些方法都定义在
Function.prototype
. -
这些方法允许编写一次函数并在不同的上下文中调用它。换句话说,它们允许指定
this
在执行函数时将使用的值。它们还会在调用时接受要传递给原始函数的任何参数。 -
fun.apply(obj1 [, argsArray])
将其设置obj1
内部this
的值fun()
并调用fun()
传递的元素作为argsArray
其参数。 -
fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])
- 设置obj1
内部this
的值fun()
并调用fun()
传递arg1, arg2, arg3, ...
的参数。 -
fun.bind(obj1 [, arg1 [, arg2 [, arg3 [, ...]]]])
绑定到内部fun
的this
引用obj1
,并将参数fun
绑定到指定的参数arg1, arg2, arg3,...
. -
现在
apply
,call
和bind
一定已经很明显了。apply
允许将函数的参数指定为类似数组的对象,即具有数字length
属性和相应的非负整数属性的对象。而call
允许直接指定函数的参数。apply
和call
在指定的上下文中使用指定的参数立即调用该函数。另一方面,bind
只是返回与指定值和参数绑定的函数this
。我们可以通过将这个返回函数的引用分配给一个变量来捕获它,然后我们可以随时调用它。
function add(inc1, inc2) { return this.a + inc1 + inc2; } var o = { a : 4 }; document.write(add.call(o, 5, 6)+"<br />"); //15 //above add.call(o,5,6) sets `this` inside //add() to `o` and calls add() resulting: // this.a + inc1 + inc2 = // `o.a` i.e. 4 + 5 + 6 = 15 document.write(add.apply(o, [5, 6]) + "<br />"); //15 // `o.a` i.e. 4 + 5 + 6 = 15 var g = add.bind(o, 5, 6); //g: `o.a` i.e. 4 + 5 + 6 document.write(g()+"<br />"); //15 var h = add.bind(o, 5); //h: `o.a` i.e. 4 + 5 + ? document.write(h(6) + "<br />"); //15 // 4 + 5 + 6 = 15 document.write(h() + "<br />"); //NaN //no parameter is passed to h() //thus inc2 inside add() is `undefined` //4 + 5 + undefined = NaN</code>
7. 事件处理程序中的 this
-
当您将函数直接分配给元素的事件处理程序时,事件处理函数内部的直接使用
this
方法或通过传统的事件注册方法addeventListener
完成,onclick
. -
类似地,当您
this
直接在元素的事件属性(如<button onclick="...this..." >
)内部使用时,它指的是该元素。 -
但是通过在事件处理函数或事件属性中调用的其他函数间接使用
this
会解析为全局对象window
. -
当我们使用 Microsoft 的事件注册模型方法将函数附加到事件处理程序时,可以实现上述相同的行为
attachEvent
。它不是将函数分配给事件处理程序(从而使其成为元素的函数方法),而是在事件上调用该函数(实际上是在全局上下文中调用它)。
我建议最好在 JSFiddle 中尝试一下。
<script> function clickedMe() { alert(this + " : " + this.tagName + " : " + this.id); } document.getElementById("button1").addEventListener("click", clickedMe, false); document.getElementById("button2").onclick = clickedMe; document.getElementById("button5").attachEvent('onclick', clickedMe); </script> <h3>Using `this` "directly" inside event handler or event property</h3> <button id="button1">click() "assigned" using addEventListner() </button><br /> <button id="button2">click() "assigned" using click() </button><br /> <button id="button3" onclick="alert(this+ ' : ' + this.tagName + ' : ' + this.id);">used `this` directly in click event property</button> <h3>Using `this` "indirectly" inside event handler or event property</h3> <button onclick="alert((function(){return this + ' : ' + this.tagName + ' : ' + this.id;})());">`this` used indirectly, inside function <br /> defined & called inside event property</button><br /> <button id="button4" onclick="clickedMe()">`this` used indirectly, inside function <br /> called inside event property</button> <br /> IE only: <button id="button5">click() "attached" using attachEvent() </button>
8. ES6 箭头函数中的 this
在箭头函数中,
this
的行为将与普通变量类似:它将从其词法范围继承。this
箭头函数定义所在的函数的 将是箭头函数的this
.因此,这与以下行为相同:
(function(){}).bind(this)
请参阅以下代码:
const globalArrowFunction = () => { return this; }; console.log(globalArrowFunction()); //window const contextObject = { method1: () => {return this}, method2: function(){ return () => {return this}; } }; console.log(contextObject.method1()); //window const contextLessFunction = contextObject.method1; console.log(contextLessFunction()); //window console.log(contextObject.method2()()) //contextObject const innerArrowFunction = contextObject.method2(); console.log(innerArrowFunction()); //contextObject
-
上面我们使用对象字面量表示法向对象添加成员。我们可以通过使用