添加到可能存在也可能不存在的 json 属性

Posted

技术标签:

【中文标题】添加到可能存在也可能不存在的 json 属性【英文标题】:adding to json property that may or may not exist yet 【发布时间】:2011-02-01 07:51:57 【问题描述】:

假设我想这样做:

  var dashboard = ;
  var page = "index";

  $('.check').click(function() 
    $(this).toggleClass("active").siblings().slideToggle('slow', function() 
        dashboard['pages'][page][$(this).closest('li').attr("id")]['show'] = $(this).is(":hidden") ? 'collapsed' : 'expanded';
    );
  

我收到一条错误消息:

Dashboard.pages 未定义

是否可以动态添加pages 和随后的子代,而无需检查它是否先定义,然后再检查是否定义:

   dashboard['pages'] = ;

因为有时它们可​​能已经存在,我不想先检查树,我只想根据需要构建分支

编辑 我将pagename 更改为page 以表明页面名称会发生​​变化,而且我想指出这些页面实际上也可以是任何东西。 这个想法是你有任何对象可以包含带有参数的对象,而无需检查分支是否存在

看起来$extend 如前所述将是可行的方法,只是不确定它是如何工作的。必须解决这个问题。

【问题讨论】:

抱歉 - 脚本对我来说毫无意义。使用括号索引器意味着希望动态索引对象,但您使用的是常量。再加上你“不想做这项工作”的说法,我想知道是否知道你想要完成什么。不是试图诋毁 - 只是观察一下为什么您可能无法得到您正在寻找的答案。 ES6 的更好解决方案在这里。 ***.com/a/52471690/10405671 【参考方案1】:

Object 上定义 get 和 set 方法。实际上它可以只在 dashboard 对象上定义,而且只在它的后代上,但这很容易做到。

Object.prototype.get = function(prop) 
    this[prop] = this[prop] || ;
    return this[prop];
;

Object.prototype.set = function(prop, value) 
    this[prop] = value;

使用此get() 方法遍历嵌套属性,并在必须设置值时调用set()

var dashboard = ;

dashboard.get('pages').get('user').set('settings', 'oh crap');
// could also set settings directly without using set()
dashboard.get('pages').get('user').settings = 'oh crap';

console.log(dashboard); //​​​​​​​​​​​​​​​ pages: user: settings: "oh crap";

您还可以扩展/修改get 方法以接受嵌套属性作为单独的参数数组字符串。使用它,您只需调用一次 get:

// get accepts multiple arguments here
dashboard.get('pages', 'user').set('settings', 'something');

// get accepts an array here
dashboard.get(['pages', 'user']).set('settings', 'something');

// no reason why get can't also accept dotted parameters
// note: you don't have to call set(), could directly add the property
dashboard.get('pages.user').settings = 'something';

更新

由于get方法一般返回一个对象,不知道你需要一个数组还是其他类型的对象,所以你必须自己指定:

dashboard.get('pages.user').settings = [];

然后您可以将项目推送到设置数组

dashboard.get('pages.user').settings.push('something');
dashboard.get('pages.user').settings.push('something else');

要真正让 get 函数从给定字符串(例如 pages.user)构造对象层次结构,您必须将字符串拆分为多个部分并检查每个嵌套对象是否存在。这是 get 的修改版本,它就是这样做的:

Object.prototype.get = function(prop) 
    var parts = prop.split('.');
    var obj = this;
    for(var i = 0; i < parts.length; i++) 
        var p = parts[i];
        if(obj[p] === undefined) 
            obj[p] = ;
        
        obj = obj[p];
    
    return obj;


// example use
var user = dashboard.get('pages.user');
user.settings = [];
user.settings.push('something');
user.settings.push('else');

console.log(dashboard); // pages: user: settings: ["something", "else"] 

// can also add to settings directly
dashboard.get('pages.user.settings').push('etc');

【讨论】:

好的,这看起来像我要求的,除了我没有使用原型我将如何在 jquery 中执行此操作?也让我更进一步让我说我想这样做,所以我有 dashboard.get('pages.user.settings').push("something"); dashboard.get('pages.user.settings').push("somethingelse");那应该在设置中给我两个项目吧? @mmcgrail,这是常规的 javascript,而不是 Prototype 框架。获取每个属性的第一种方法应该适用于每个浏览器(不需要 jquery)。更新其他查询的答案。 我会告诫不要以这种方式盲目地添加到Object 的原型中。【参考方案2】:

我会用三元运算符来做:

dashboard['pages'][page] = dashboard['pages'][page] ? dashboard['pages'][page] : ;

无论它是设置/为空还是其他,这都可以解决问题。

【讨论】:

【参考方案3】:

我不认为有一个好的内置方法可以做到这一点,但你总是可以用一个函数来抽象它。

function getProperty(obj,prop)
    if( typeof( obj[prop] ) == 'undefined' )
        obj[prop] = ;
    
    return obj[prop];

那你就用

getProperty(dashboard,'pages')['pagename']

getProperty(getProperty(dashboard,'pages'),'pagename');

如前所述,$.extend 将减轻这方面的负担。

【讨论】:

【参考方案4】:

对我来说最好的解决方案是做一个对象原型

 /**
 * OBJECT GET
 * Used to get an object property securely
 * @param object
 * @param property
 * @returns *
 */
Object.get = function(object, property) 
    var properties = property.split('.');
    for (var i = 0; i < properties.length; i++) 
        if (object && object[properties[i]]) 
            object = object[properties[i]];
        
        else 
            return null;
        
    
    return object;
;

然后你可以像这样得到你的财产

var object =  step1:  step2:  step3: ['value1', 'value2'] 
Object.get(object, 'step1.step2.step3'); // ['value1', 'value2']
Object.get(object, 'step1.step2.step3.0'); // 'value1'
Object.get(object, 'step1.step2.step3.step4'); // null

希望对你有帮助:)

