嵌套函数中的Javascript“this”指针

我有一个关于如何在一个嵌套函数场景中处理“this”指针的问题。

假设我将下面的示例代码插入到网页中。 我调用嵌套函数“doSomeEffects()”时出现错误。 我检查了Firebug,它表明当我在嵌套函数中时,“this”指针实际上是指向全局的“window”对象 – 这是我没有想到的。 我不能正确理解某些东西,因为我认为自从我在对象的函数中声明了嵌套函数以来,它应该具有与函数相关的“局部”范围(即“this”指针将指向对象本身如何在我的第一个“如果”声明)。

任何指针(没有双关语意)将不胜感激。

var std_obj = { options : { rows: 0, cols: 0 }, activeEffect : "none", displayMe : function() { // the 'this' pointer is referring to the std_obj if (this.activeEffect=="fade") { } var doSomeEffects = function() { // the 'this' pointer is referring to the window obj, why? if (this.activeEffect=="fade") { } } doSomeEffects(); } }; std_obj.displayMe(); 

在JavaScript中, this对象是基于你如何进行函数调用。

通常有三种方式来设置this对象:

  1. someThing.someFunction(arg1, arg2, argN)
  2. someFunction.call(someThing, arg1, arg2, argN)
  3. someFunction.apply(someThing, [arg1, arg2, argN])

在上面的所有例子中, this对象将会是一些someThing 。 调用没有前导父对象的函数通常会得到全局对象,在大多数浏览器中这个对象意味着window对象。

this不是闭包范围的一部分,它可以被认为是绑定在呼叫站点的函数的附加参数。 如果方法没有被作为一个方法调用,那么全局对象就是这样传递的。 在浏览器中,全局对象与window相同。 例如,考虑以下function,

 function someFunction() { } 

和下面的对象,

 var obj = { someFunction: someFunction }; 

如果您使用方法语法(如,

 obj.someFunciton(); 

那么this是必然的obj

如果你直接调用一些函数(),比如,

 someFunction(); 

那么this绑定到了全局对象,那就是window

最常见的解决方法就是将其捕捉到闭包中,

 displayMe : function() { // the 'this' pointer is referring to the std_obj if (this.activeEffect=="fade") { } var that = this; var doSomeEffects = function() { // the 'this' pointer is referring to global // that, however, refers to the outscope this if (that.activeEffect=="fade") { } } doSomeEffects(); } 

由于这似乎是这类问题中最有争议的问题之一,所以让我补充一下这些年来使用箭头function的ES6解决scheme:

 var std_obj = { ... displayMe() { ... var doSomeEffects = () => { ^^^^^^^ ARROW FUNCTION // In an arrow function, the 'this' pointer is interpreted lexically, // so it will refer to the object as desired. if (this.activeEffect=="fade") { } }; ... } }; 

shellvariables和“this”之间有区别。 “this”实际上是由函数的调用者定义的,而显式variables在被称为shell的函数声明块内保持不变。 看下面的例子:

 function myFirstObject(){ var _this = this; this.name = "myFirstObject"; this.getName = function(){ console.log("_this.name = " + _this.name + " this.name = " + this.name); } } function mySecondObject(){ var _this = this; this.name = "mySecondObject"; var firstObject = new myFirstObject(); this.getName = firstObject.getName } var secondObject = new mySecondObject(); secondObject.getName(); 

你可以在这里试试看: http : //jsfiddle.net/kSTBy/

你的函数中发生了什么是“doSomeEffects()”,显式调用,这意味着上下文或函数的“this”是窗口。 如果“doSomeEffects”是一个原型方法,比如说this.doSomeEffects说的是“myObject”,那么myObject.doSomeEffects()会导致“this”为“myObject”。

要理解这个问题,请尝试获取以下片段的输出

 var myObject = { foo: "bar", func: function() { var self = this; console.log("outer func: this.foo = " + this.foo); console.log("outer func: self.foo = " + self.foo); (function() { console.log("inner func: this.foo = " + this.foo); console.log("inner func: self.foo = " + self.foo); }()); } }; myObject.func(); 

上面的代码将输出到控制台:

 outer func: this.foo = bar outer func: self.foo = bar inner func: this.foo = undefined inner func: self.foo = bar 

在外部函数中,this和self都引用myObject,因此都可以正确地引用和访问foo。

但是在内部函数中,这不再指向myObject。 因此,this.foo在内部函数中是未定义的,而对局部variablesself的引用仍然在范围内并且可以在那里访问。 (在ECMA 5之前,这个在内部函数中是指全局窗口对象;而在ECMA 5中,这个在内部函数中是不确定的。)

正如Kyle所解释的那样,您可以使用callapply来在函数中指定:

这个概念适用于你的代码:

 var std_obj = { options: { rows: 0, cols: 0 }, activeEffect: "none", displayMe: function() { // the 'this' pointer is referring to the std_obj if (this.activeEffect == "fade") {} var doSomeEffects = function() { // the 'this' pointer is referring to the window obj, why? if (this.activeEffect == "fade") {} } doSomeEffects.apply(this,[]); } }; std_obj.displayMe(); 

的jsfiddle