从成员函数对对象所做的更改不会保留。范围/参考问题?

时间:2018-05-14 19:32:31

标签: javascript node.js object scope reference

我会尽量保持这简洁。我有两个文件,Main.js和Component1.js。我正在尝试实现模块模式,但我遇到了在事件处理程序中进行更改后仍然存在的问题。我会解释代码,我在nodejs中写这个,这是每个文件的简短版本:

Main.js

var component1 = require("Component1");
var components = { compA: component1(), compB: {} };

Component1.js

module.exports = function () {
    var count = 0;

    function listener(e) {     // Event handler of custom event.
        console.log(count);
        count++;
    }

    return { count: count }
}

现在,如果我将以下行添加到Main.js

components.compA.randomString = "Hello";

并将Component1.js中的listener()更改为

function listener(e) {     // Event handler of custom event.
    console.log(typeof randomString);
    console.log(count);
    count++;
}

在发出与听众绑定的1个自定义事件后,我得到以下打印输出:

undefined
0

如果我要发出第二个自定义事件,则打印输出为:

undefined
1

但是如果我现在调试main.js中的compA.count,我会看到它仍为零。

我猜这意味着听众要么可以访问不同的范围,所以也没有改变"持续存在"从另一个的角度来看(对于Main.js计数=== 0,为侦听器计算字符串未定义),或者compA和侦听器引用两个不同的对象?我得出这个结论,因为如果我现在将Component1.js改为

module.exports = function () {
    var count = 0;
    var _this;

    function listener(e) {     // Event handler of custom event.
        console.log(typeof _this.randomString);
        console.log(_this.count);
        _this.count++;
    }

    function init() {
        _this = this;
    }

    return { count : count, init: init }
}

并将以下行添加到Main.js的末尾:

components.compA.init();

并发布2个新的自定义事件我得到以下打印输出:

string
0
string
1

并且正确的计数将持续到components.compA.count。

有人可以解释一下这种行为吗?

1 个答案:

答案 0 :(得分:1)

事实:

首先让我们先了解data types的一些事实:

  1. 事实#1:分配后复制原始值(数字,字符串,布尔值,...):
  2. 
    
    var a = 5;
    var b = a;
    
    b++;
    
    console.log(a);  // a is still 5
    console.log(b);  // b is 6
    
    
    

    1. 事实#2:不会复制非原始值,但只会传递对它们的引用:
    2. 
      
      var a = { prop: 5 };
      var b = a;
      
      b.prop++;
      
      console.log(a);    // a is changed to ...
      console.log(b);    // ... b's value, because both a and b are pointing to the same object so changing one will alter the other.
      
      
      

      为什么第一个代码不起作用?

      1。 randomString的案例:

      在第一个代码中,您将randomString属性添加到此行返回的对象:

      return { count: count }
      

      显然不会神奇地创建一个名为randomString的新变量,可以在 Component1.js 中的函数内使用。例如,如果您已将该对象存储到名为myObject的变量中,则可以使用myObject.randomString访问该对象。

      2。 count的案例:

      您正在访问上述对象的count属性,该属性是count变量的副本,因为该值是原始值(事实#1 ),改变一个不会影响另一个。因此,当您更新count内的变量listener时,对象的属性count(在 Main.js 中分配给components.compA)不会得到更新。

      修复:

      只需摆脱独立变量并使用对象(从事实#2 中受益):

      module.exports = function () {
          var myObject = { count: 0 };                       // use an object
      
          function listener(e) {
              console.log(myObject.randomString);            // when randomString get assigned on the other side (Main.js) this will be defined
              console.log(myObject.count);                   // use myObject.count not count
              myObject.count++;                              // ... same here
          }
      
          return myObject;                                   // return the object, according to Fact #2, any changes to this object (either on this side or the other) will be reflected, ie both this side and the other point to the same object
      }
      

      现在,当你这样做时:

      var components = { compA: component1(), compB: {} };
      
      Main.js 中的

      myObjectcomponents.compA都指向同一个对象,因此一个对象所做的任何更改都会反映在另一个对象上。如果您向randomString添加components.compA属性,则可以通过myObject.randomString Component1.js 访问该属性。当您在 Component1.js 中增加count时,components.compA.count也会增加,因为事实上两者都是相同的。

      为什么第二个代码有效?

      好吧,因为你有点像上面的修复代码一样。您的init函数只会将其this值赋予变量_this。由于init被调用,因此对象" THE OBJECT" (我们返回的对象),this的值是该对象。所以基本上它与上面的修复代码相同,但你需要一个全新的功能,只是将对象分配给一个变量,即冗余