代码之家  ›  专栏  ›  技术社区  ›  Pierre Capo

模块中的变量范围

  •  1
  • Pierre Capo  · 技术社区  · 8 年前

    我正在编写我的第一个javascript模块,对于范围变量有一些我不理解的地方。这是我的模块:

    var Module = (function () {
    
        var myString ='a';
    
        var changeString = function () {
            myString ='b';
            console.log(myString);
        };
    
        return {
          changeString: changeString,
          myString:myString
        };
    
      })();
    

    现在如果我这样做:

    Module.myString;             // returns 'a'
    Module.changeString();       // returns 'b'
    Module.myString;             // returns 'a'
    

    对我来说,最后一个命令应该返回“b”,因为我已经用changeString方法更改了myString。我不明白为什么,因为myString是在changeString方法之外声明的,所以作用域似乎没有问题。我想了解它为什么会这样,以及如何创建一个覆盖变量值的方法。 提前谢谢。

    4 回复  |  直到 8 年前
        1
  •  4
  •   Paul    8 年前

    这将复制 myString 创建对象时:

    return {
      changeString: changeString,
      myString:myString
    }
    

    您可以使用getter动态返回局部变量,这将为您提供预期的行为:

    return {
      changeString: changeString,
      get myString() { 
        return myString;
      }
    }
    

    完整示例:

    var Module = (function () {
    
        var myString ='a';
    
        var changeString = function () {
            myString ='b';
            console.log(myString);
        };
    
        return {
          changeString: changeString,
          get myString() { 
            return myString;
          }
        }
    
    })();
    
    console.log( Module.myString );
    Module.changeString();
    console.log( Module.myString );
        2
  •  3
  •   trincot    8 年前

    匿名函数只执行一次,因此它返回的对象也只计算一次:它是一个具有字符串属性的对象 myString 这是一个基元值,如果变量 我的字符串 稍后更改。

    如果希望行为符合预期,则应在模块中保留对返回对象的引用,然后 变异 字符串属性需要更改时的对象:

    var Module = (function () {    
        var changeString = function () {
            obj.myString = 'b'; // mutation of obj!
            console.log(obj.myString);
        };
        var obj = {
             changeString: changeString,
             myString: 'a';
        };
        return obj; // we have a reference to this object
    })();
    
        3
  •  3
  •   Patrick Roberts Benjamin Gruenbaum    8 年前

    正如其他答案所说,因为 myString 是基元,其值从范围复制到返回的匿名对象的成员值。以访问外部可用的 我的字符串 changeString() 方法,可以引用指定给的匿名对象 Module 使用 this 关键词:

    var Module = (function() {
    
      var myString = 'a';
    
      var changeString = function() {
        // `Module.changeString()` causes `this === Module` inside here
        this.myString = 'b';
      };
    
      return {
        changeString: changeString,
        myString: myString
      };
    })();
    
    console.log(Module.myString);             // returns 'a'
    Module.changeString();
    console.log(Module.myString);             // returns 'b'

    使用ES6语法,可以通过以下几个快捷方式简化此方法:

    var Module = (() => {
    
      let myString = 'a';
    
      return {
        // ES6 for `myString: myString,`
        myString,
        // ES6 for `changeString: function () {`
        changeString () {
          this.myString = 'b';
        }
      };
    })();
    
    console.log(Module.myString); // returns 'a'
    Module.changeString();
    console.log(Module.myString); // returns 'b'
        4
  •  1
  •   Marco    8 年前

    你看到这种行为是因为你 return 一个新的对象。

    字符串 myString 复制,因为它是基元值。

    您可以通过一些调整来实现您的目标:

    var Module = function() {
        var myString = 'a';
    
        this.changeString = function() {
            myString = 'b';
        };
    
        this.getString = function() {
            return myString;
        };
    };
    
    var mod = new Module;
    
    console.log(mod.getString()); // a
    mod.changeString();
    console.log(mod.getString()); // b