Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/33.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JavaScript:向可能不存在的对象添加嵌套属性_Javascript_Node.js_Object - Fatal编程技术网

JavaScript:向可能不存在的对象添加嵌套属性

JavaScript:向可能不存在的对象添加嵌套属性,javascript,node.js,object,Javascript,Node.js,Object,假设我有一个json对象,其中记录了我的站点的访问者数量,按浏览器/版本分组 let data = { browsers: { chrome: { 43 : 13, 44 : 11 }, firefox: { 27: 9 } } } 要增加一个特定的浏览器,我需要检查是否存在多个键,如果不存在,则创建它们 let uap = UAParser(r

假设我有一个json对象,其中记录了我的站点的访问者数量,按浏览器/版本分组

let data = {
    browsers: {
        chrome: {
           43 : 13, 
           44 : 11
        }, 
        firefox: {
           27: 9
        }
    }
}
要增加一个特定的浏览器,我需要检查是否存在多个键,如果不存在,则创建它们

let uap = UAParser(request.headers['user-agent']);

if (typeof uap.browser !== 'undefined') {

    if (typeof data.browsers === 'undefined') 
        data.browsers = {}

    if (typeof data.browsers[uap.browser.name] === 'undefined')
        data.browsers[uap.browser.name] = {}

    if (typeof data.browsers[uap.browser.name][uap.browser.version] === 'undefined')
        data.browsers[uap.browser.name][uap.browser.version] = 0

    data.browsers[uap.browser.name][uap.browser.version] += 1;
}
我的数据结构越深,事情就越疯狂


感觉必须有一种更简洁的方式在javascript中实现这一点。总有更整洁的方法。这里有人能给我点化一下吗

您可以放弃if语句,这样做:

uap.browser = uap.browser || {}

本质上,它与if相同,只是要短得多

您可以放弃if语句,这样做:

uap.browser = uap.browser || {}

从本质上讲,它与if相同,只不过要短得多

这个较短的代码应该可以实现以下功能:

if (uap.browser) { // typeof is pretty much redundant for object properties.
    const name = uap.browsers.name; // Variables for readability.
    const version = uap.browser.version;

    // Default value if the property does not exist.
    const browsers = data.browsers = data.browsers || {}; 
    const browser = browsers[name] = browsers[name] || {};
    browser[version] = browser[version] || 0;

    // Finally, increment the value.
    browser[version]++;
}
请注意,您使用的是===您应该在==={}中使用的===位置

让我们解释一下这句话:

const browsers = data.browsers = data.browsers || {};
最后一部分:data.browsers=data.browsers | |{}将data.browsers设置为自身(如果存在)。如果还没有,它将被设置为一个新的空对象。 然后,为了便于访问,将整个值分配给浏览器


现在,较短的代码不应该是最优先的,但在这种情况下,您可以使代码更具可读性。

这段较短的代码应该可以做到:

if (uap.browser) { // typeof is pretty much redundant for object properties.
    const name = uap.browsers.name; // Variables for readability.
    const version = uap.browser.version;

    // Default value if the property does not exist.
    const browsers = data.browsers = data.browsers || {}; 
    const browser = browsers[name] = browsers[name] || {};
    browser[version] = browser[version] || 0;

    // Finally, increment the value.
    browser[version]++;
}
请注意,您使用的是===您应该在==={}中使用的===位置

让我们解释一下这句话:

const browsers = data.browsers = data.browsers || {};
最后一部分:data.browsers=data.browsers | |{}将data.browsers设置为自身(如果存在)。如果还没有,它将被设置为一个新的空对象。 然后,为了便于访问,将整个值分配给浏览器


现在,更短的代码不应该是最重要的,但在这种情况下,您可以使代码更具可读性。

这里有一个使用代理的非常干净和通用的解决方案,我有第二个解决方案,它是标准的ECMAscript 5,如果您不需要它,或者不需要它太依赖于浏览器

var handler = {
    get: function (target, property) {
        if (property !== "toJSON" && target[property] === undefined) {
            target[property] = new Proxy ({}, handler);
        }
        return target[property];
    }
}
var jsonProxy = new Proxy ({}, handler);

jsonProxy.non.existing.property = 5;
jsonProxy.another.property.that.doesnt.exist = 2;
jsonProxy["you"]["can"]["also"]["use"]["strings"] = 20;

console.log (JSON.stringify (jsonProxy));
您可以对类执行相同的操作,但使用更详细的语法:

var DynamicJSON = function () {};
DynamicJSON.prototype.get = function (property) {
    if (this[property] === undefined) {
        this[property] = new DynamicJSON ();
    }
    return this[property];
};
DynamicJSON.prototype.set = function (property, value) {
    this[property] = value;
};

var jsonClass = new DynamicJSON ();
jsonClass.get("non").get("existing").set("property", 5);
jsonClass.get("you").get("have").get("to").get("use").set("strings", 20);

console.log (JSON.stringify (jsonClass));

这里有一个使用代理的非常干净和通用的解决方案,我还有第二个解决方案,它是标准的ECMAscript 5,如果您不需要它那么干净,或者不需要太依赖浏览器

var handler = {
    get: function (target, property) {
        if (property !== "toJSON" && target[property] === undefined) {
            target[property] = new Proxy ({}, handler);
        }
        return target[property];
    }
}
var jsonProxy = new Proxy ({}, handler);

jsonProxy.non.existing.property = 5;
jsonProxy.another.property.that.doesnt.exist = 2;
jsonProxy["you"]["can"]["also"]["use"]["strings"] = 20;

console.log (JSON.stringify (jsonProxy));
您可以对类执行相同的操作,但使用更详细的语法:

var DynamicJSON = function () {};
DynamicJSON.prototype.get = function (property) {
    if (this[property] === undefined) {
        this[property] = new DynamicJSON ();
    }
    return this[property];
};
DynamicJSON.prototype.set = function (property, value) {
    this[property] = value;
};

var jsonClass = new DynamicJSON ();
jsonClass.get("non").get("existing").set("property", 5);
jsonClass.get("you").get("have").get("to").get("use").set("strings", 20);

console.log (JSON.stringify (jsonClass));

现在已经有一个很好的库来进行这样的操作——lodash。它有一个方法可以满足您的需要:u.setobject'a[0].b.c',4;使用Object.prototype.hasOwnProperty而不是typeof…@DenisGiffeler这似乎是一种更长的方法。我想缩短我的时间code@alexmac我想避免使用lodash或任何其他库来进行此操作-寻找更整洁的方法-已经有一个非常好的库来进行此类操作-lodash。它有一个方法可以满足您的需要:u.setobject'a[0].b.c',4;使用Object.prototype.hasOwnProperty而不是typeof…@DenisGiffeler这似乎是一种更长的方法。我想缩短我的时间code@alexmac我想避免使用lodash或任何其他库来实现这一点——寻找更简洁的香草JSoop。是的,我看到了===应该在哪里==-谢谢that@roryok:np。我添加了一个关于较短代码的免责声明。最后,您希望实现可读性,这可能并不一定意味着名称/版本越短越好。谢谢你接受这个答案!哎呀。是的,我看到了===应该在哪里==-谢谢that@roryok:np。我添加了一个关于较短代码的免责声明。最后,您希望实现可读性,这可能并不一定意味着名称/版本越短越好。谢谢你接受这个答案!