javascript - 从成员函数对对象所做的更改不会持续存在。范围/引用问题?

标签 javascript node.js object scope reference

我会尽量保持简短。我有两个文件,Main.js 和 Component1.js。我正在尝试实现模块模式,但在事件处理程序中进行更改后,我无法持久化更改。我将在接下来的过程中解释代码,我正在用 nodejs 编写它,这是每个文件的简短版本:

主要.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 个绑定(bind)到监听器的自定义事件后,我得到以下打印输出:

undefined
0

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

undefined
1

但如果我现在在 Main.js 中控制台记录 compA.count,我会看到它仍然为零。

我猜这意味着监听器可以访问不同的范围,因此从另一个 Angular 来看,两者都不会“持久化”(Main.js 的计数 === 0,监听器的字符串未定义) ,或者 compA 和 listener 指的是两个不同的对象?我得出这个结论是因为如果我现在将 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。

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

最佳答案

事实:

首先让我们从关于 data types 的一些事实开始:

  1. 事实 #1:原始值(数字、字符串、 bool 值...)在分配时被复制:

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),更改其中一个不会影响另一个。因此,当您更新变量 count 时里面listener , 属性(property) 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将指向同一个对象,因此一个人所做的任何更改都会反射(reflect)在另一个人身上。如果您添加 randomString属性(property)components.compA ,您可以通过 myObject.randomStringComponent1.js 访问它.当你增加 countComponent1.js 中,components.compA.count也是递增的,因为,事实上,两者是同一个东西。

为什么第二个代码有效?

好吧,因为您的操作与上面的修复代码相同。你的init函数只是分配它的 this变量的值 _this .自 init在“THE OBJECT”(我们返回的对象)上调用,this 的值是那个对象。所以基本上它与上面的修复代码相同,但是您需要一个全新的函数来将对象分配给变量,这是冗余

关于javascript - 从成员函数对对象所做的更改不会持续存在。范围/引用问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50337734/

相关文章:

javascript - RequireJS 订单插件和 Dojo 1.7.1

javascript - 无法监视现有功能

Java 无法将对象从文件转换为数组列表

javascript - 对象分配相同的键不同的值

javascript - 当自动播放激活并到达幻灯片末尾时如何停止滑动 slider ?

javascript - 合并对象数组

javascript - 居中的弹出窗口突然在 Chrome 中不起作用

javascript - 在 Node.js 中创建精美的盒子

javascript - 如何在 Sails.js 中引发自定义错误消息

javascript - 替换 javascript 对象中的字段?使用 splice 和 push,splice 的 indexOf 返回 -1 值?