有没有办法改变/重定向“间接”自我引用?

时间:2016-08-12 17:07:05

标签: javascript object knockout.js merge self-reference

我正在使用Knockout.js开发一个网站,但我的问题更为笼统,所以不要专注于此。

我通过变量名引用自身内的对象,在本例中为viewModel,如下所示:

var viewModel = {
    propA: "propA",
    fnA: function () {
        alert("I am " + viewModel.propA); //the same as this.propA
    }
};

这样,在涉及子对象和其他“花哨”的东西时,我不会遇到任何麻烦。

现在,我需要将另一个对象合并到我的viewModel中,但是我遇到了一个引用问题:

g_test = {}; //The way with this global variable is just for demonstration purposes

(function () {
    var viewModel = {
        propA: "propA",
        fnA: function () {
            alert("I am " + viewModel.propB);
        }
    };
    g_test.vmA = viewModel;
})();

(function () {
    var viewModel = {
        propB: "propB",
        fnB: function () {
            alert("I am " + viewModel.propA);
        }
    }

    /** merge viewModel "A" into viewModel "B" */
    var vmA = g_test.vmA;
    for (var key in vmA) {
        if (vmA.hasOwnProperty(key)) {
            viewModel[key] = vmA[key];
        }
    }

    viewModel.fnA(); //I am undefined
    viewModel.fnB(); //I am propA
})();

如您所见,fnB知道propA,但fnA不知道propB

然后使用this作为对viewModel对象的引用。但是我不希望遍历我的整个对象并用viewModel替换每个this或者在需要时引入相应的“辅助变量”,因为这需要我很长时间。另外,对我来说,这意味着合并两个没有彼此双向知识的物体是不可能的。

是否有一种让viewModel中的fnA变量指向viewModel“B”而不必知道viewModel“B”的有意义方法?

1 个答案:

答案 0 :(得分:0)

创建多个viewModel然后尝试合并它们似乎是一个有问题的方法,我不知道你想用它实现什么。可能有更好的方法(至少,使用this是创建mixins)的正确选择。但是假设现在有一个很好的理由或者现在重做它的努力太多了,让我们来看看你的问题。

您有两个viewModel,并且您希望以这样的方式合并它们,即每个都知道另一个的成员。你在一个方向合并它们,所以B知道A,但A不知道B.你需要合并另一个方向。 Object.assign是执行循环操作的便捷方式,但如果您使用的是Object.assign之前的浏览器,则可以添加另一个遍历viewModel的循环并将其中的属性复制到vmA

结果是你有两个viewModel,它们的方法相互引用。每个都有propApropBfnAfnB,但fnA(在两个对象中)都指对象A的成员和反之亦然。

g_test = {}; //The way with this global variable is just for demonstration purposes

function mergeObjects(obj1, obj2) {
  Object.assign(obj1, obj2);
  Object.assign(obj2, obj1);
}

(function() {
  var viewModel = {
    propA: "propA",
    fnA: function() {
      alert("fnA: I am " + viewModel.propB);
    }
  };
  g_test.vmA = viewModel;
})();

(function() {
  var viewModel = {
    propB: "propB",
    fnB: function() {
      alert("fnB: I am " + viewModel.propA);
    }
  }

  mergeObjects(g_test.vmA, viewModel);

  // to demonstrate which value is outputted by which function
  g_test.vmA.propA = "A.propA";   // not used
  g_test.vmA.propB = "A.propB";   // used by fnA
  viewModel.propA = "B.propA";    // used by fnB
  viewModel.propB = "B.propB";    // not used

  viewModel.fnA(); //I am A.propB
  viewModel.fnB(); //I am B.propA
  // also
  g_test.vmA.fnA();
  g_test.vmA.fnB();
})();