Javascript:如何dynamic地使用数组给定的对象名创build嵌套对象

我希望有人可以帮助我这个Javascript。

我有一个名为“设置”的对象,我想写一个函数,将新的设置添加到该对象。

新设置的名称和值以stringforms提供。 给出设置名称的string然后被下划线分割成一个数组。 新的设置应该添加到现有的“设置”对象通过创build新的嵌套对象的数组中的每个部分给出的名称,除了最后一部分应该是一个string给出设置的值。 那么我应该能够参考这个设定,并且提醒它的价值。 我可以用这种静态的方式做这个…

var Settings = {}; var newSettingName = "Modules_Video_Plugin"; var newSettingValue = "JWPlayer"; var newSettingNameArray = newSettingName.split("_"); Settings[newSettingNameArray[0]] = {}; Settings[newSettingNameArray[0]][newSettingNameArray[1]] = {}; Settings[newSettingNameArray[0]][newSettingNameArray[1]][newSettingNameArray[2]] = newSettingValue; alert(Settings.Modules.Mediaplayers.Video.Plugin); 

…创build嵌套对象的部分是这样做的…

 Settings["Modules"] = {}; Settings["Modules"]["Video"] = {}; Settings["Modules"]["Video"]["Plugin"] = "JWPlayer"; 

