why does `this` refer to the global object in closure

时间:2015-09-14 15:52:01

标签: javascript this

var num = 1;

var obj = {

    num: 2,

    getNum: function() {
        return (function() {
            return this.num;
        })();
    }

}

console.log(obj.getNum()); // 1

the JavaScript code's result is 1. So this refers to global object rather than obj.

4 个答案:

答案 0 :(得分:2)

在其他条件相同的情况下,this在函数中直接使用 时指向函数为方法的对象(成员),当以obj.method()的典型方式调用该函数时。直接意味着直接;在嵌套在方法中的函数中使用,无论是匿名的还是立即调用的,否则符合条件。

在你的情况下

return (function() {
    return this.num;
})();

该函数不是任何对象的成员,因此没有this,因此this是全局对象(在严格模式下为null)。

仅仅因为您使用this的函数嵌套在一个函数中,该函数就足够了。您使用this的函数必须是方法本身。

要获得所需的行为,您有以下几种选择:

getNum: function() {
  return (() => this.num)();
}

这是有效的,因为胖箭头函数使用词法this

另一个想法,已在另一个答案中显示:

getNum: function() {
  var self = this;
  return function() {
    return self.num;
  }();
}

顺便说一句,在这种情况下,不需要将函数括在括号中以强制它成为可以立即调用的函数表达式。仅凭:的右侧,它已经是一种表达。

还有第三种方法:

getNum: function() {
  return function() {
    return this.num;
  }.call(this);
}

我们通过明确使用this强制匿名函数的thisgetNum call

有关最终答案,请参阅How does the "this" keyword work?

关于术语"关闭"

的说明

在你的问题中,你似乎正在使用术语"关闭"表示"嵌套功能"。虽然你的嵌套,匿名,立即调用的函数可能是一个非常狭隘的技术意义上的闭包,但使用这种术语可能会让你自己和其他人感到困惑。您的函数不满足以下两个通常接受的关闭条件:

  1. 它没有"关闭" (使用)来自周围范围的任何变量。

  2. 它不会作为一个带有它的函数值返回到外面的世界,而是从周围的词法范围引用这些变量。

  3. 因此,简单地将此函数称为"嵌套函数"会更清楚。

答案 1 :(得分:0)

函数this内部取决于执行上下文,因此调用函数非常重要。

如果调用上下文未设置this,则在严格和非严格模式下会有所不同。

在非严格模式下,它指的是全局对象。 在严格模式下,其undefined。请注意,undefined实际上可以设置为其他内容。

要设置所述上下文,您需要将函数作为对象的属性调用,如obj.getNum()调用。 In会为函数提供一个对象范围,但它与您尝试实际访问的另一个函数调用没有任何关系this

以下代码说明了:

var num = 1;
var obj = {
  num: 2,
  getNum: function() {
    var outerThis = this;
    return (function() {
      return {
        innerThis: this,
        outerThis: outerThis,
        innerNum: this.num,
        outerNum: outerThis.num
      };
    })();
  },
  getNumStrict:function() {
    "use strict"
    var outerThis = this;
    return (function() {
      return {
        innerThis: this,
        outerThis: outerThis,
        outerNum: outerThis.num
      };
    })(outerThis.num);
  }
}
console.log(obj.getNum());
// Object {innerThis: Window, outerThis: Object, innerNum: 1, outerNum: 2}

console.log(obj.getNumStrict());
// Object {innerThis: undefined, outerThis: Object, outerNum: 2}

正如您所看到的,this在JavaScript中是一个有争议的概念,如果没有它,您很容易就可以了。

要将私有属性设为私有,可以在函数范围内创建它们,并返回一个返回接口副本而不是对象引用的函数:

var num = 1;
var createHaveNum = function(initial) {
  var num = initial;
  var getInterface;
  var setNum = function(x) {
    num = x;
    console.log("setting num");
  };
  var getNum = function() {
    console.log("getting num");
    return num;
  };
  getInterface = function() {
    return {
      getNum: getNum,
      setNum: setNum
    };
  };
  console.log("Instance is initialized.");
  return getInterface;
};

var obj = createHaveNum(2); // create an object, obtain a reference in form of a function

var i = obj(); // obtain an interface
var j = obj(); // do it again, interface to same object
j.setNum = undefined; // does not break internal state, object is intact
console.log(i.getNum());
i.setNum(3);
var getNum = i.getNum; // reference function
console.log(getNum()); // invoke without a scope, no problem
var other = {getNum: i.getNum}; // put in another object
console.log(other.getNum()); // call with another context, no problem - same scope as before.
/*
Instance is initialized.
getting num
2
setting num
getting num
3
getting num
3
*/

答案 2 :(得分:-1)

Because obj does not exist when the object literal is defined, so it can't be closed over. On top of that, closure operates on the scope, and you don't have a scope outside the function.

At the moment the literal is being evaluated, there is no obj. When evaluating that statement, the object literal is evaluated first (the right-hand operand to the = operator must be evaluated first), then assigned to the newly-declared variable obj.

To make matters worse, closure in ES is on the scope and ES5 (and below) only have function-scope. You don't have an outer scope to close over, besides the global scope.

答案 3 :(得分:-1)

To get the "desired" result, you'd have to redefine getName as below:

getNum: function() {

    var that = this; //the enclosing object
    return (function() {

        return that['num'];

    })();

}