javascript - 对象不可变?

时间:2012-09-25 22:41:54

标签: javascript

我正在尝试创建一些树形结构。

我希望按如下方式访问我的数据:

data[key1][key2]

但是,key1和key2具有对称关系;以下情况总是如此:

data[key1][key2] == data[key2][key1]

更具体地说,我data[key1][key2]data[key2][key1]指向同一个对象,因此对一个对象的更改会影响另一个对象。

我的问题出现了,因为我希望删除基础对象。我知道我是否使用:

delete data[key1][key2];

data[key2][key1]仍然引用该对象。

我的问题是:有没有办法删除底层对象,或用虚假的东西覆盖它,这样上面的两个属性都会评估为false?

3 个答案:

答案 0 :(得分:3)

这样想:

data[key1][key2] -----> object1
                          ^
data[key2][key1] ---------+

如果你将其中一个(比如说后者)的密钥更改为新对象,你就会得到这个:

data[key1][key2] -----> object1

data[key2][key1] -----------> object2

(或者,如果删除它,密钥将会丢失:)

data[key1][key2] -----> object1

data[key2]

也就是说,您将更改其中一个引用但不更改另一个引用。任何只替换其中一个的尝试都可以实现这一目标。您有两种选择:

a)更改两个键以指向新对象:

data[key1][key2] -----> object2
                          ^
data[key2][key1] ---------+

(或删除两个键:)

data[key1][key2]       object1 (no references, will be garbage collected)

data[key2][key1]

b)修改对象本身的字段。这样他们两个仍然会指向同一个对象,但有关它的东西会有所不同。但是,您使用的任何代码都必须考虑到这一点。

data[key1][key2] -----> object1 with 'isDeleted'=true
                          ^
data[key2][key1] ---------+

根据您的使用案例,a)选项似乎最有意义。如果你还有两个键,为什么不更新/删除它们?

答案 1 :(得分:1)

valueOf()方法可能会提供解决方案。如果您正在对布尔值进行显式比较,则valueOf将作为类型转换为布尔值的一部分进行调用。例如,假设您的数据结构引用了一些对象x ...

> x = {}
Object
> (x == false ? 'yes' : 'no')
"no"
> x.valueOf = function() {return false;}
function () {return false;}
> (x == false ? 'yes' : 'no')
"yes"

...即如果data[key1][key2] == data[key2][key1] == x,那么分配x.valueOf = function() {return false;}会将x评估为时显式更改为布尔。因此,只要您测试的是data[key1][key2] == falsex就应该是假的。

但是,您需要小心这一点,因为x比原始值更少虚假。例如。即使在如上所述分配valueOf之后,隐式强制仍然看起来很简单......

(x ? 'yes' : 'no')
"yes"

答案 2 :(得分:1)

你可能从其他答案中得到了你需要的东西,但总结一下:

  

我的问题是:有没有办法删除基础对象

没有。您可以删除对它的所有引用,以使其可用于垃圾回收。当垃圾收集器运行时(在某个未指定的时间),它将删除该对象。

  

或用falsey覆盖它,以便上面的两个属性都会评估为falsey?

不完全是。您只能为每个属性分配一个新值,以便它们计算为false(false,null,undefined,0等)。对象不跟踪引用它们的标识符,因此没有通用的方法来说明“删除对该对象的所有引用”。如果你想这样做,你必须自己跟踪引用并改变它们的值。

另一种方法是给对象一个属性以指示是否应该使用它(例如“过时”),这可以在访问其他属性时进行检查。公共属性非常简单,或者您可以使用构造函数中的闭包创建“私有”成员:

function Foo() {
  var obsolete = false;

  this.obsolete = function (){
    return obsolete;
  };

  this.delete = function (){
    obsolete = true;
  };
}

var foo = new Foo();
var bar = new Foo();

alert(foo.obsolete() + ', ' + bar.obsolete()); // false, false

foo.delete();

alert(foo.obsolete() + ', ' + bar.obsolete()); // true, false

这将与你想要的一样工作。如果你可以删除你需要做的对象:

if ( data[key1][key2] ) {
  // do stuff
}

使用上述方法:

if ( !data[key1][key2].obsolete() ) {
  // do stuff
}

注意到对象仍然存在。您可能希望将过时更改为当前并反转布尔值,以便检查if (obj.current())而不是if (!obj.obsolete())。无论什么都适合。