我注意到似乎没有清楚地解释this
关键字是什么以及它在Stack Overflow站点上的JavaScript中是如何正确(和错误地)使用的。
我亲眼目睹了一些非常奇怪的行为,并且无法理解为什么会发生这种行为。
this
如何工作以及何时使用?
我建议先阅读Mike West的文章Scope in JavaScript(mirror)。它是对JavaScript中this
和范围链概念的优秀,友好的介绍。
一旦你开始习惯this
,规则实际上非常简单。 ECMAScript 5.1 Standard定义this
:
§11.1.1 The
this
keyword
this
关键字计算为当前执行上下文的ThisBinding的值
ThisBinding是JavaScript解释器在评估JavaScript代码时维护的东西,比如一个特殊的CPU寄存器,它保存对象的引用。只要在三种不同情况之一中建立执行上下文,解释器就会更新ThisBinding:
这是在顶层评估的JavaScript代码的情况,例如当直接在<script>
内:
<script>
alert("I'm evaluated in the initial global execution context!");
setTimeout(function () {
alert("I'm NOT evaluated in the initial global execution context.");
}, 1);
</script>
在初始全局执行上下文中计算代码时,ThisBinding设置为全局对象window
(§10.4.1.1)。
eval()
(2)(a))的ThisBinding值相同。eval()
(1))中执行一样。§15.1.2.1.1定义了对§10.4.2的直接调用。基本上,eval()
是直接调用,而像eval(...)
或(0, eval)(...)
这样的东西是对var indirectEval = eval; indirectEval(...);
的间接调用。当你可以使用间接的eval()
调用时,请参阅chuckj's answer到(1, eval)('this') vs eval('this') in JavaScript?和Dmitry Soshnikov’s ECMA-262-5 in detail. Chapter 2. Strict Mode.。
调用函数时会发生这种情况。如果在对象上调用函数,例如在eval()
或等效的obj.myMethod()
中,则将ThisBinding设置为对象(示例中为obj["myMethod"]()
; obj
)。在大多数其他情况下,ThisBinding设置为全局对象(§13.2.1)。
在“大多数其他情况下”编写的原因是因为有八个ECMAScript 5内置函数允许在参数列表中指定ThisBinding。这些特殊函数采用所谓的§10.4.3,在调用函数(thisArg
)时成为ThisBinding。
这些特殊的内置功能是:
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 ] )
函数,它们在函数对象上调用,但不是将ThisBinding设置为函数对象,而是将ThisBinding设置为Function.prototype
。
在thisArg
函数的情况下,给定的Array.prototype
在执行上下文中被调用,其中ThisBinding被设置为callbackfn
(如果提供);否则,到全局对象。
这些是纯JavaScript的规则。当您开始使用JavaScript库(例如jQuery)时,您可能会发现某些库函数操纵thisArg
的值。这些JavaScript库的开发人员这样做是因为它倾向于支持最常见的用例,并且库的用户通常会发现这种行为更方便。当传递将this
引用到库函数的回调函数时,您应该参考文档以获得有关调用函数时this
的值的任何保证。
如果您想知道JavaScript库如何操纵this
的值,那么库只是使用一个接受this
的内置JavaScript函数。您也可以使用回调函数和thisArg
编写自己的函数:
thisArg
我还没有提到一个特例。通过function doWork(callbackfn, thisArg) {
//...
if (callbackfn != null) callbackfn.call(thisArg);
}
运算符构造新对象时,JavaScript解释器创建一个新的空对象,设置一些内部属性,然后在新对象上调用构造函数。因此,当在构造函数上下文中调用函数时,new
的值是解释器创建的新对象:
this
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);
(在ECMA6中引入)改变了Arrow functions的范围。有关更多信息,请参阅现有的规范问题this
。但简而言之:
箭头函数没有自己的Arrow function vs function declaration / expressions: Are they equivalent / exchangeable? ....绑定。相反,这些标识符在词法范围内像任何其他变量一样被解析。这意味着在箭头函数内部,
this
...指定箭头函数定义的环境中this
的值。
要显示答案,请将鼠标悬停在浅黄色框上。
this
在标记线上的价值是多少?为什么?
this
- 标记的行在初始全局执行上下文中进行评估。
window
if (true) {
// What is `this` here?
}
时,this
在标记线上的价值是多少?为什么?
obj.staticFunction()
- 在对象上调用函数时,ThisBinding设置为对象。
obj
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);
在标记线上的价值是多少?为什么?
this
在此示例中,JavaScript解释器输入函数代码,但由于未在对象上调用window
/ myFun
,因此ThisBinding设置为obj.myMethod
。
这与Python不同,其中访问方法(window
)创建了obj.myMethod
。
bound method objectvar 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);
在标记线上的价值是多少?为什么?
this
这个很棘手。在评估评估代码时,window
是this
。但是,在eval代码中,没有在对象上调用obj
,因此对于调用,ThisBinding设置为myFun
。
window
function myFun() {
return this; // What is `this` here?
}
var obj = {
myMethod: function () {
eval("myFun()");
}
};
在标记线上的价值是多少?为什么?
this
行obj
正在调用特殊的内置函数myFun.call(obj);
,它接受Function.prototype.call()
作为第一个参数。
thisArg
关于如何在JavaScript中解释“this”关键字存在很多困惑。希望这篇文章能够让所有人一劳永逸地休息。还有更多。请仔细阅读整篇文章。预先警告这篇文章很长。
无论使用它的上下文,“this”总是引用Javascript中的“当前对象”。但是,“当前对象”根据上下文而不同。上下文可能恰好是以下6个中的1个:
以下逐一描述每个上下文:
<button onclick="foo"> // In the foo - window, but you can <button
onclick="foo(this)">
它成为窗口对象的属性,就好像您已将其定义为
function UserDefinedFunction(){
alert(this)
}
在“非严格模式”中,直接通过“UserDefinedFunction()”调用/调用此函数将自动调用/调用它作为“window.UserDefinedFunction()”使“窗口”成为“当前对象”(因此值“这个“)在”UserDefinedFunction“中。在”非严格模式“中调用此函数将导致以下结果
window.UserDefinedFunction=function(){
alert(this)
}
在“严格模式”中,通过“UserDefinedFunction()”直接调用/调用函数将“NOT”自动调用/调用它作为“window.UserDefinedFunction()”。因此“当前对象”(以及“this”的值) )“UserDefinedFunction”中的内容应该是未定义的。在“严格模式”中调用此功能将导致以下结果
UserDefinedFunction() // displays [object Window] as it automatically gets invoked as window.UserDefinedFunction()
但是,使用window对象显式调用它将导致以下结果
UserDefinedFunction() // displays undefined
让我们看另一个例子。请查看以下代码
window.UserDefinedFunction() // "always displays [object Window] irrespective of mode."
在上面的例子中,我们看到当通过o1调用“UserDefinedFunction”时,“this”取值为o1,并显示其属性“a”和“b”的值。 “c”和“d”的值显示为未定义,因为o1未定义这些属性
类似地,当通过o2调用“UserDefinedFunction”时,“this”获取o2的值并且显示其属性“c”和“d”的值。“a”和“b”的值显示为未定义为o2没有定义这些属性。 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
上面的代码清楚地表明,任何“NON Bound Function”的“this”值都可以通过call / apply来改变。此外,如果未将“this”参数显式传递给call / apply,则“当前对象”(因此“this”的值)在非严格模式下设置为“window”,在严格模式下设置为“undefined”。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”值都不能通过call / apply来改变。此外,如果未将“this”参数显式传递给bind,则“当前对象”(因此“this”的值)在非严格模式下设置为“window”,在严格模式下设置为“undefined”。还有一件事。绑定已绑定的函数不会更改“this”的值。它仍然设置为第一个绑定函数设置的值。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”分别表示“button”元素和“div”元素。
在第一个示例中,单击按钮时的字体颜色应设置为白色。
在单击“div”元素的第二个示例中,它将调用OnDivClick函数,其第二个参数引用单击的div元素。但是,OnDivClick中“this”的值不会引用单击的div元素。它应分别在Non strict和Strict Modes中设置为“window object”或“undefined”(如果OnDivClick是未绑定的函数)或设置为预定义的Bound值(如果OnDivClick是绑定函数)以下总结了整篇文章
关于<button onclick='this.style.color=white'>Hello World</button>
<div style='width:100px;height:100px;' onclick='OnDivClick(event,this)'>Hello World</div>
的最详细和最全面的文章可能如下:
this
Gentle explanation of 'this' keyword in JavaScript背后的想法是要理解函数调用类型对于设置this
值具有重要意义。
在识别this
时遇到麻烦,不要问自己:
this
从何而来?
但要问问自己:
如何调用该函数?
对于箭头函数(上下文透明度的特殊情况),请问自己:
this
定义箭头函数的值是多少?
在处理this
时,这种心态是正确的,并且可以避免头痛。
这是我见过的最好的解释:this
此引用始终引用(并保持其值)对象 - 单个对象 - 它通常在函数或方法中使用,尽管它可以在全局范围内的函数外部使用。请注意,当我们使用严格模式时,它在全局函数和未绑定到任何对象的匿名函数中保存undefined的值。
有四种情况可能令人困惑:
他提供了代码示例,解释和解决方案,我认为这些非常有用。
如果你不完全理解JS,很难掌握JS,或者写出更多的琐碎内容。你不能只是快速下降:)我认为开始使用JS的最佳方式是首先观看Douglas Crockford的这些视频讲座 - Understand JavaScripts this with Clarity,它涵盖了这个和那个,以及关于JS的所有其他内容。
在伪古典术语中,许多讲座教授'this'关键字的方式是作为由类或对象构造函数实例化的对象。每次从一个类构造一个新对象时,想象一下,创建并返回一个'this'对象的本地实例。我记得它是这样教的:
http://yuiblog.com/crockford/
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;
是JavaScript中被误解的概念之一,因为它在各个地方的表现差别不大。简单地说,this
指的是我们当前正在执行的函数的“所有者”。
this
有助于获取我们使用的当前对象(a.k.a.执行上下文)。如果你了解当前函数在哪个对象中执行,你可以很容易地理解当前的this
是什么
this
上面我们创建3个同名“val”的变量。一个在全局上下文中,一个在obj中,另一个在obj的innerMethod中。 JavaScript通过从本地go全局上升范围链来解析特定上下文中的标识符。
很少有地方可以区分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
this
当执行line1时,JavaScript为函数调用建立执行上下文(EC),将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
设置为前一个“。”之前引用的对象。所以在最后一行你可以理解this
是在全球范围内执行的,即a()
。
window
可用于指代正在创建的对象
this
执行新的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
时,会创建一个全新的对象。 Person()
被调用,它的Person
被设置为引用该新对象。
this
如果我们错过了qazxsw poi关键字,qazxsw poi指的是它能找到的最全球化背景(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
)
如果事件处理程序是内联的,则new
引用全局对象
whatIsThis
通过JavaScript添加事件处理程序时,window
引用生成事件的DOM元素。
this
<script type="application/javascript">
function click_handler() {
alert(this); // alerts the window object
}
</script>
<button id='thebutton' onclick='click_handler()'>Click me!</button>
和this
来操纵上下文.apply()
,.call()
).bind()
“this”的值取决于执行函数的“上下文”。上下文可以是任何对象或全局对象,即窗口。
所以“this”的语义不同于传统的OOP语言。它会导致问题:1。当一个函数传递给另一个变量时(很可能是一个回调); 2.从类的成员方法调用闭包时。
在这两种情况下,都设置为窗口。
Understanding $.proxy()有帮助吗? (javascript中对'this'的大多数混淆来自于它通常不与您的对象相关联,而是与当前执行范围相关联 - 这可能不是它的确切工作方式,但对我来说总是这样 - 看到文章的完整解释)
关于这个关键字的一点信息
让我们在全局范围内将jQuery.proxy() usage关键字记录到控制台,而不需要更多代码
What does var that = this
means in JavaScript
在客户端/浏览器中,this关键字是一个全局对象,它是this
console.log(this)
和
在Server / Node / Javascript运行时this
关键字也是一个全局对象,它是window
console.log(this === window) // true
请记住,this
只是对module.exports
的引用
这个用于Scope就像这样
console.log(this === module.exports) // true
console.log(this === exports) // true
上面示例中的txt1和txt的值相同$(this)= $('#tbleName tbody tr')是相同的
与其他语言相比,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中的行为有所不同。在面向对象语言中,this
关键字引用类的当前实例。在JavaScript中,this
的值主要由函数的调用上下文(this
)以及调用它的位置决定。
1.在全球范围内使用时
当你在全局上下文中使用context.function()
时,它被绑定到全局对象(浏览器中的this
)
window
当你在全局上下文中定义的函数中使用document.write(this); //[object Window]
时,this
仍然绑定到全局对象,因为该函数实际上是一个全局上下文的方法。
this
以上function f1()
{
return this;
}
document.write(f1()); //[object Window]
是一种全球对象的方法。因此我们也可以在f1
对象上调用它,如下所示:
window
2.在对象内部使用时
在对象方法中使用function f()
{
return this;
}
document.write(window.f()); //[object Window]
关键字时,this
绑定到“立即”封闭对象。
this
我在上面用双引号括起来。它的目的是,如果您将对象嵌套在另一个对象中,那么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
3.调用无上下文函数时
当您在没有任何上下文(即不在任何对象上)时调用的函数内部使用var obj1 = {
name: "obj1",
}
function returnName() {
return this + ":" + this.name;
}
obj1.f = returnName; //add method to object
document.write(obj1.f()); //[object Object]:obj1
时,它将绑定到全局对象(浏览器中的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
运算符创建其实例。下面我尝试了上面用Object和new
做的所有事情,但是先创建函数而不是直接写一个对象。
this
4.在构造函数内部使用时。
当函数用作构造函数时(即使用/*********************************************************************
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
关键字调用它时),函数体内的new
指向正在构造的新对象。
this
5.在原型链中定义的函数内部使用时
如果方法在对象的原型链上,则此方法中的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
引用调用该方法的对象,就好像该方法是在对象上定义的一样。
this
6.内部调用(),apply()和bind()函数
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
上定义。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
7. 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>
内部事件处理程序
this
指的是相应的元素。这种直接函数赋值可以使用this
方法或通过传统的事件注册方法(如addeventListener
)来完成。onclick
)中直接使用this
时,它引用该元素。<button onclick="...this..." >
会解析为全局对象this
。window
将函数附加到事件处理程序时,可以实现相同的上述行为。它不是将函数赋值给事件处理程序(从而构成元素的函数方法),而是调用事件上的函数(在全局上下文中有效地调用它)。我建议在attachEvent
中更好地尝试这个。
JSFiddle
8. ES6箭头功能中的<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>
在箭头函数中,this
将表现为常见变量:它将从其词法范围继承。定义箭头函数的函数this
将是箭头函数的this
。
所以,这与以下行为相同:
this
请参阅以下代码:
(function(){}).bind(this)
我从其他答案中对exports
有不同看法,我希望对此有所帮助。
查看JavaScript的一种方法是看到只有一种方法可以调用function1。它是
module.exports
总是为 <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)
});
</script>
提供一些价值。
其他一切都是this
的语法糖
所以,其他一切都可以通过它如何转化为functionObject.call(objectForThis, arg0, arg1, arg2, ...);
来描述。
如果你只是调用一个函数,那么objectForThis
就是“全局对象”,它在浏览器中就是窗口
functionObject.call
换一种说法,
functionObject.call
被有效地翻译成了
this
请注意,如果您使用严格模式,那么function foo() {
console.log(this);
}
foo(); // this is the window object
将是foo();
foo.call(window);
意思是
换一种说法,
this
被有效地翻译成了
undefined
在JavaScript中有像'use strict';
function foo() {
console.log(this);
}
foo(); // this is the window object
和foo();
以及foo.call(undefined);
这样的运算符。还有点运算符是+
当-
运算符与右边的函数和左边的对象一起使用时,有效地意味着“将对象作为*
传递给函数。
例
.
换句话说,.
翻译成this
请注意,创建函数的方式并不重要(主要是......)。所有这些都会产生相同的结果
const bar = {
name: 'bar',
foo() {
console.log(this);
},
};
bar.foo(); // this is bar
这些都只是语法糖
bar.foo()
另一个皱纹是原型链。当您使用const temp = bar.foo; temp.call(bar);
时,JavaScript首先查看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
直接引用的对象{ const temp = bar.fn1; temp.call(bar); }
{ const temp = bar.fn2; temp.call(bar); }
{ const temp = bar.fn3; temp.call(bar); }
属性。如果在对象上找不到a.b
,则JavaScript将查看对象的原型以查找a
。
有多种方法可以定义对象的原型,2019年最常见的是b
关键字。出于b
的目的虽然没关系。重要的是,如果它在物体b
上查找属性class
,如果它在对象或其原型链中找到属性this
,如果a
最终成为一个函数,那么适用于上述相同的规则。函数b
引用将使用b
方法调用并将b
作为objectForThis传递,如此答案的顶部所示。
现在。让我们假设我们创建一个函数,在调用另一个函数之前显式设置b
然后用call
(点)运算符调用它
a
在翻译使用this
后,.
成为function foo() {
console.log(this);
}
function bar() {
const objectForThis = {name: 'moo'}
foo.call(objectForThis); // explicitly passing objectForThis
}
const obj = {
bar,
};
obj.bar();
。当我们输入call
函数时,我们调用obj.bar()
,但是我们明确传入了另一个objectForThis对象,所以当我们到达foo时,const temp = obj.bar; temp.call(obj);
就是那个内部对象。
这就是bar
和foo
有效的功能。它们更具语法糖。它们有效地构建了一个新的不可见函数,就像上面的this
一样,在调用任何指定函数之前显式设置bind
。在绑定的情况下,=>
被设置为你传递给bar
的任何东西。
this
请注意,如果this
不存在,我们可以像这样制作自己的
bind
然后我们就可以这样称呼它
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'});
箭头函数,functionObject.bind
运算符是绑定的语法糖
function bind(fn, objectForThis) {
return function(...args) {
return fn.call(objectForthis, ...args);
};
}
是相同的
function foo() {
console.log(this);
}
const bar = bind(foo, {name:'abc'});
就像=>
一样,创建了一个新的不可见函数,它使用const a = () => {console.log(this)};
的绑定值调用给定函数,但与const tempFn = function() {console.log(this)};
const a = tempFn.bind(this);
不同,要绑定的对象是隐式的。这就是当使用bind
算子时objectForThis
恰好是什么。
所以,就像上面的规则一样
bind
this
=>
const a = () => { console.log(this); } // this is the global object
转换为'use strict';
const a = () => { console.log(this); } // this is undefined
,这意味着function foo() {
return () => { console.log(this); }
}
const obj = {
foo,
};
const b = obj.foo();
b();
中的箭头运算符将obj.foo()
绑定到一个新的不可见函数,并返回分配给const temp = obj.foo; temp.call(obj);
的新的不可见函数。 foo
将像obj
或b
一样工作,调用b()
创建的新的隐形函数。那个看不见的函数忽略了传入它的b.call(window)
并将b.call(undefined)
作为objectForThis`传递给了箭头函数。
上面的代码转换为
foo
1this
是另一个类似于obj
的功能
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);
但从概念上讲,你可以将ES6翻译成
apply
call
Javascript:functionName.apply(objectForThis, arrayOfArgs);
的值取决于函数的调用方式,创建函数的位置!functionName.call(objectForThis, ...arrayOfArgs);
的值由点左边的Object确定。 (this
在全球空间)this
的值指的是调用事件的DOM元素。this
关键字调用函数时,window
的值引用新创建的对象this
的值:new
,this
,this
call
apply
bind
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
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
简单回答:
“this”关键字始终取决于调用的上下文。他们在下面提到。
.foo:hover {
color: red;
cursor: pointer;
}
在上面这将被绑定到'myCar'对象<div class="foo">click me</div>
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.
function Car(){
this.name="BMW";
}
const myCar=new Car();
myCar.name; // output "BMW"
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.
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
考虑以下功能:
this
请注意,我们在正常模式下运行它,即不使用严格模式。
在浏览器中运行时,function foo() {
console.log("bar");
console.log(this);
}
foo(); // calling the function
的值将记录为this
。这是因为window
是Web浏览器范围内的全局变量。
如果在node.js之类的环境中运行同一段代码,window
将引用应用程序中的全局变量。
现在,如果我们通过在函数声明的开头添加语句this
来以严格模式运行它,那么"use strict";
将不再引用任何环境中的全局变量。这样做是为了避免严格模式下的混淆。 this
,在这种情况下只记录this
,因为它就是这样,它没有定义。
在下面的例子中,我们将看到如何操纵undefined
的值。
有不同的方法来做到这一点。如果你在Javascript中调用了本机方法,如this
和forEach
,你应该已经知道在这种情况下slice
变量是指你调用该函数的this
(请注意,在javascript中,几乎所有东西都是Object
,包括Object
s和Array
s)。以下面的代码为例。
Function
如果var myObj = {key: "Obj"};
myObj.logThis = function () {
// I am a method
console.log(this);
}
myObj.logThis(); // myObj is logged
包含持有Object
的属性,则该属性称为方法。调用此方法时,将始终将Function
变量设置为与之关联的this
。对于严格和非严格模式都是如此。
请注意,如果方法存储(或者更确切地说,复制)在另一个变量中,则对Object
的引用不再保留在新变量中。例如:
this
考虑更常见的实际情况:
// continuing with the previous code snippet
var myVar = myObj.thisMethod;
myVar();
// logs either of window/global/undefined based on mode of operation
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中的构造函数:
new
这是如何运作的?好吧,让我们看看当我们使用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`
关键字时会发生什么。
new
关键字调用函数会立即初始化new
类型的Object
。Person
的构造函数的构造函数设置为Object
。另外,请注意Person
只返回typeof awal
。Object
将被分配Object
的原型。这意味着Person.prototype
原型中的任何方法或属性都可用于所有Person
实例,包括Person
。awal
本身; Person
是对新构建的对象this
的引用。很简单,嗯?
请注意,官方的ECMAScript规范没有说明这种类型的函数是实际的awal
函数。它们只是普通函数,constructor
可用于任何函数。只是我们这样使用它们,所以我们只将它们称为它们。
new
和call
所以是的,既然apply
s也是function
(实际上是Javascript中的第一类变量),甚至函数都有方法......好吧,函数本身。
所有函数都继承自全局Objects
,其中许多方法中的两个是Function
和call
,两者都可用于在调用它们的函数中操纵apply
的值。
this
这是使用function foo () { console.log (this, arguments); }
var thisArg = {myObj: "is cool"};
foo.call(thisArg, 1, 2, 3);
的典型示例。它基本上采用第一个参数,并在函数call
中设置this
作为对foo
的引用。传递给thisArg
的所有其他参数都作为参数传递给函数call
。
所以上面的代码将在控制台中记录foo
。在任何函数中更改{myObj: "is cool"}, [1, 2, 3]
值的相当不错的方法。
this
与apply
几乎相同,只接受两个参数:call
和一个包含要传递给函数的参数的数组。所以上面的thisArg
调用可以像这样翻译成call
:
apply
请注意,foo.apply(thisArg, [1,2,3])
和call
可以覆盖我们在第二个项目中讨论的点方法调用设置的apply
的值。很简单:)
this
!bind
是bind
和call
的兄弟。它也是Javascript中全局apply
构造函数的所有函数继承的方法。 Function
和bind
/ call
之间的区别在于apply
和call
实际上都会调用该函数。另一方面,apply
返回一个新函数,其中bind
和thisArg
预设。让我们举个例子来更好地理解这个:
arguments
看到三者之间的区别?它很微妙,但它们的使用方式不同。像function foo (a, b) {
console.log (this, arguments);
}
var thisArg = {myObj: "even more cool now"};
var bound = foo.bind(thisArg, 1, 2);
console.log (typeof bound); // logs `function`
console.log (bound);
/* logs `function () { native code }` */
bound(); // calling the function returned by `.bind`
// logs `{myObj: "even more cool now"}, [1, 2]`
和call
一样,apply
也将覆盖由点方法调用设置的bind
的值。
另请注意,这三个函数都不会对原始函数进行任何更改。 this
和call
将从新构造的函数返回值,而apply
将返回新构造的函数本身,准备被调用。
有时,您不喜欢bind
随范围而变化的事实,尤其是嵌套范围。看一下下面的例子。
this
在上面的代码中,我们看到var myObj = {
hello: function () {
return "world"
},
myMethod: function () {
// copy this, variable names are case-sensitive
var that = this;
// callbacks ftw \o/
foo.bar("args", function () {
// I want to call `hello` here
this.hello(); // error
// but `this` references to `foo` damn!
// oh wait we have a backup \o/
that.hello(); // "world"
});
}
};
的值随嵌套范围而改变,但我们希望this
的值来自原始范围。因此我们将'this
'复制到this
并使用副本而不是that
。聪明,是吗?
指数:
this
默认举行?this
关键字怎么办?new
和this
操纵call
?apply
。bind
以解决嵌套范围问题。“这个”就是范围。每个函数都有自己的作用域,因为JS中的所有东西都是一个对象,所以即使函数也可以使用“this”将一些值存储到自身中。 OOP 101教导“this”仅适用于对象的实例。因此,每次执行一个函数时,该函数的新“实例”都具有“this”的新含义。
大多数人在尝试在匿名闭包函数中使用“this”时会感到困惑:
(function(value) { this.value = value; $('.some-elements').each(function(elt){ elt.innerHTML = this.value; // uh oh!! possibly undefined }); })(2);
所以在这里,在每个()中,“this”不包含你期望它的“值”(来自
this.value = value;above it). So, to get over this (no pun intended) problem, a developer could:
(function(value) { var self = this; // small change self.value = value; $('.some-elements').each(function(elt){ elt.innerHTML = self.value; // phew!! == 2 }); })(2);
试试看;你会开始喜欢这种编程模式
由于这个帖子已经提升,我为this
主题的新读者编写了几点。
this
determined?我们使用类似于我们在英语等自然语言中使用代词的方式:“约翰跑得快,因为他试图赶上火车。”相反,我们可以写“......约翰试图赶上火车”。
this
在对象调用定义它的函数之前,不会为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);
}
}
分配值。在全局范围内,所有全局变量和函数都在this
对象上定义。因此,全局函数中的window
指的是(并且具有)全局this
对象的值。
当window
,use strict
在全局和匿名函数中没有绑定到任何对象时,其值为this
。
undefined
关键字是this
时:1)我们借用一个使用most misunderstood的方法,2)我们分配一个使用this
到变量的方法,3)使用this
的函数作为回调函数传递,并且4)使用this
在一个闭包里面 - 一个内在的功能。 (2)
在this
中定义,箭头函数采用封闭(函数或全局)范围内的ECMA Script 6绑定。
this
虽然箭头函数提供了使用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!
的替代方法,但重要的是要注意它们基本上禁用传统的bind()
机制,以支持更广泛理解的词法范围。 (1)
参考文献:
this
JavaScript中的http://goo.gl/Z2RacU始终引用正在执行的函数的“所有者”。
如果未定义显式所有者,则引用最顶层的所有者(窗口对象)。
所以,如果我这样做
this
function someKindOfFunction() {
this.style = 'foo';
}
element.onclick = someKindOfFunction;
将引用元素对象。但要小心,很多人犯了这个错误。
this
在后一种情况下,您只需引用该函数,而不是将其移交给元素。因此,<element onclick="someKindOfFunction()">
将引用窗口对象。
一切 功能 javascript中的执行上下文有一个 范围 上下文 此参数由以下设置:
无论该范围上下文是什么,都由“this”引用。
您可以
改变这一点
设置它的值
范围
上下文
使用this
,func.call
或func.apply
。
默认情况下,什么混淆了大多数初学者,当a 打回来 在DOM元素上引发事件后调用listener 范围上下文 该函数的值是DOM元素。
jQuery使用jQuery.proxy改变这一点。
func.bind
是Here的this
的一个很好的来源。
以下是摘要:
JavaScript
是this
object
window
在使用repl的<script type="text/javascript">
console.log(this === window); // true
var foo = "bar";
console.log(this.foo); // "bar"
console.log(window.foo); // "bar"
中,node
是顶级命名空间。您可以将其称为this
。
global
在从脚本执行的>this
{ ArrayBuffer: [Function: ArrayBuffer],
Int8Array: { [Function: Int8Array] BYTES_PER_ELEMENT: 1 },
Uint8Array: { [Function: Uint8Array] BYTES_PER_ELEMENT: 1 },
...
>global === this
true
中,全局范围内的node
作为空对象开始。它与this
不同
global
除了DOM事件处理程序或提供\\test.js
console.log(this); \\ {}
console.log(this === global); \\ fasle
的情况(参见下文),在未使用thisArg
调用的函数中使用this
在节点和浏览器中引用全局范围...
new
如果你使用<script type="text/javascript">
foo = "bar";
function testThis() {
this.foo = "foo";
}
console.log(this.foo); //logs "bar"
testThis();
console.log(this.foo); //logs "foo"
</script>
,在这种情况下use strict;
将是this
undefined
如果你用<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
</script>
调用函数,new
将是一个新的上下文,它将不会引用全局this
。
this
您创建的函数将成为函数对象。它们会自动获得一个特殊的<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"
</script>
属性,这是你可以赋值的东西。通过使用prototype
调用函数创建实例时,可以访问分配给new
属性的值。您可以使用prototype
访问这些值。
this
在function Thing() {
console.log(this.foo);
}
Thing.prototype.foo = "bar";
var thing = new Thing(); //logs "bar"
console.log(thing.foo); //logs "bar"
上分配数组或对象通常是错误的。如果您希望每个实例都有自己的数组,请在函数中创建它们,而不是原型。
prototype
您可以在对象的任何函数中使用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 []
来引用该对象上的其他属性。这与使用this
创建的实例不同。
new
在HTML DOM事件处理程序中,var obj = {
foo: "bar",
logFoo: function () {
console.log(this.foo);
}
};
obj.logFoo(); //logs "bar"
始终是对事件附加到的DOM元素的引用
this
除非你function Listener() {
document.getElementById("foo").addEventListener("click",
this.handleClick);
}
Listener.prototype.handleClick = function (event) {
console.log(this); //logs "<div id="foo"></div>"
}
var listener = new Listener();
document.getElementById("foo").click();
的背景
bind
在您可以放置JavaScript的HTML属性中,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();
是对元素的引用。
this
你可以使用<div id="foo" onclick="console.log(this);"></div>
<script type="text/javascript">
document.getElementById("foo").click(); //logs <div id="foo"...
</script>
访问eval
。
this
您可以使用function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
eval("console.log(this.foo)"); //logs "bar"
}
var thing = new Thing();
thing.logFoo();
将with
添加到当前范围,以读取和写入this
上的值,而无需明确引用this
。
this
jQuery会在很多地方让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"
引用一个DOM元素。
this
丹尼尔,很棒的解释!在事件处理程序的情况下,这个和<div class="foo bar1"></div>
<div class="foo bar2"></div>
<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();
});
</script>
执行上下文指针的良好列表上的几个单词。
用两个词来说,JavaScript中的this
指向运行当前函数的对象(或从其执行上下文中运行)并且它始终是只读的,无论如何都无法设置它(这样的尝试最终会导致'无效左 - 手边的任务'消息。
对于事件处理程序:内联事件处理程序(如this
)会覆盖之前和之前附加的任何其他处理程序,因此请务必小心,最好不要使用内联事件委派。感谢Zara Alaverdyan,他通过不同的辩论激励我参加这个例子清单:)
<element onclick="foo">
el.onclick = foo; // in the foo - obj
el.onclick = function () {this.style.color = '#fff';} // obj
el.onclick = function() {doSomething();} // In the doSomething -
Window
el.addEventListener('click',foo,false) // in the foo - obj
el.attachEvent('onclick, function () { // this }') // window, all the
compliance to IE :)
<button onclick="this.style.color = '#fff';"> // obj