【问题标题】:Why private variables in an anonymous function are accessible from outside the function in javascript?为什么匿名函数中的私有变量可以从javascript中的函数外部访问?
【发布时间】:2014-12-30 01:29:51
【问题描述】:

看了一本《Essential JS Design Patterns》一书,无法理解这段代码中私有变量的行为:

var SingletonTester = (function () {

  // options: an object containing configuration options for the singleton
  // e.g var options = { name: "test", pointX: 5};
  function Singleton( options )  {

    // set options to the options supplied
    // or an empty object if none are provided
    options = options || {};

    // set some properties for our singleton
    this.name = "SingletonTester";

    this.pointX = options.pointX || 6;

    this.pointY = options.pointY || 10;

  }

  // our instance holder
  var instance;

  // an emulation of static variables and methods
  var _static  = {

    name:  "SingletonTester",

    // Method for getting an instance. It returns
    // a singleton instance of a singleton object
    getInstance:  function( options ) {
      if( instance  ===  undefined )  {
        instance = new Singleton( options );
      }

      return  instance;

    }
  };

  return  _static;

})();

var singletonTest  =  SingletonTester.getInstance({
  pointX:  5
});

// Log the output of pointX just to verify it is correct
// Outputs: 5
console.log( singletonTest.pointX );

这是本书中关于单例模式的示例。
有一个匿名函数,它返回一个包含“name”成员的对象和用于返回“Singleton”函数实例的“getInstance”方法。
我的麻烦是了解存储在 SingletonTester 中的对象如何访问“实例”私有变量。我的意思是,在匿名函数完成其工作后,SingletonTester 变量应该只保存对象:

{
    name:  "SingletonTester",

    // Method for getting an instance. It returns
    // a singleton instance of a singleton object
    getInstance:  function( options ) {
      if( instance  ===  undefined )  {
        instance = new Singleton( options );
 }

而且这个对象不知道实例是什么。 “单例”函数的实例化也是如此。它是如何知道定义在匿名函数范围内的“Singleton”是什么函数?

【问题讨论】:

  • 看起来只是变量作用域,instance 在类函数内部定义高于getInstance(),所以它在它下面的任何作用域中都可用,但在它上面不可用,所以它在getInstance() 内部可用但不在 IIFE 之外,除非在公开变量时调用 getInstance()

标签: javascript


【解决方案1】:

您遇到的是 JavaScript 中的词法作用域。基本上,每当您执行一个函数时,您都可以访问该函数的作用域。除此之外,您还可以访问定义函数的词法范围。

我们来看一个例子:

var someObject = (function () {
  var privateVariable = 18;

  var getValue = function () {
    return privateVariable;
  };

  return {
    getValue: getValue
  };
})();

对象“someObject”有一个方法“getValue”,执行时返回值 18。但这怎么可能呢?当您尝试执行 someObject.getValue() 时,JavaScript 引擎的工作方式如下:

  1. JavaScript 引擎对 someObject 对象执行属性查找,发现它有自己的 getValue 属性。
  2. 一旦找到函数对象 (getValue),它就会执行函数。
  3. 当函数被执行时,JavaScript 引擎会尝试查找 privateVariable 的值。
  4. 但是,在“getValue”函数的范围内,privateVariable 不存在。
  5. 因此,JavaScript 引擎查找 PARENT 范围(即声明 getValue 函数的范围)。
  6. 此范围对应于匿名函数的范围。在这个范围内,privateVariable 的值为 18。

这是 JavaScript 中的词法作用域。关于您的示例,这就是 SingletonTester 的实例可以访问“instance”变量的原因。

我强烈推荐这本书以了解更多信息:Scope and Closures

【讨论】:

  • 非常感谢!我最近才开始使用 javascript 编程,有很多对我来说很奇怪的东西,来自 PHP。很好的答案。
  • 很高兴我能提供帮助。如果您愿意,我提供的链接是一个很好的资源,可以真正了解范围界定的工作原理。事实上,它不仅仅适用于 JavaScript,因为许多编程语言也使用词法作用域。
猜你喜欢
  • 2012-02-25
  • 2012-12-31
  • 2020-08-19
  • 2012-05-26
  • 2013-08-16
  • 2014-03-11
  • 1970-01-01
  • 2012-01-14
相关资源
最近更新 更多