然而,由于组成设置名称的部分数量可能会有所不同,例如newSettingName可能是“Modules_Floorplan_Image_Src”,我想这样做dynamic使用一个函数,如…

 createSetting (newSettingNameArray, newSettingValue); function createSetting(setting, value) { // code to create new setting goes here } 

任何人都可以帮助我解决如何dynamic地做到这一点?

我认为必须有一个for …循环在那里通过数组,但我一直没有能够找出一种方法来创build嵌套的对象。

如果你非常感谢你花时间阅读,即使你不能帮助。

 function assign(obj, keyPath, value) { lastKeyIndex = keyPath.length-1; for (var i = 0; i < lastKeyIndex; ++ i) { key = keyPath[i]; if (!(key in obj)) obj[key] = {} obj = obj[key]; } obj[keyPath[lastKeyIndex]] = value; } 

用法:

 var settings = {}; assign(settings, ['Modules', 'Video', 'Plugin'], 'JWPlayer'); 

放入一个函数,简短快速。

 var createNestedObject = function( base, names ) { for( var i = 0; i < names.length; i++ ) { base = base[ names[i] ] = base[ names[i] ] || {}; } }; // Usage: createNestedObject( window, ["shapes", "triangle", "points"] ); // Now window.shapes.triangle.points is an empty object, ready to be used. 

跳过层次结构中已有的部分。 如果您不确定层次结构是否已经创build,那么很有用。

要么:

您可以直接将值分配给层次结构中最后一个对象的发烧友版本,并且可以链接函数调用,因为它返回最后一个对象。

 // Function: createNestedObject( base, names[, value] ) // base: the object on which to create the hierarchy // names: an array of strings contaning the names of the objects // value (optional): if given, will be the last object in the hierarchy // Returns: the last object in the hierarchy var createNestedObject = function( base, names, value ) { // If a value is given, remove the last name and keep it for later: var lastName = arguments.length === 3 ? names.pop() : false; // Walk the hierarchy, creating new objects where needed. // If the lastName was removed, then the last object is not set yet: for( var i = 0; i < names.length; i++ ) { base = base[ names[i] ] = base[ names[i] ] || {}; } // If a value was given, set it to the last name: if( lastName ) base = base[ lastName ] = value; // Return the last object in the hierarchy: return base; }; // Usages: createNestedObject( window, ["shapes", "circle"] ); // Now window.shapes.circle is an empty object, ready to be used. createNestedObject( window, ["shapes", "rectangle", "width"], 300 ); // Now we have: window.shapes.rectangle.width === 300 createNestedObject( window, "shapes.rectangle.height".split('.'), 400 ); // Now we have: window.shapes.rectangle.height === 400 

注意:如果您的层次结构中需要的值不同于标准对象(即非{} ),请参阅TimDog的答案。

编辑:使用常规的循环,而不是for...in循环。 在库修改数组原型的情况下更安全。

另一个recursion解决scheme:

 var nest = function(obj, keys, v) { if (keys.length === 1) { obj[keys[0]] = v; } else { var key = keys.shift(); obj[key] = nest(typeof obj[key] === 'undefined' ? {} : obj[key], keys, v); } return obj; }; 

用法示例:

 var dog = {bark: {sound: 'bark!'}}; nest(dog, ['bark', 'loudness'], 66); nest(dog, ['woff', 'sound'], 'woff!'); console.log(dog); // {bark: {loudness: 66, sound: "bark!"}, woff: {sound: "woff!"}} 

我的ES2015解决scheme。 保持现有值。

 const set = (obj, path, val) => { const keys = path.split('.'); const lastKey = keys.pop(); const lastObj = keys.reduce((obj, key) => obj[key] = obj[key] || {}, obj); lastObj[lastKey] = val; }; 

例:

 const obj = {'a': {'prop': {'that': 'exists'}}}; set(obj, 'a.very.deep.prop', 'value'); console.log(JSON.stringify(obj)); // {"a":{"prop":{"that":"exists"},"very":{"deep":{"prop":"value"}}}} 

这是对jlgrall答案的简单调整,它允许在嵌套层次结构中的每个元素上设置不同的值:

 var createNestedObject = function( base, names, values ) { for( var i in names ) base = base[ names[i] ] = base[ names[i] ] || (values[i] || {}); }; 

希望它有帮助。

尝试使用recursion函数:

 function createSetting(setting, value, index) { if (typeof index !== 'number') { index = 0; } if (index+1 == setting.length ) { settings[setting[index]] = value; } else { settings[setting[index]] = {}; createSetting(setting, value, ++index); } } 

我想这个比较短:

 Settings = {}; newSettingName = "Modules_Floorplan_Image_Src"; newSettingValue = "JWPlayer"; newSettingNameArray = newSettingName.split("_"); a = Settings; for (var i = 0 in newSettingNameArray) { var x = newSettingNameArray[i]; a[x] = i == newSettingNameArray.length-1 ? newSettingValue : {}; a = a[x]; } 

我发现@ jlgrall的答案很好,但简化后,它不适用于Chrome。 这是我的固定应该任何人都想要一个精简版的版本

 var callback = 'fn.item1.item2.callbackfunction', cb = callback.split('.'), baseObj = window; function createNestedObject(base, items){ $.each(items, function(i, v){ base = base[v] = (base[v] || {}); }); } callbackFunction = createNestedObject(baseObj, cb); console.log(callbackFunction); 

我希望这是有用和相关的。 对不起,我刚刚捣毁了这个例子

你可以定义你自己的Object方法; 为简洁起见,我还使用了下划线:

 var _ = require('underscore'); // a fast get method for object, by specifying an address with depth Object.prototype.pick = function(addr) { if (!_.isArray(addr)) return this[addr]; // if isn't array, just get normally var tmpo = this; while (i = addr.shift()) tmpo = tmpo[i]; return tmpo; }; // a fast set method for object, put value at obj[addr] Object.prototype.put = function(addr, val) { if (!_.isArray(addr)) this[addr] = val; // if isn't array, just set normally this.pick(_.initial(addr))[_.last(addr)] = val; }; 

示例用法:

 var obj = { 'foo': { 'bar': 0 }} obj.pick('foo'); // returns { bar: 0 } obj.pick(['foo','bar']); // returns 0 obj.put(['foo', 'bar'], -1) // obj becomes {'foo': {'bar': -1}} 

欣赏这个问题是大老! 但是在遇到需要在node中做这样的事情之后,我创build了一个模块并将其发布到npm。 Nestob

 var nestob = require('nestob'); //Create a new nestable object - instead of the standard js object ({}) var newNested = new nestob.Nestable(); //Set nested object properties without having to create the objects first! newNested.setNested('biscuits.oblong.marmaduke', 'cheese'); newNested.setNested(['orange', 'tartan', 'pipedream'], { poppers: 'astray', numbers: [123,456,789]}); console.log(newNested, newNested.orange.tartan.pipedream); //{ biscuits: { oblong: { marmaduke: 'cheese' } }, orange: { tartan: { pipedream: [Object] } } } { poppers: 'astray', numbers: [ 123, 456, 789 ] } //Get nested object properties without having to worry about whether the objects exist //Pass in a default value to be returned if desired console.log(newNested.getNested('generic.yoghurt.asguard', 'autodrome')); //autodrome //You can also pass in an array containing the object keys console.log(newNested.getNested(['chosp', 'umbridge', 'dollar'], 'symbols')); //symbols //You can also use nestob to modify objects not created using nestob var normalObj = {}; nestob.setNested(normalObj, 'running.out.of', 'words'); console.log(normalObj); //{ running: { out: { of: 'words' } } } console.log(nestob.getNested(normalObj, 'random.things', 'indigo')); //indigo console.log(nestob.getNested(normalObj, 'improbable.apricots')); //false 

对于那些需要创build一个支持数组键的嵌套对象来设置一个值到path末尾的代码片段。 path是这样的string: modal.product.action.review.2.write.survey.data 。 基于jlgrall版本。

 var updateStateQuery = function(state, path, value) { var names = path.split('.'); for (var i = 0, len = names.length; i < len; i++) { if (i == (len - 1)) { state = state[names[i]] = state[names[i]] || value; } else if (parseInt(names[i+1]) >= 0) { state = state[names[i]] = state[names[i]] || []; } else { state = state[names[i]] = state[names[i]] || {}; } } }; 

设置嵌套数据:

 function setNestedData(root, path, value) { var paths = path.split('.'); var last_index = paths.length - 1; paths.forEach(function(key, index) { if (!(key in root)) root[key] = {}; if (index==last_index) root[key] = value; root = root[key]; }); return root; } var obj = {'existing': 'value'}; setNestedData(obj, 'animal.fish.pet', 'derp'); setNestedData(obj, 'animal.cat.pet', 'musubi'); console.log(JSON.stringify(obj)); // {"existing":"value","animal":{"fish":{"pet":"derp"},"cat":{"pet":"musubi"}}} 

获取嵌套数据:

 function getNestedData(obj, path) { var index = function(obj, i) { return obj && obj[i]; }; return path.split('.').reduce(index, obj); } getNestedData(obj, 'animal.cat.pet') // "musubi" getNestedData(obj, 'animal.dog.pet') // undefined 

Eval可能是矫枉过正,但结果很容易可视化,没有嵌套的循环或recursion。

  function buildDir(obj, path){ var paths = path.split('_'); var final = paths.pop(); for (let i = 1; i <= paths.length; i++) { var key = "obj['" + paths.slice(0, i).join("']['") + "']" console.log(key) eval(`${key} = {}`) } eval(`${key} = '${final}'`) return obj } var newSettingName = "Modules_Video_Plugin_JWPlayer"; var Settings = buildDir( {}, newSettingName ); 

基本上你正在逐渐写一个string"obj['one']= {}", "obj['one']['two']"= {}并对其进行评估;

试试这个: https : //github.com/silkyland/object-to-formdata

 var obj2fd = require('obj2fd/es5').default var fd = obj2fd({ a:1, b:[ {c: 3}, {d: 4} ] }) 

结果:

 fd = [ a => 1, b => [ c => 3, d => 4 ] ]