代码之家  ›  专栏  ›  技术社区  ›  Empha

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

  •  1
  • Empha  · 技术社区  · 7 年前

    我会尽量保持简短整洁。我有两个文件,Main。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";
    

    并更改Component1中的listener()。js收件人

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

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

    undefined
    0
    

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

    undefined
    1
    

    但如果我现在安慰你。记录公司。在Main中计数。我会看到它仍然是零。

    我猜这意味着监听器要么有权访问不同的作用域,因此从另一个角度来看,更改都不会“持久化”(count==0 for Main.js,string undefined for the listener),要么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
    

    正确的计数将保留到组件。公司。计数

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

    1 回复  |  直到 7 年前
        1
  •  1
  •   Community CDub    5 年前

    事实:

    首先,让我们从以下事实开始 data types :

    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 :

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

    return { count: count }
    

    这显然不会神奇地创建一个名为 随机串 可在中的函数内部使用 组成部分1。js公司 。如果已将该对象存储到名为 myObject 例如,您可以使用 myObject.randomString

    2. 的情况 count :

    您正在访问 计数 上述对象的属性,它是 计数 变量,因为该值是基元值( 事实#1 ),更改一个不会影响另一个。因此,当您更新变量时 计数 在…内 listener ,属性 计数 对象的 components.compA 在里面 主要的js公司 )不会更新。

    修复程序:

    只需去掉独立变量并使用对象(从中受益 事实#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: {} };
    

    在里面 主要的js公司 二者都 myObject(我的对象) 组件。compA公司 将指向同一对象,因此一个对象所做的任何更改都将反映在另一个对象上。如果您添加 随机串 属性到 组件。compA公司 ,您可以从 组成部分1。js公司 通过 我的对象。随机串 .当您增加 计数 在里面 组成部分1。js公司 ,则, components.compA.count 也是递增的,因为事实上,两者是相同的。

    为什么第二个代码可以工作?

    好吧,因为您正在执行与上面的修复代码相同的操作。你的 init 函数只分配其 this 变量的值 _this 自从 初始化 在“对象”(我们返回的对象)上调用 就是那个物体。因此,基本上它与上面的修复代码相同,但您需要一个全新的函数来将对象分配给一个变量 冗余的