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



我会尽量保持简短和整洁。我有两个文件,主文件.js和组件 1.js。我正在尝试实现模块模式,但在事件处理程序中进行更改后,我在获取更改以保留时遇到问题。我将在进行过程中解释代码,我正在用nodejs编写它,这是每个文件的简短版本:

主.js

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

组件1.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";

并将组件 1.js 中的侦听器(( 更改为

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

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

undefined
0

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

undefined
1

但如果我现在控制台.log Main中的compA.count.js我会看到它仍然是零。

我猜这意味着侦听器要么可以访问不同的范围,因此从另一个的角度来看都不会更改"持久化"(Main.js的计数 === 0,侦听器的字符串未定义(,或者 compA 和侦听器引用两个不同的对象?我得出这个结论是因为如果我现在将组件 1.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. 事实 #1:分配时会复制基元值(数字、字符串、布尔值等(:

var a = 5;
var b = a;
b++;
console.log(a);  // a is still 5
console.log(b);  // b is 6

  1. 事实 #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(,因此更改一个不会影响另一个。因此,当您更新listener内部的变量count时,对象的属性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组件 1.js访问它。当您在Component1.js中递增count时,components.compA.count也会递增,因为实际上两者是一回事。

为什么第二个代码有效?

好吧,因为您正在执行与上述修复代码相同的操作。您的init函数只是将其this值分配给变量_this。由于init是在"THE OBJECT"(我们返回的对象(上调用的,因此this的值就是该对象。所以基本上它与上面的修复代码相同,但你需要一个全新的函数来将对象分配给一个变量,这是多余的

最新更新