对象不可变



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

我希望访问我的数据如下:

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覆盖它,这样上面的两个属性都会计算false?

这样想:

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)选项似乎最有意义。如果两个密钥都有,为什么不同时更新/删除呢?

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"

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

我的问题是:有没有任何方法可以删除底层对象

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

或者用false覆盖它,这样上面的两个属性都会计算false?

不完全是。您只能为每个属性分配一个新值,以便它们的值为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())。随便什么。

最新更新