5

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

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

data[key1][key2]

但是key1和key2是对称关系;以下情况总是正确的:

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

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

我的问题出现是因为我希望删除底层对象。我知道我是否使用:

delete data[key1][key2];

data[key2][key1]仍然指对象。

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

4

3 回答 3

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) 选项似乎最有意义。如果您仍然拥有两个密钥,为什么不更新/删除两者?

于 2012-09-25T22:52:34.920 回答
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"
于 2012-09-25T23:25:52.217 回答
1

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

我的问题是:有什么方法可以删除底层对象

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

或者用虚假的东西覆盖它,这样上面的两个属性都会评估虚假?

不完全是。您只能为每个属性分配一个新值,以便它们评估为 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
}

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

于 2012-09-25T23:54:57.577 回答