3

In JavaScript I want to do the following:

var pi = {}; pi[0]['*']['*'] = 1;

of course this throws a "Cannot read property '*' of undefined" error. Clearly I can define p[0] = {}, but that's kind of a pain as I will be sticking lots of different values in the different attributes, e.g.

pi[2]['O']['I-GENE'] = 1;

etc. The first key into the hash is just an integer, so I guess I could use an array at the top level instead of a hash, and then default initialize like in this post:

default array values

but that doesn't handle my need for default initialization of the other hashes.

It does seem like what I am trying to do is running up against the ECMAScript spec which indicates that undefined attributes of an object (which is a hash in JavaScript) should return undefined, as mentioned here:

Set default value of javascript object attributes

which interestingly includes a dangerous work around.

In other places where I'm trying use nested hashes like this I am finding myself writing long bits of ugly code like this:

function incrementThreeGramCount(three_grams,category_minus_two,category_minus_one,category){
    if(three_grams[category_minus_two] === undefined){
      three_grams[category_minus_two] = {};
    }
    if(three_grams[category_minus_two][category_minus_one] === undefined){
      three_grams[category_minus_two][category_minus_one] = {};
    }
    if(three_grams[category_minus_two][category_minus_one][category] === undefined){
      three_grams[category_minus_two][category_minus_one][category] = 0;
    }
    three_grams[category_minus_two][category_minus_one][category]++;
}

which I'd really like to avoid here, or at least find some good way of adding to the functionality of the Hash through the prototype method. However it seems like since the Hash and Object in JavaScript are just the same thing, we can't really play around with default hash behaviour in JavaScript without impacting a lot of other things ...

Maybe I should be writing my own Hash class ... or using Prototypes:

http://prototypejs.org/doc/latest/language/Hash/

or someone elses:

http://www.daveperrett.com/articles/2007/07/25/javascript-hash-class/

or mootools:

http://mootools.net/docs/more/Types/Hash

argh, so many choices - wish I knew the best practice here ...

4

4 回答 4

2

这可以使用ES6 代理来完成。您将使用get处理程序在对象上定义代理。当get对具有undefined值的键或对象没有自己的属性的键执行 a 时,您将其设置为使用相同get处理程序的新代理并返回该新代理。

此外,这无需括号语法即可工作:

var obj = ...;
obj.a.b.c = 3;

不幸的是,作为 ES6 功能,它们的支持仅限于 Firefox,并且可以在 Chrome 中使用实验标志启用。

于 2013-04-11T09:30:46.310 回答
1

我会做这样的事情:

Object.prototype.get = function(v){ 
    if(!this[v]){
        this[v] = {} 
    } 

    return this[v];  
}

然后,改为object["x"]["y"].z = 666使用object.get("x").get("y").z = 666.

于 2013-04-11T09:25:35.533 回答
0

您可以编写一个简单的助手来执行此操作。例如

function setWDef() {
    var args = [].slice.call(arguments);
    var obj = args.shift();
    var _obj = obj;
    var val = args.pop();
    if (typeof obj !== "object") throw new TypeError("Expected first argument to be of type object");
    for (var i = 0, j = args.length - 1; i < j; i++) {
        var curr = args[i];
        if (!_obj[curr]) _obj[curr] = {};
        _obj = _obj[curr];
    }
    _obj[args.pop()] = val;
    return obj;
}   

现在只需使用函数设置值

var pi ={}
console.log (setWDef(pi,"0","*","a*",1)) //{"0": {"*": {"a*": 1}}}

这是一个关于JSBin的演示

于 2013-04-11T09:36:49.323 回答
0

使用草拟的 逻辑 OR 赋值运算符 ||=,您可以执行以下操作:

 const pi = [];
 ((((pi[0]||={})['*'])||={})['*'] = 1);
 console.log(JSON.stringify({pi}));

输出:

{"pi":[{"*":{"*":1}}]}

您还可以将某些级别初始化为数组或定义默认属性值:

const pi = [];
((((((pi[0]||={})['*'])||=[])[3])||={'#':2})['*'] = 1);
console.log(JSON.stringify({pi}));

输出:

{"pi":[{"*":[null,null,null,{"#":2,"*":1}]}]}
于 2021-02-27T18:07:12.577 回答