【讨论】:

【参考方案5】:
var foo = dashboard['pages'] || ;
foo['pagename'] = 'your thing here';
dashboard['pages'] = foo;

说明:第一行会检查第一个值是null、undefined还是...使用它。

【讨论】:

【参考方案6】:

$.extend 是要走的路

function elem(a,b)
var r='pages':'pagename':;
r.pages.pagename[a]='show':b;
return r;

data=;
//inside the event handler or something:
data = $.extend(true,data,elem($(this).closest('li').attr("id"),$(this).is(":hidden") ? 'collapsed' : 'expanded'));

但老实说 - 无论如何,存储这些信息是一个相当混乱的想法。 我敢打赌,如果您以后需要这些信息,可以使用一个好的选择器或 jQuery.data()

【讨论】:

但在函数中定义 json 并不是动态的。我会研究你的其他建议 不,我正在构建一个只有一个元素的对象并将其合并到数据变量中。如果您的代码有效,它会做同样的事情,但在您的代码无效时也可以。我仍然很高兴你尝试不同的方式:)【参考方案7】:

我猜你需要这个:

var dashBoard = new Array();
if(!dashboard['page123']) 
    dashBoard.push('page123');
 else 
...do what you want

您似乎正在处理 XML。

【讨论】:

【参考方案8】:

如果你使用下划线>= 1.9.0,你可以使用propertypropertyOf

d=a: b: "c"
_.property(["a", "b", "c", "e"])(d)   // undefined
_.property(["a", "b"])(d)             // "c"
_.propertyOf(d)(["a", "b", "c", "e"]) // undefined
_.propertyOf(d)(["a", "b"])           // "c"

【讨论】:

【参考方案9】:

我的小对象实用程序库中的这个方法回答了@mcgrailm 在他对标记答案的评论中提出的问题: 问题 dashboard.get('pages.user.settings').push("something"); dashboard.get('pages.user.settings').push("somethingelse") 回答

const users = 
    0:
      name:"John",
      age:30,
      car:null,
      job: "Developer",
      address: "Dakar",
      interest: 
        music: ["rnb", "rap"],
        sports: ["football", "basketball"],
        food: [
          
            senegal: 0:"yassa", 1:"mafé",
            mali: ["yassa", "mafé", "jolof rice"]
          ,
          
            usa: ["burger", "nuggets", 
              [
                jfr:["jfr_sn", "jfr_ng"]
              ]
            ]
          ,
          
            italia: ["pizza", "peperoni"]
          
        ]
      
    ,
    1:
      name:"Jane",
      age:20,
      car:null,
      job: "attorney",
      address: "Dakar",
      interest: 
        music: ["rnb", "rap"],
        sports: ["football", "basketball"],
        language: ["deutch", "english"]
      
    ,
    2:
      name:"Moussa",
      age:26,
      car:null,
      job: "plice officer",
      address: "Dakar",
      interest: 
        music: ["rnb", "rap", "trap"],
        sports: ["basketball", "handball"],
        countries: 
          Africa: ["Senegal", "Rwanda", "Morroco"],
          Europe: ["England", "Russia"],
          Asia: ["China", "Saudi Arabia", "Palestine"],
          America: ["Brasil", "Mexico", "USA"],
          Oceania: ["Australia"]
        
      
    


/*In this example we are using our users object declared previously and we are tryin to access the jfr key
by using the path that leads to this key
*/
//using vanilla js
let result1 = users[0].interest.food[1].usa[2][0].jfr

//using this library
let result2 = _Object(users).getEntryByPath("0.interest.food.1.usa.2.0.jfr")

//expected output for both method
[ "jfr_sn", "jfr_ng" ]

更多实用程序访问https://www.npmjs.com/package/spicy_object

【讨论】:

以上是关于添加到可能存在也可能不存在的 json 属性的主要内容,如果未能解决你的问题,请参考以下文章

检查 JSON 密钥是不是存在

在Python中删除可能存在或不存在的字典属性[重复]

从可能不存在的 JToken 中获取价值(最佳实践)

如何附加到 RethinkDB 中可能不存在的子文档?

如何附加到 RethinkDB 中可能不存在的子文档?

“ObjectConstructor”类型上不存在属性“值”