【问题标题】:Function to modify object in arguments, not just a property修改参数中的对象的函数,而不仅仅是属性
【发布时间】:2013-05-13 01:14:12
【问题描述】:

我确定这一定存在于某个地方,但我一直无法找到它...

我正在尝试编写一个将对象作为参数并更新其引用的函数。不是引用的属性,也不是重新分配对象,而是更新整个引用。

请注意,PubSub 只是为了证明传入和更新的对象类型需要异步性和灵活性。

最好的例子解释:

//ideally how function would work
function watch(event, obj) {
    PubSub.on(event, function(model) {
        // I want to update the entire object
        // I understand that currently, this is just reassigning
        // I know I can do obj.prop = model, but that's not what I want to do
        obj = model;
    }
};

//example usage
var myObj = {"name" : "Tom"};
watch("anEvent", myObj);
console.log(myObj.name); //still "Tom"

// time passes, then somewhere
PubSub.trigger("anEvent", {"name" : "John"})

console.log(myObj.name); // now should read "John"

这是一种bind() 方法的场景,例如$.bind() 或 currying 会很有用,还是只是为了在适当的上下文中使用“this”?

【问题讨论】:

标签: javascript object


【解决方案1】:

这是不可能的。

让你感到困惑的是,在 js 运行时你没有办法管理实际的引用值,而只能为变量分配一些引用值。

就是这样 - 您可以“附加”另一个对给定变量名称的引用,但不能修改引用值。

为了澄清我上面所说的:对象的内存是在其初始化时分配的

var o = {};

之后,对未命名对象的引用(对象没有名称,变量有)被分配给o 变量。之后,您无法将另一个对象重新分配到内存中的同一位置。

【讨论】:

  • 感谢您的反对。我敢肯定,downvoter 可以证明我错了。你能? :-)
  • 不是投反对票的人,但我猜是因为你没有解释原因。
  • 很高兴看到开车兜风仍然很流行。 :-)
  • 我不关注。引用变量有一个值。还有什么? “管理”参考值是什么意思?
  • @Brandon:“引用变量有值”---变量有值。没有任何“参考变量”。有时值是对对象的引用。您可以修改变量的值。但是你不能替换一个对象,它是一个参考值。
【解决方案2】:

我假设你已经阅读了我的解释:Why are objects' values captured inside function calls?

如果你明白发生了什么。而且你想得够辛苦。您会看到明显的变通方法。

因此,与其他所有人的回答相反,我要说的是:是的,这是可能的(在限制范围内)。


解决方法

首先,回顾一下。你意识到你所拥有的实际上是对同一个对象的两个不同的引用?分配一个引用不会导致另一个引用被重新分配:

var foo = {some : 'values'};
(function (bar) {
    // 'bar' in here points to the
    // same object as foo but is a
    // completely different reference
})(foo)

// is it obvious yet?

所以,虽然直截了当的 bar = new_object 不起作用。意识到这两个引用都指向您感兴趣的同一个对象

这意味着,即使您无法访问原始引用(在我的示例中为“foo”,在您的示例中为“myObj”),您所拥有的是它指向的对象。这是我们可以利用的。

如果您不关心当前对象会发生什么,并且您不介意对该对象的所有引用都被修改,您可以简单地对其所有属性进行深度删除并用深度副本替换它们新对象。

所以,虽然你不能这样做:

obj = model;

你可以这样做:

for (var n in obj) {
    if (obj.hasOwnProperty(n)) {
        delete(obj[n]);
    }
}
for (var n in model) {
    if (model.hasOwnProperty(n)) {
        obj[n] = model[n];
    }
}

并且您的代码应该可以按预期工作。

如果你经常这样做(或者如果你只是想让你的代码更具可读性),你可以封装这个逻辑:

function reassignObjRef (ref, new_obj) {
  for (var n in ref) {
    if (ref.hasOwnProperty(n)) {
      delete(ref[n]);
    }
  }
  for (var n in new_obj) {
    if (new_obj.hasOwnProperty(n)) {
      ref[n] = new_obj[n];
    }
  }
}

所以你可以简单地做:

function watch(event, obj) {
    PubSub.on(event, function(model) {
        reassignObjRef(obj,model);
    }
};

【讨论】:

    【解决方案3】:

    引用只是变量,就像原语一样。重新分配它正在改变它的值。

    你说

    而不是重新分配对象,而是更新整个引用。

    问题是它们的意思是一样的。如果您的意思是更新指向该对象的另一个引用以指向其他内容,那么只有在另一个引用在您的范围内时才能这样做。

    没有办法说,给定一个特定对象的引用,将所有对该对象的引用更改为指向其他对象。听起来这就是你想要做的。对不起,不可能。您需要一个具有属性的中间对象,该属性是您要更改的引用。

    //ideally how function would work
    function watch(event, obj) {
        PubSub.on(event, function(model) {
            // I want to update the entire object
            // I understand that currently, this is just reassigning
            // I know I can do obj.prop = model, but that's not what I want to do
            obj.model = model;
        }
    };
    
    //example usage
    var myObj = {model: {"name" : "Tom"}};
    watch("anEvent", myObj);
    console.log(myObj.model.name); //still "Tom"
    
    // time passes, then somewhere
    PubSub.trigger("anEvent", {"name" : "John"})
    
    console.log(myObj.name); // now should read "John"
    

    【讨论】:

    • 关于:if the other reference is in your scope,我想说一点也不,因为要执行 OP 想要的操作,您需要知道引用该对象的所有其他变量。而且由于甚至无法知道当前范围内的所有变量(您不能在范围、变量或执行上下文对象上 for..in),因此您当然不能在其他范围内这样做。跨度>
    • 正确。这就是我想说的是,您必须有权访问您范围内的所有引用,并希望它们没有被修改。不太现实。
    【解决方案4】:

    没有办法知道或找到对一个对象的所有引用,因此没有通用的方法来重新分配对某个其他对象的所有引用。您可以使用闭包和getset 方法静态地执行此操作(请参阅Douglas Crockford 的Private Members in Javascript),但这似乎不是您想要的。

    另外,bind 特定于函数的 this 变量,它是函数execution context 的一个参数。它与范围无关。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-04-14
      • 1970-01-01
      • 1970-01-01
      • 2013-05-17
      • 2022-06-12
      • 1970-01-01
      • 1970-01-01
      • 2011-09-09
      相关资源
      最近更新 更多