How does the “this” keyword work?
我注意到,似乎没有一个明确的解释说明什么是
我亲眼目睹了一些非常奇怪的行为,却不明白为什么会发生这种事。
我建议先阅读一下MikeWest在javascript(mirror)中的文章范围。这是一个极好的、友好的介绍,介绍了Javascript中的
一旦你开始习惯了
§11.1.1 The
this keywordThe
this keyword evaluates to the value of the ThisBinding of the current execution contextOk.
这个绑定是JavaScript解释器在评估JavaScript代码时维护的,比如一个特殊的CPU寄存器,它保存对对象的引用。当仅在三种不同情况中的一种情况下建立执行上下文时,解释器将更新此绑定:好的。1。初始全局执行上下文
这是在顶层评估的javascript代码的情况,例如,当直接在
1 2 3 4 5 | alert("I'm evaluated in the initial global execution context!"); setTimeout(function () { alert("I'm NOT evaluated in the initial global execution context."); }, 1); |
在初始全局执行上下文中评估代码时,将此绑定设置为全局对象
…直接打电话给
eval() 。此绑定保持不变;它与调用执行上下文的此绑定的值相同(§10.4.2(2)(a))。好的。…如果不是直接打电话给
eval() 。将此绑定设置为全局对象,如同在初始全局执行上下文(§10.4.2(1))中执行一样。好的。
§15.1.2.1.1定义了直接调用
调用函数时会发生这种情况。如果在对象上调用函数,例如在
之所以写"在大多数其他情况下",是因为有八个ecmascript 5内置函数允许在参数列表中指定此绑定。这些特殊函数采用所谓的
这些特殊的内置功能包括:好的。
Function.prototype.apply( thisArg, argArray ) Function.prototype.call( thisArg [ , arg1 [ , arg2, ... ] ] ) Function.prototype.bind( thisArg [ , arg1 [ , arg2, ... ] ] ) Array.prototype.every( callbackfn [ , thisArg ] ) Array.prototype.some( callbackfn [ , thisArg ] ) Array.prototype.forEach( callbackfn [ , thisArg ] ) Array.prototype.map( callbackfn [ , thisArg ] ) Array.prototype.filter( callbackfn [ , thisArg ] )
对于
在
这些是普通JavaScript的规则。当您开始使用javascript库(例如jquery)时,您可能会发现某些库函数操作EDOCX1的值(0)。这些JavaScript库的开发人员这样做是因为它倾向于支持最常见的用例,而库的用户通常认为这种行为更方便。当将引用
如果您想知道一个javascript库如何处理EDOCX1的值(0),那么这个库只是使用一个接受
1 2 3 4 | function doWork(callbackfn, thisArg) { //... if (callbackfn != null) callbackfn.call(thisArg); } |
我还没有提到一个特殊的案例。通过
1 2 3 4 5 6 7 8 | function MyType() { this.someData ="a string"; } var instance = new MyType(); // Kind of like the following, but there are more steps involved: // var instance = {}; // MyType.call(instance); |
箭头函数
arrow函数(在ecma6中引入)更改EDOCX1的作用域〔0〕。参见现有的规范问题,箭头函数与函数声明/表达式:它们是否等价/可交换?更多信息。但简而言之:好的。
Arrow functions don't have their own
this .... binding.
Instead, those identifiers are resolved in the lexical scope like any
other variable. That means that inside an arrow function,this ...refer(s) to the values ofthis in the environment
the arrow function is defined in.Ok.
为了好玩,用一些例子来测试你的理解
要显示答案,请将鼠标移到淡黄色框上。好的。
在标记的行上,
window —标记行在初始全局执行上下文中进行评估。好的。< /块引用>
1
2
3 if (true) {
// What is `this` here?
}
执行
obj —当对对象调用函数时,此绑定被设置为对象。好的。< /块引用>
1
2
3
4
5
6
7
8
9
10
11
12 var obj = {
someData:"a string"
};
function myFun() {
return this // What is `this` here?
}
obj.staticFunction = myFun;
console.log("this is window:", obj.staticFunction() == window);
console.log("this is obj:", obj.staticFunction() == obj);好的。
在标记的行上,
window 在本例中,javascript解释器输入函数代码,但由于没有对对象调用
myFun /obj.myMethod ,因此将此绑定设置为window 。这与python不同,在python中,访问方法(
obj.myMethod 创建绑定方法对象。好的。< /块引用>
1
2
3
4
5
6
7
8 var obj = {
myMethod: function () {
return this; // What is `this` here?
}
};
var myFun = obj.myMethod;
console.log("this is window:", myFun() == window);
console.log("this is obj:", myFun() == obj);好的。
在标记的行上,
window 这件事很棘手。评估评估评估代码时,
this 为obj 。但是,在eval代码中,没有对对象调用myFun ,因此调用时将此绑定设置为window 。好的。< /块引用>
1
2
3
4
5
6
7
8 function myFun() {
return this; // What is `this` here?
}
var obj = {
myMethod: function () {
eval("myFun()");
}
};
在标记的行上,
obj 行
myFun.call(obj); 正在调用特殊的内置函数Function.prototype.call() ,它接受thisArg 作为第一个参数。好的。< /块引用>
1
2
3
4
5
6
7
8 function myFun() {
return this; // What is `this` here?
}
var obj = {
someData:"a string"
};
console.log("this is window:", myFun.call(obj) == window);
console.log("this is obj:", myFun.call(obj) == obj);好的。
好啊。
与其他语言相比,在javascript中,
1。在全局上下文中使用时好的。
在全局上下文中使用
1 | document.write(this); //[object Window] |
当在全局上下文中定义的函数内使用
1 2 3 4 5 | function f1() { return this; } document.write(f1()); //[object Window] |
上面的
1 2 3 4 5 6 | function f() { return this; } document.write(window.f()); //[object Window] |
2。在对象方法内部使用时好的。
在对象方法中使用
1 2 3 4 5 6 7 | var obj = { name:"obj", f: function () { return this +":" + this.name; } }; document.write(obj.f()); //[object Object]:obj |
上面我已经用双引号将单词immediate括起来了。要强调的是,如果将对象嵌套在另一个对象中,那么
1 2 3 4 5 6 7 8 9 10 11 | var obj = { name:"obj1", nestedobj: { name:"nestedobj", f: function () { return this +":" + this.name; } } } document.write(obj.nestedobj.f()); //[object Object]:nestedobj |
即使您将函数显式地作为一个方法添加到对象中,它仍然遵循上述规则,即
1 2 3 4 5 6 7 8 9 10 | var obj1 = { name:"obj1", } function returnName() { return this +":" + this.name; } obj1.f = returnName; //add method to object document.write(obj1.f()); //[object Object]:obj1 |
三。调用无上下文函数时好的。
当您在没有任何上下文(即不在任何对象上)调用的函数内部使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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和
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | /********************************************************************* 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。在构造函数函数内部使用时。好的。
当函数用作构造函数时(即用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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。当在原型链上定义的函数内部使用时好的。
如果该方法位于对象的原型链上,则该方法内部的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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 设置为fun() 内的this 的值,并称argsArray 的fun() 传递元素为其参数。fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]]) —将obj1 设置为fun() 内的this 的值,并称fun() 通过arg1, arg2, arg3, ... 作为其论据。fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]]) —返回对函数fun 的引用,其中this inside fun绑定到obj1 上,fun 的参数绑定到指定的arg1, arg2, arg3,... 上。- 到目前为止,
apply 、call 和bind 之间的差别肯定已经很明显了。apply 允许指定参数作为类似数组的对象,即具有数字length 属性和相应的非负整数属性的对象。而call 允许直接为函数指定参数。apply 和call 都立即在指定的上下文和指定的参数中调用函数。另一方面,bind 只返回绑定到指定this 值和参数的函数。我们可以通过将返回函数赋给变量来捕获对它的引用,稍后我们可以随时调用它。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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</wyn> |
7。
- 当您将函数直接分配给元素的事件处理程序时,直接在事件处理函数内部使用
this 是指相应的元素。这种直接的函数分配可以使用addeventListener 方法,也可以通过传统的事件注册方法(如onclick 方法)来完成。 - 同样,当您直接在元素的事件属性(如
中)内使用 this 时,它指的是元素。 - 但是,通过事件处理函数或事件属性内部调用的其他函数间接使用
this 可以解析为全局对象window 。 - 当我们使用Microsoft的事件注册模型方法
attachEvent 将函数附加到事件处理程序时,实现了相同的上述行为。它不是将函数分配给事件处理程序(从而生成元素的函数方法),而是对事件调用函数(在全局上下文中有效地调用它)。
我建议最好在jfiddle中尝试一下。好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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); Using `this`"directly" inside event handler or event property <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> Using `this`"indirectly" inside event handler or event property <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> |
好啊。
javascript的
考虑以下功能:
1 2 3 4 5 | function foo() { console.log("bar"); console.log(this); } foo(); // calling the function |
请注意,我们是在正常模式下运行的,即不使用严格模式。
在浏览器中运行时,EDOCX1的值(0)将记录为
如果在node.js等环境中运行这段代码,
现在,如果我们通过在函数声明的开头添加语句
在下面的例子中,我们将看到如何操纵
有不同的方法可以做到这一点。如果您已经在诸如
1 2 3 4 5 6 | var myObj = {key:"Obj"}; myObj.logThis = function () { // I am a method console.log(this); } myObj.logThis(); // myObj is logged |
如果
注意,如果一个方法存储(或者更确切地说,复制)在另一个变量中,那么对
1 2 3 4 5 | // continuing with the previous code snippet var myVar = myObj.thisMethod; myVar(); // logs either of window/global/undefined based on mode of operation |
考虑到更普遍的实际情况:
1 2 3 4 | var el = document.getElementById('idOfEl'); el.addEventListener('click', function() { console.log(this) }); // the function called by addEventListener contains this as the reference to the element // so clicking on our element would log that element itself |
考虑一个javascript中的构造函数函数:
1 2 3 4 5 6 7 8 9 10 | function Person (name) { this.name = name; this.sayHello = function () { console.log ("Hello", this); } } var awal = new Person("Awal"); awal.sayHello(); // In `awal.sayHello`, `this` contains the reference to the variable `awal` |
这是怎么工作的?好吧,让我们看看当我们使用
很简单,嗯?
请注意,官方的ecmascript规范没有说明此类函数是实际的
所以,是的,因为
所有函数都继承自全局
1 2 3 | function foo () { console.log (this, arguments); } var thisArg = {myObj:"is cool"}; foo.call(thisArg, 1, 2, 3); |
这是使用
"这"是关于范围的。每个函数都有自己的作用域,因为JS中的所有内容都是一个对象,所以即使函数也可以使用"this"将一些值存储到自身中。oop 101告诉我们"这"只适用于对象的实例。因此,每次执行一个函数时,该函数的一个新"实例"都具有"this"的新含义。
大多数人在匿名闭包函数中尝试使用"this"时会感到困惑,比如:
1 2 3 4 5 6 | (function(value) { this.value = value; $('.some-elements').each(function(elt){ elt.innerHTML = this.value; // uh oh!! possibly undefined }); })(2); |
因此,在这里,在每个()中,"this"不包含您期望的"value"(从它上面的
1 | this.value = value; |
)。因此,为了克服这个(没有双关语)问题,开发人员可以:
1 2 3 4 5 6 7 | (function(value) { var self = this; // small change self.value = value; $('.some-elements').each(function(elt){ elt.innerHTML = self.value; // phew!! == 2 }); })(2); |
试试看,你会开始喜欢这种编程模式的
由于这篇文章的内容增加了,我为
我们使用这个词的方式和我们使用英语等自然语言的代词的方式类似:"约翰跑得很快,因为他想赶火车。"相反,我们可以写"约翰想赶火车"。
1 2 3 4 5 6 7 8 9 10 11 12 | var person = { firstName:"Penelope", lastName:"Barrymore", fullName: function () { // We use"this" just as in the sentence above: console.log(this.firstName +"" + this.lastName); // We could have also written: console.log(person.firstName +"" + person.lastName); } } |
在对象调用定义它的函数之前,不会为
当
当:1)我们借用一个使用
在ECMA脚本6中定义,arrow函数采用来自封闭(函数或全局)范围。
1 2 3 4 5 6 7 8 9 10 11 12 | function foo() { // return an arrow function return (a) => { // `this` here is lexically inherited from `foo()` console.log(this.a); }; } var obj1 = { a: 2 }; var obj2 = { a: 3 }; var bar = foo.call(obj1); bar.call( obj2 ); // 2, not 3! |
虽然arrow函数提供了一种使用
参考文献:
javascript中的
如果未定义显式所有者,则引用最顶层的所有者窗口对象。
如果我做到了
1 2 3 | function someKindOfFunction() { this.style = 'foo'; } |
在后一种情况下,您只引用函数,而不将其移交给元素。因此,
javascript中的每个functionexecution context都有一个scopecontextthis parameter that is set by:
无论作用域上下文是什么,都由"this"引用。
您可以使用
默认情况下,当在DOM元素上引发事件后调用callbacklistener时,函数的这个值就是dom元素,这会让大多数初学者感到困惑。
jquery使得使用jquery.proxy进行更改变得很简单。
这是
以下是总结:
全球这
在浏览器中,在全局范围内,
this 是window 对象。1
2
3
4
5<script type="text/javascript">
console.log(this === window); // true
var foo ="bar";
console.log(this.foo); //"bar"
console.log(window.foo); //"bar"在使用repl的
node 中,this 是顶部命名空间。你可以把它称为global 。1
2
3
4
5
6
7>this
{ ArrayBuffer: [Function: ArrayBuffer],
Int8Array: { [Function: Int8Array] BYTES_PER_ELEMENT: 1 },
Uint8Array: { [Function: Uint8Array] BYTES_PER_ELEMENT: 1 },
...
>global === this
true在从脚本执行的
node 中,全局范围内的this 以空对象开始。与global 不同1
2
3\\test.js
console.log(this); \\ {}
console.log(this === global); \\ fasle函数此
除了在dom事件处理程序的情况下,或者当提供
1 2 3 4 5 6 7 8 9 10 | <script type="text/javascript"> foo ="bar"; function testThis() { this.foo ="foo"; } console.log(this.foo); //logs"bar" testThis(); console.log(this.foo); //logs"foo" |
如果您使用
1 2 3 4 5 6 7 8 9 10 | <script type="text/javascript"> foo ="bar"; function testThis() { "use strict"; this.foo ="foo"; } console.log(this.foo); //logs"bar" testThis(); //Uncaught TypeError: Cannot set property 'foo' of undefined |
如果使用
1 2 3 4 5 6 7 8 9 10 11 12 | <script type="text/javascript"> foo ="bar"; function testThis() { this.foo ="foo"; } console.log(this.foo); //logs"bar" new testThis(); console.log(this.foo); //logs"bar" console.log(new testThis().foo); //logs"foo" |
- 原型本
您创建的函数将成为函数对象。它们会自动获得一个特殊的
1 2 3 4 5 6 7 8 | function Thing() { console.log(this.foo); } Thing.prototype.foo ="bar"; var thing = new Thing(); //logs"bar" console.log(thing.foo); //logs"bar" |
在
1 2 3 4 5 6 7 8 9 | function Thing() { this.things = []; } var thing1 = new Thing(); var thing2 = new Thing(); thing1.things.push("foo"); console.log(thing1.things); //logs ["foo"] console.log(thing2.things); //logs [] |
- 对象此
您可以在对象的任何函数中使用
1 2 3 4 5 6 7 8 | var obj = { foo:"bar", logFoo: function () { console.log(this.foo); } }; obj.logFoo(); //logs"bar" |
- DOM事件
在HTML DOM事件处理程序中,
1 2 3 4 5 6 7 8 9 10 | function Listener() { document.getElementById("foo").addEventListener("click", this.handleClick); } Listener.prototype.handleClick = function (event) { console.log(this); //logs"" } var listener = new Listener(); document.getElementById("foo").click(); |
除非你在上下文中
1 2 3 4 5 6 7 8 9 10 | function Listener() { document.getElementById("foo").addEventListener("click", this.handleClick.bind(this)); } Listener.prototype.handleClick = function (event) { console.log(this); //logs Listener {handleClick: function} } var listener = new Listener(); document.getElementById("foo").click(); |
- 这个HTML
在可以放置javascript的HTML属性中,
1 2 | <script type="text/javascript"> document.getElementById("foo").click(); //logs <div id="foo"... |
- 这个时代
您可以使用
1 2 3 4 5 6 7 8 9 | function Thing () { } Thing.prototype.foo ="bar"; Thing.prototype.logFoo = function () { eval("console.log(this.foo)"); //logs"bar" } var thing = new Thing(); thing.logFoo(); |
- 用这个
您可以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 | function Thing () { } Thing.prototype.foo ="bar"; Thing.prototype.logFoo = function () { with (this) { console.log(foo); foo ="foo"; } } var thing = new Thing(); thing.logFoo(); // logs"bar" console.log(thing.foo); // logs"foo" |
- jQuery
jquery在很多地方都会让
1 2 3 4 5 6 7 8 9 10 | <script type="text/javascript"> $(".foo").each(function () { console.log(this); //logs <div class="foo... }); $(".foo").on("click", function () { console.log(this); //logs <div class="foo... }); $(".foo").each(function () { this.click(); }); |
关于
在javascript中温和地解释"this"关键字
在识别
Where is
this taken from?
但一定要问问自己:
How is the function invoked?
对于箭头函数(上下文透明的特殊情况),请自问:
What value has
this where the arrow function is defined?
这种心态在处理
关于"this"关键字在JavaScript中的解释方式有很多困惑。希望这篇文章能让所有这些都一劳永逸。还有更多。请仔细阅读整篇文章。请注意,这篇文章很长。好的。
不管使用它的上下文是什么,"这个"总是引用JavaScript中的"当前对象"。但是,根据上下文,"当前对象"是不同的。上下文可能正好是以下6个上下文中的1个:好的。
下面逐一描述每个上下文:好的。
全局上下文(即在所有函数之外):好的。
在所有功能之外(即在全局上下文中),"当前对象(因此"this"的值)始终是浏览器的"窗口"对象。好的。
内部直接"非绑定函数"调用:好的。
在直接的"非绑定函数"调用中,调用函数调用成为"当前对象"(因此"this"的值)。如果在没有显式当前对象的情况下调用函数,则当前对象是"window"对象(对于非严格模式)或未定义(对于严格模式)。中定义的任何函数(或变量)全局上下文自动成为"窗口"对象的属性。例如,假设函数在全局上下文中定义为好的。
1 2 3 | function UserDefinedFunction(){ alert(this) } |
它将成为窗口对象的属性,就好像您已经定义了它作为好的。
1 2 3 | window.UserDefinedFunction=function(){ alert(this) } |
在"非严格模式"下,直接通过"userDefinedFunction()"调用/调用此函数将自动调用/调用它是"window.userDefinedFunction()"使"window"成为"用户定义函数"中的"当前对象"(以及"this"的值)。在"非严格模式"中调用此函数将导致以下结果好的。
1 | UserDefinedFunction() // displays [object Window] as it automatically gets invoked as window.UserDefinedFunction() |
在"严格模式"下,直接通过"userDefinedFunction()"将"not"自动调用/调用它为"window.userDefinedFunction()",因此"current"对象"(和"this"的值)"用户定义函数"应未定义。在"严格模式"中调用此函数将导致以下结果好的。
1 | UserDefinedFunction() // displays undefined |
但是,使用window对象显式调用它将导致以下好的。
1 | window.UserDefinedFunction() //"always displays [object Window] irrespective of mode." |
让我们来看另一个例子。请看下面的代码好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | function UserDefinedFunction() { alert(this.a +"," + this.b +"," + this.c +"," + this.d) } var o1={ a:1, b:2, f:UserDefinedFunction } var o2={ c:3, d:4, f:UserDefinedFunction } o1.f() // Shall display 1,2,undefined,undefined o2.f() // Shall display undefined,undefined,3,4 |
在上面的示例中,我们看到当"userDefinedFunction"是通过O1调用,"this"的值为O1,并且显示其属性"A"和"B"的值。价值其中"c"和"d"如o1所示未定义。不定义这些属性好的。
同样,当通过O2调用"userdefinedFunction"时,"this"获取O2值,并显示其属性"c"和"d"的值。"a"和"b"的值显示为未定义,因为O2没有定义这些属性。好的。
在通过functionname.call和functionname.apply的间接"非绑定函数"调用中:好的。
当通过调用"非绑定函数"时functionname.call或functionname.apply,将"当前对象"(因此"this")的值设置为传递给call/apply的"this"参数(第一个参数)。下面的代码演示了相同的内容。好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | function UserDefinedFunction() { alert(this.a +"," + this.b +"," + this.c +"," + this.d) } var o1={ a:1, b:2, f:UserDefinedFunction } var o2={ c:3, d:4, f:UserDefinedFunction } UserDefinedFunction.call(o1) // Shall display 1,2,undefined,undefined UserDefinedFunction.apply(o1) // Shall display 1,2,undefined,undefined UserDefinedFunction.call(o2) // Shall display undefined,undefined,3,4 UserDefinedFunction.apply(o2) // Shall display undefined,undefined,3,4 o1.f.call(o2) // Shall display undefined,undefined,3,4 o1.f.apply(o2) // Shall display undefined,undefined,3,4 o2.f.call(o1) // Shall display 1,2,undefined,undefined o2.f.apply(o1) // Shall display 1,2,undefined,undefined |
上面的代码清楚地显示了"this"值对于任何"non"绑定函数"可以通过调用/应用进行更改。此外,如果"this"参数未显式传递给call/apply,"current object"(因此,"this")的值在非严格模式下设置为"window",在严格模式下设置为"undefined"。好的。
在"bound function"调用中(即通过调用functionname.bind绑定的函数):好的。
绑定函数是其"this"值固定的。下面的代码演示了"this"在有界函数好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | function UserDefinedFunction() { alert(this.a +"," + this.b +"," + this.c +"," + this.d) } var o1={ a:1, b:2, f:UserDefinedFunction, bf:null } var o2={ c:3, d:4, f:UserDefinedFunction, bf:null } var bound1=UserDefinedFunction.bind(o1); // permanantly fixes"this" value of function"bound1" to Object o1 bound1() // Shall display 1,2,undefined,undefined var bound2=UserDefinedFunction.bind(o2); // permanantly fixes"this" value of function"bound2" to Object o2 bound2() // Shall display undefined,undefined,3,4 var bound3=o1.f.bind(o2); // permanantly fixes"this" value of function"bound3" to Object o2 bound3() // Shall display undefined,undefined,3,4 var bound4=o2.f.bind(o1); // permanantly fixes"this" value of function"bound4" to Object o1 bound4() // Shall display 1,2,undefined,undefined o1.bf=UserDefinedFunction.bind(o2) // permanantly fixes"this" value of function"o1.bf" to Object o2 o1.bf() // Shall display undefined,undefined,3,4 o2.bf=UserDefinedFunction.bind(o1) // permanantly fixes"this" value of function"o2.bf" to Object o1 o2.bf() // Shall display 1,2,undefined,undefined bound1.call(o2) // Shall still display 1,2,undefined,undefined."call" cannot alter the value of"this" for bound function bound1.apply(o2) // Shall still display 1,2,undefined,undefined."apply" cannot alter the value of"this" for bound function o2.bf.call(o2) // Shall still display 1,2,undefined,undefined."call" cannot alter the value of"this" for bound function o2.bf.apply(o2) // Shall still display 1,2,undefined,undefined."apply" cannot alter the value of"this" for bound function |
如上述代码所示,"此"值表示任何"绑定函数"不能通过调用/应用更改。此外,如果"this"参数未显式传递给bind,"当前对象"(因此,"this")的值在非严格模式和"未定义"严格模式。还有一件事。绑定已绑定的函数不会更改"this"的值。它仍然被设置为第一个绑定函数设置的值。好的。
通过"新建"创建对象时:好的。
在构造函数函数内部,"当前对象"(因此"this")引用当前正在创建的对象通过"new"而不管函数的绑定状态如何。然而如果构造函数是绑定函数,则应使用作为绑定函数集的预定义参数集。好的。
在内联DOM事件处理程序内:好的。
请看下面的HTML代码段好的。
1 2 | <button onclick='this.style.color=white'>Hello World</button> Hello World |
上述示例中的"this"指的是"button"元素和"DIV"元素。好的。
在第一个示例中,按钮的字体颜色应设置为单击时为白色。好的。
在第二个示例中,单击"div"元素时,它应用第二个参数调用OnDivClick函数引用单击的DIV元素。然而,"这个"的价值OnDivClick中不应引用单击的DIV元素。应设置为"窗口对象"或分别在非严格和严格模式下"未定义"(如果OnDivClick是未绑定函数)或设置为预定义的绑定值(如果OnDivClick是绑定函数)好的。
以下是对整篇文章的总结好的。
在全局上下文中,"this"始终指"window"对象好的。
每当调用函数时,都会在对象("当前对象")。如果未显式提供当前对象,当前对象是非严格的"窗口对象"模式和"未定义"默认为严格模式。好的。
非绑定函数中"this"的值是对调用该函数的上下文中的对象的引用("当前对象")。好的。
非绑定函数中"this"的值可以由重写调用并应用函数的方法。好的。
对于绑定函数,"this"的值是固定的,不能由函数的调用和应用方法重写。好的。
绑定和已绑定函数不会更改"this"的值。它仍然被设置为第一个绑定函数设置的值。好的。
构造函数中"this"的值是已创建并初始化好的。
内联DOM事件处理程序中"this"的值是引用为其提供事件处理程序的元素。好的。
好啊。
丹尼尔,太棒了!在事件处理程序的情况下,这里有两个单词和一个很好的
换句话说,在javascript中,
对于事件处理程序:内联事件处理程序(如
- 6
el.onclick = function () {this.style.color = '#fff';} // obj el.onclick = function() {doSomething();} // In the doSomething -
Windowel.addEventListener('click',foo,false) // in the foo - obj el.attachEvent('onclick, function () { // this }') // window, all the
compliance to IE :)
这是我见过的最好的解释。清楚地理解javascripts
The this reference ALWAYS refers to (and holds the value of) an
object—a singular object—and it is usually used inside a function or a
method, although it can be used outside a function in the global
scope. Note that when we use strict mode, this holds the value of
undefined in global functions and in anonymous functions that are not
bound to any object.
有四种情况会让人困惑:
他给出了代码示例、解释和我认为非常有用的代码修复。
在伪经典术语中,许多讲座教授"this"关键字的方式是将其作为类或对象构造函数实例化的对象。每次从一个类构造一个新对象时,想象一下在hood下会创建并返回一个"this"对象的本地实例。我记得它是这样教的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | function Car(make, model, year) { var this = {}; // under the hood, so to speak this.make = make; this.model = model; this.year = year; return this; // under the hood } var mycar = new Car('Eagle', 'Talon TSi', 1993); // ========= under the hood var this = {}; this.make = 'Eagle'; this.model = 'Talon TSi'; this.year = 1993; return this; |
如果您不完全理解JS,那么很难很好地掌握它,或者写得比它中的任何琐碎内容都多。你不能只花一点点钱去尝试一下:)我认为开始使用JS的最好方法是首先观看Douglas Crockford的视频讲座-http://yuiblog.com/crockford/,它涵盖了这个和那个,以及JS的所有其他方面。
"this"的值取决于执行函数的"context"。上下文可以是任何对象或全局对象,即窗口。
因此,"this"的语义不同于传统的OOP语言。它会导致问题:1。当一个函数传递给另一个变量(很可能是回调)时;和2。当从类的成员方法调用闭包时。
在这两种情况下,这都设置为"窗口"。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | var val ="window.val" var obj = { val:"obj.val", innerMethod: function () { var val ="obj.val.inner", func = function () { var self = this; return self.val; }; return func; }, outerMethod: function(){ return this.val; } }; //This actually gets executed inside window object console.log(obj.innerMethod()()); //returns window.val //Breakdown in to 2 lines explains this in detail var _inn = obj.innerMethod(); console.log(_inn()); //returns window.val console.log(obj.outerMethod()); //returns obj.val |
上面我们创建了3个同名"val"的变量。一个在全球范围内,一个在obj内部,另一个在obj内部。javascript通过从本地go global向上搜索作用域链来解析特定上下文中的标识符。
很少有地方能区分
1 2 3 4 5 6 7 8 9 10 11 12 13 | var status = 1; var helper = { status : 2, getStatus: function () { return this.status; } }; var theStatus1 = helper.getStatus(); //line1 console.log(theStatus1); //2 var theStatus2 = helper.getStatus; console.log(theStatus2()); //1 |
执行第1行时,javascript为函数调用建立一个执行上下文(ec),将
1 2 3 4 5 6 7 8 9 10 11 12 13 | function Person(name){ this.personName = name; this.sayHello = function(){ return"Hello" + this.personName; } } var person1 = new Person('Scott'); console.log(person1.sayHello()); //Hello Scott var person2 = new Person('Hugh'); var sayHelloP2 = person2.sayHello; console.log(sayHelloP2()); //Hello undefined |
执行新的
1 2 3 4 5 6 7 8 9 10 11 12 13 | function testFunc() { this.name ="Name"; this.myCustomAttribute ="Custom Attribute"; return this; } var whatIsThis = testFunc(); console.log(whatIsThis); //window var whatIsThis2 = new testFunc(); console.log(whatIsThis2); //testFunc() / object console.log(window.myCustomAttribute); //Custom Attribute |
如果我们错过了
如果事件处理程序是内联的,那么
1 2 3 4 5 6 7 | <script type="application/javascript"> function click_handler() { alert(this); // alerts the window object } <button id='thebutton' onclick='click_handler()'>Click me!</button> |
通过javascript添加事件处理程序时,
- 您还可以使用
.apply() .call() 和.bind() 来操纵上下文。 - jquery代理是另一种方法,可以用来确保函数中的这个值是您想要的值。(检查是否理解$.proxy()、jquery.proxy()的用法)
- 在javascript中,
var that = this 是什么意思?
关于这个关键字的一些信息
让我们将
1 | console.log(this) |
在客户端/浏览器中,
1 | console.log(this === window) // true |
和
在server/node/javascript运行时,
1 2 | console.log(this === module.exports) // true console.log(this === exports) // true |
记住,
这对谁有帮助?(在javascript中,"this"最令人困惑的是,它通常不链接到您的对象,而是链接到当前的执行范围——这可能并不完全是它的工作方式,但对我来说总是这样——请参阅本文以获得完整的解释)
我对
查看javascript的一种方法是查看只有一种方法可以调用函数1。它是好的。
1 | functionObject.call(objectForThis, arg0, arg1, arg2, ...); |
总是有一些值提供给
其他的都是
所以,其他一切都可以用它如何翻译成
如果您只是调用一个函数,那么
1 2 3 4 5 | function foo() { console.log(this); } foo(); // this is the window object |
好的。
换言之,好的。
1 | foo(); |
被有效地转化为好的。
1 | foo.call(window); |
请注意,如果使用严格模式,那么
1 2 3 4 5 6 7 | 'use strict'; function foo() { console.log(this); } foo(); // this is the window object |
好的。
这意味着什么好的。
换言之,好的。
1 | foo(); |
被有效地转化为好的。
1 | foo.call(undefined); |
在javascript中,有像
当与右边的函数和左边的对象一起使用时,
例子好的。
1 2 3 4 5 6 7 8 | const bar = { name: 'bar', foo() { console.log(this); }, }; bar.foo(); // this is bar |
好的。
换句话说,
注意,函数是如何创建的并不重要(主要是…)。所有这些都会产生相同的结果好的。
1 2 3 4 5 6 7 8 9 10 11 12 | const bar = { name: 'bar', fn1() { console.log(this); }, fn2: function() { console.log(this); }, fn3: otherFunction, }; function otherFunction() { console.log(this) }; bar.fn1(); // this is bar bar.fn2(); // this is bar bar.fn3(); // this is bar |
好的。
再说一遍,这些都只是句法上的糖分好的。
1 2 3 | { const temp = bar.fn1; temp.call(bar); } { const temp = bar.fn2; temp.call(bar); } { const temp = bar.fn3; temp.call(bar); } |
另一个褶皱是原型链。使用
定义对象原型有多种方法,2019年最常见的是
现在。假设我们在调用另一个函数之前创建一个显式设置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | function foo() { console.log(this); } function bar() { const objectForThis = {name: 'moo'} foo.call(objectForThis); // explicitly passing objectForThis } const obj = { bar, }; obj.bar(); |
好的。
翻译使用
这就是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | function foo() { console.log(this); } const bar = foo.bind({name: 'moo'}); // bind created a new invisible function that calls foo with the bound object. bar(); // the objectForThis we are passing to bar here is ignored because // the invisible function that bind created will call foo with with // the object we bound above bar.call({name: 'other'}); |
好的。
注意,如果
1 2 3 4 5 | function bind(fn, objectForThis) { return function(...args) { return fn.call(objectForthis, ...args); }; } |
然后我们可以这样称呼它好的。
1 2 3 4 5 | function foo() { console.log(this); } const bar = bind(foo, {name:'abc'}); |
arrow函数,
1 | const a = () => {console.log(this)}; |
是一样的好的。
1 2 | const tempFn = function() {console.log(this)}; const a = tempFn.bind(this); |
就像
所以,就像上面的规则一样好的。
1 | const a = () => { console.log(this); } // this is the global object |
1 2 | 'use strict'; const a = () => { console.log(this); } // this is undefined |
1 2 3 4 5 6 7 8 9 | function foo() { return () => { console.log(this); } } const obj = { foo, }; const b = obj.foo(); b(); |
上面的代码翻译成好的。
1 2 3 4 5 6 7 8 9 10 11 12 | function foo() { function tempFn() { console.log(this); } return tempFn.bind(this); } const obj = { foo, }; const b = obj.foo(); b.call(window or undefined if strict mode); |
1
1 | functionName.apply(objectForThis, arrayOfArgs); |
但是从概念上讲,从ES6开始,你甚至可以将其转化为好的。
1 | functionName.call(objectForThis, ...arrayOfArgs); |
好啊。
这种作用域的用法就像这样
1 2 3 4 5 6 7 8 9 | <script type="text/javascript" language="javascript"> $('#tbleName tbody tr').each(function{ var txt=''; txt += $(this).find("td").eq(0).text(); \\same as above but synatx different var txt1=''; txt1+=$('#tbleName tbody tr').eq(0).text(); alert(txt1) }); |
txt1和txt值相同在上面的例子中$(this)=$('tblename tbody tr')相同
javascript中的"this"关键字是什么
这个关键字指的是一个对象,这个对象正在执行当前位的javascript代码。
换句话说,执行时的每个javascript函数都有一个对当前执行上下文的引用,称为this。执行上下文的意思是如何调用函数。
要理解这个关键字,我们只需要知道如何、何时和从何处调用函数,而不需要知道如何和在何处声明或定义函数。
1 2 3 4 5 6 7 8 9 10 11 | function bike() { console.log(this.name); } var name ="Ninja"; var obj1 = { name:"Pulsar", bike: bike }; var obj2 = { name:"Gixxer", bike: bike }; bike(); //"Ninja" obj1.bike(); //"Pulsar" obj2.bike(); //"Gixxer" |
在上述代码段中,
在上面的代码片段中,当函数
在
"this"的默认和隐式绑定
如果我们处于严格模式,那么这个关键字的默认值是未定义的,否则这个关键字作为一个全局对象,它被称为这个关键字的默认绑定。(对于浏览器,默认为窗口对象)。
当有一个对象属性被我们作为一个方法调用时,该对象就成为这个对象或该方法的执行上下文对象,它是这个关键字的隐式绑定。
1 2 3 4 5 6 7 8 9 10 11 12 13 | var obj1 = { name:"Pulsar", bike: function() { console.log(this.name); } } var obj2 = { name:"Gixxer", bike: obj1.bike }; var name ="Ninja"; var bike = obj1.bike; bike(); //"Ninja" obj1.bike(); //"Pulsar" obj2.bike(); //"Gixxer" |
在上面的代码段中,函数调用
知道如何、何时和从何处调用函数与在何处声明函数无关,这一点很重要。
"this"关键字的显式和固定绑定
如果我们使用带有调用函数的call和apply方法,那么这两个方法都将作为它们的第一个参数作为执行上下文。这就是这个绑定。
1 2 3 4 5 6 7 8 9 | function bike() { console.log(this.name); } var name ="Ninja"; var obj = { name:"Pulsar" } bike(); //"Ninja" bike.call(obj); //"Pulsar" |
在上面的代码片段中,如果我们调用函数bike,其中
固定装订或硬装订
我们可以强制这个对象保持不变,不管它是从哪里被调用的以及如何被调用的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | var bike = function() { console.log(this.name); } var name ="Ninja"; var obj1 = { name:"Pulsar" }; var obj2 = { name:"Gixxer" }; var originalBikeFun = bike; bike = function() { originalBikeFun.call(obj1); }; bike(); //"Pulsar" bike.call(obj2); //"Pulsar" |
根据上面的代码片段,
总结
- EDOCX1的值(0)由函数的调用方式决定,而不是由函数的创建位置决定的!
- 通常,EDOCX1的值(0)由点左边的对象确定。(全球空间中的
window ) - 在事件侦听器中,EDOCX1的值(0)是指调用事件的DOM元素。
- 当使用
new 关键字调用in函数时,this 的值指新创建的对象。 - 可以通过函数:
call 、apply 、bind 来操纵this 的值。
例子:
1 2 3 4 5 6 7 8 9 10 11 | let object = { prop1: function () {console.log(this);} } object.prop1(); // object is left of the dot, thus this is object const myFunction = object.prop1 // We store the function in the variable myFunction myFunction(); // Here we are in the global space // myFunction is a property on the global object // Therefore it logs the window object |
1 2 3 4 5 6 7 8 | document.querySelector('.foo').addEventListener('click', function () { console.log(this); // This refers to the DOM element the eventListener was invoked from }) document.querySelector('.foo').addEventListener('click', () => { console.log(this); // Tip, es6 arrow function don't have their own binding to the this v }) // Therefore this will log the global object |
1 2 3 4 | .foo:hover { color: red; cursor: pointer; } |
1 | click me |
1 2 3 4 5 6 7 8 9 | function Person (name) { this.name = name; } const me = new Person('Willem'); // When using the new keyword the this in the constructor function will refer to the newly created object console.log(me.name); // Therefore, the name property was placed on the object created with new keyword. |
简单回答:
"this"关键字始终依赖于调用的上下文。它们在下面提到。
用new关键字调用函数
如果用new关键字调用函数,那么它将绑定到新创建的对象。
1 2 3 4 5 | function Car(){ this.name="BMW"; } const myCar=new Car(); myCar.name; // output"BMW" |
在上面,这将绑定到"mycar"对象
使用调用和应用方法显式调用函数。
在这种情况下,它将绑定到显式传递给函数的对象。
1 2 3 4 5 6 | var obj1={"name":"bond"}; function printMessage(msg){ return msg+""+this.name; } const message=printMessage.call(obj1,"my name is"); console.log(message); //HERE THIS WILL BE BOUND TO obj1 WHICH WE PASSED EXPLICITLY. SAME FOR APPLY METHOD ALSO. |
如果用对象隐式调用函数,则此函数将绑定到该对象
1 2 3 4 5 6 7 8 | var obj1={ "name":"bond", getName: function () { return this.name; } }; const newname=obj1.getName(); console.log(newname); //HERE THIS WILL BE BOUND TO obj1(WHITCHEVER OBJECT IS MENTIONED BEFORE THE DOT THIS WILL BE BOUND TO THAT) |
如果在没有任何上下文的情况下调用函数,则此函数将绑定到全局对象
1 2 3 4 5 6 7 8 9 | const util = { name: 'Utility', getName: function () { return this.name; }; const getName=util.getName; const newName=getName(); console.log(newName); // IF THIS EXECUTED IN BROWSER THIS WILL BE BOUND TO WINDOW OBJECT. IF THIS EXECUTED IN SERVER THIS WILL BE BOUND TO GLOBAL OBJECT |
在严格模式下,这将是未定义的
1 2 3 4 5 | function setName(name){ "use strict" return this.name; } setName(); //WILL BE ERROR SAYING name IS UNDEFINED. |