40

我正在尝试在具有多个名称的键的 JavaScript 脚本中设置对象文字。指的是相同的对象值,即我已经尝试过的类似的东西:

var holidays: {
    "thanksgiving day", "thanksgiving", "t-day": {
        someValue : "foo"
    }
}

var holidays: {
    ["thanksgiving day", "thanksgiving", "t-day"]: {
        someValue : "foo"
    }
}

有没有办法我可以做到这一点?

4

10 回答 10

18

另一种方法是做一些后处理

function expand(obj) {
    var keys = Object.keys(obj);
    for (var i = 0; i < keys.length; ++i) {
        var key = keys[i],
            subkeys = key.split(/,\s?/),
            target = obj[key];
        delete obj[key];
        subkeys.forEach(function(key) { obj[key] = target; })
    }
    return obj;
}

var holidays = expand({
    "thanksgiving day, thanksgiving, t-day": {
        someValue : "foo"
    } 
});
于 2013-02-07T04:54:11.307 回答
17

JSON 不提供这样的功能,Javascript 对象文字也不提供。

您可能可以使用以下方法:

holidays = {
    thanksgiving: {foo: 'foo'},
    groundhogDay: {foo: 'bar'},
    aliases: {
        'thanksgiving day': 'thanksgiving',
        't-day': 'thanksgiving',
        'Bill Murrays nightmare': 'groundhogDay'
    }
}

然后你可以检查

holidays[name] || holidays[holidays.aliases[name]]

为您的数据。

这不是一个很好的解决方案。但是编写一个从以下表示创建这种对象的小函数并不难:

[
    {
        names: ['thanksgiving', 'thanksgiving day', 't-day'],
        obj: {foo: 'foo'}
    },
    {
        names: ['groundhogDay', 'Bill Murrays nightmare'],
        obj: {foo: 'bar'}
    },
]

如果这样更容易维护。

于 2013-02-07T04:41:35.420 回答
7

另一个解决方案,如果你能负担得起 RegExp 执行和 ES6 代理:

let align = new Proxy({
    
    'start|top|left': -1,
    'middle|center': 0,
    'end|bottom|right': 1,

}, {

    get: function(target, property, receiver) {

        for (let k in target)
            if (new RegExp(k).test(property))
                return target[k]

        return null

    }

})

align.start     // -1
align.top       // -1
align.left      // -1

align.middle    // 0
align.center    // 0

align.end       // 1
align.bottom    // 1
align.right     // 1

请参阅MDN 代理

2021 年编辑:使用reducedefineProperty 的
另一个(更清洁?)解决方案:

const myDict = [
    // list of pairs [value, keys],
    // note that a key should appear only once
    [-1, ['start', 'left', 'top']],
    [0, ['center', 'middle']],
    [1, ['end', 'right', 'bottom']],
].reduce((obj, [value, keys]) => {
    for (const key of keys) {
        Object.defineProperty(obj, key, { value })
    }
    return obj
}, {})
于 2017-12-07T14:54:22.183 回答
3

我想你可以做这样的事情:

var holidays = {
  'thanksgiving day': {
    foo: 'foo'
  }
};

holidays.thanksgiving = holidays['t-day'] = holidays['thanksgiving day'];

如果您看到自己经常这样做,或者您有更多的价值观,请考虑以下模式:

'thanksgiving, t-day, thanks, thank, thank u'.split(',').forEach(function(key) {
  holidays[key] = holidays['thanksgiving day'];
});

更好的方法是预先处理您的数据,而不是添加重复数据。

于 2013-02-07T04:30:54.913 回答
2

这应该按预期工作:

function getItem(_key) {
    items = [{
        item: 'a',
        keys: ['xyz','foo']
    },{
        item: 'b',
        keys: ['xwt','bar']
    }];

    _filtered = items.filter(function(item) {
        return item.keys.indexOf(_key) != -1
    }).map(function(item) {
        return item.item;
    });
    return !!_filtered.length ? _filtered[0] : false;
}
于 2017-07-20T17:38:25.923 回答
1

现在这对您来说可能有点过头了,但这里有一个通用函数,它将创建一个具有“多个键”的对象。它实际上所做的是拥有一个具有实际值的真实属性,然后定义 getter 和 setter 将操作从虚拟键转发到实际属性。

function multiKey(keyGroups) {
    let obj = {};
    let props = {};

    for (let keyGroup of keyGroups) {
        let masterKey = keyGroup[0];
        let prop = {
            configurable: true,
            enumerable: false,

            get() {
                return obj[masterKey];
            },

            set(value) {
                obj[masterKey] = value;
            }
        };

        obj[masterKey] = undefined;
        for (let i = 1; i < keyGroup.length; ++i) {
            if (keyGroup.hasOwnProperty(i)) {
                props[keyGroup[i]] = prop;
            }
        }
    }

    return Object.defineProperties(obj, props);
}

这比您预期的要粗略,一旦创建对象就基本上没有性能损失,并且在枚举(for...in循环)和成员资格测试(in运算符)方面表现良好。这是一些示例用法:

let test = multiKey([
    ['north', 'up'],
    ['south', 'down'],
    ['east', 'left'],
    ['west', 'right']
]);

test.north = 42;
test.down = 123;

test.up; // returns 42
test.south; // returns 123

let count = 0;
for (let key in test) {
    count += 1;
}

count === 4; // true; only unique (un-linked) properties are looped over

取自我的 Gist,你可以分叉。

于 2016-08-18T19:05:24.403 回答
1

相同的响应(ES6 Proxy、RegExp),但方式更短(并且可读性显着降低)

let align = new Proxy({

    'start|top|left': -1,
    'middle|center': 0,
    'end|bottom|right': 1,

}, { get: (t, p) => Object.keys(t).reduce((r, v) => r !== undefined ? r : (new RegExp(v).test(p) ? t[v] : undefined), undefined) })

align.start     // -1
align.top       // -1
align.left      // -1

align.middle    // 0
align.center    // 0

align.end       // 1
align.bottom    // 1
align.right     // 1
于 2017-12-07T15:06:56.520 回答
1

使用 ES6 你可以这样做,但这并不理想:

const holidays = {
    "single": {
        singleValue: "foo",
    },

    ...([
        "thanksgiving day", "thanksgiving", "t-day",
    ].reduce((a, v) => ({...a, [v]: {
        someValue: "foo",
    }}), {})),

    "other": {
        otherValue: "foo",
    },
};

我仍然认为最干净的解决方案可能是:

let holidays = {
    "t-day": {
        someValue: "foo",
    },
};
holidays["thanksgiving"] = holidays["t-day"];
holidays["thanksgiving day"] = holidays["t-day"];
于 2018-06-12T08:25:44.910 回答
0
//create some objects(!) you want to have aliases for..like tags
var {learn,image,programming} = 
 ["learn", "image", "programming"].map(tag=>({toString:()=>tag }));


//create arbitrary many aliases using a Map
var alias = new Map();
alias.set("photo", image);
alias.set("pic", image);
alias.set("learning", learn);
alias.set("coding", programming);

//best put the original tagNames in here too.. 
//pretty easy huh? 

// returns the image object 
alias.get("pic");

// ;)
于 2017-09-02T14:20:57.677 回答
0

这是一种使用共享相同值的多个键初始化对象的方法

var holidays = {
    ...["thanksgiving day", "thanksgiving", "t-day"].reduce((acc, key) => ({ ...acc, [key]: 'foo' }), {})
}

虽然我个人认为如果写出来会更清楚

于 2021-05-13T19:59:15.803 回答