用于修改参数中的对象的函数,而不仅仅是属性

时间:2013-05-13 01:14:12

标签: javascript object

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

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

请注意,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”?

4 个答案:

答案 0 :(得分:8)

这是不可能的。

让您感到困惑的是,在js运行时,您无法管理实际参考值,但只能为变量分配一些参考值。

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

清除我上面所说的内容:对象的内存是在其初始化

上分配的
var o = {};

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

答案 1 :(得分:3)

我将假设您已阅读我的解释: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);
    }
};

答案 2 :(得分:1)

引用只是变量,就像基元一样。重新分配 更改其值。

你说

  

并且不重新分配对象,但更新整个引用。

问题在于那些意味着同样的事情。如果您的意思是更新另一个指向此对象的引用以指向其他内容,则只有在其他引用位于您的范围内时才能执行此操作。

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

//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"

答案 3 :(得分:0)

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

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