假设我们只知道
var obj = {};
var propName = "foo.bar.foobar";
我们如何将属性obj.foo.bar.foobar
设置为特定值(比如"hello world")?假设我们只有以字符串形式给出的属性名称:
obj.foo.bar.foobar = "hello world";
假设我们只知道
var obj = {};
var propName = "foo.bar.foobar";
我们如何将属性obj.foo.bar.foobar
设置为特定值(比如"hello world")?假设我们只有以字符串形式给出的属性名称:
obj.foo.bar.foobar = "hello world";
function assign(obj, prop, value) {
if (typeof prop === "string")
prop = prop.split(".");
if (prop.length > 1) {
var e = prop.shift();
assign(obj[e] =
Object.prototype.toString.call(obj[e]) === "[object Object]"
? obj[e]
: {},
prop,
value);
} else
obj[prop[0]] = value;
}
var obj = {},
propName = "foo.bar.foobar";
assign(obj, propName, "Value");
setDeep(obj, prop, value, returnObj) { if (is.String(prop)) prop = prop.split("."); if (prop.length > 1) { let e = prop.shift(); Craft.setDeep(obj[e] = is.Object(obj[e]) ? obj[e] : {}, prop, value); } else obj[prop[0]] = value; if (returnObj === true) return obj; }
- Saul does Code由于这个问题的回答似乎都是错误的,因此我将只引用类似问题的正确答案。
function setDeepValue(obj, value, path) {
if (typeof path === "string") {
var path = path.split('.');
}
if(path.length > 1){
var p=path.shift();
if(obj[p]==null || typeof obj[p]!== 'object'){
obj[p] = {};
}
setDeepValue(obj[p], value, path);
}else{
obj[path[0]] = value;
}
}
使用:
var obj = {};
setDeepValue(obj, 'Hello World', 'foo.bar.foobar');
foo.bar.foobar
和 foo.bar2.foobar2
两次调用它会怎样? - FrancescoMMfoo.bar2.foobar2
时,它确实重置了 obj.foo
。已编辑代码。
哎呀,没看到你建议的编辑,正在修复。 - CerbrussetDeepValue(obj[p], value, path);
- Cerbrus编辑:我已经创建了一个jsPerf.com测试用例来比较被接受的答案和我的版本。结果发现,我的版本更快,特别是当你深入到很深的时候。
var nestedObjectAssignmentFor = function(obj, propString, value) {
var propNames = propString.split('.'),
propLength = propNames.length-1,
tmpObj = obj;
for (var i = 0; i <= propLength ; i++) {
tmpObj = tmpObj[propNames[i]] = i !== propLength ? {} : value;
}
return obj;
}
var obj = nestedObjectAssignment({},"foo.bar.foobar","hello world");
所有的解决方案在设置时都覆盖了原始数据,因此我进行了以下调整,将其改为单个对象:
var obj = {}
nestObject.set(obj, "a.b", "foo");
nestObject.get(obj, "a.b"); // returns foo
var nestedObject = {
set: function(obj, propString, value) {
var propNames = propString.split('.'),
propLength = propNames.length-1,
tmpObj = obj;
for (var i = 0; i <= propLength ; i++) {
if (i === propLength){
if(tmpObj[propNames[i]]){
tmpObj[propNames[i]] = value;
}else{
tmpObj[propNames[i]] = value;
}
}else{
if(tmpObj[propNames[i]]){
tmpObj = tmpObj[propNames[i]];
}else{
tmpObj = tmpObj[propNames[i]] = {};
}
}
}
return obj;
},
get: function(obj, propString){
var propNames = propString.split('.'),
propLength = propNames.length-1,
tmpObj = obj;
for (var i = 0; i <= propLength ; i++) {
if(tmpObj[propNames[i]]){
tmpObj = tmpObj[propNames[i]];
}else{
break;
}
}
return tmpObj;
}
};
也可以将函数更改为Object.prototype方法,将obj参数更改为this:
Object.prototype = { setNested = function(){ ... }, getNested = function(){ ... } }
{}.setNested('a.c','foo')
function deepUpdate(value, path, tree, branch = tree) {
const last = path.length === 1;
branch[path[0]] = last ? value : branch[path[0]];
return last ? tree : deepUpdate(value, path.slice(1), tree, branch[path[0]]);
}
const path = 'cat.dog';
const updated = deepUpdate('a', path.split('.'), {cat: {dog: null}})
// => { cat: {dog: 'a'} }
function setValueByPath (obj, path, value) {
var ref = obj;
path.split('.').forEach(function (key, index, arr) {
ref = ref[key] = index === arr.length - 1 ? value : {};
});
return obj;
}
我刚刚从几个线程和一些自定义代码中编译了一个get和set函数。
在设置时,它还将创建不存在的键。
function setValue(object, path, value) {
var a = path.split('.');
var o = object;
for (var i = 0; i < a.length - 1; i++) {
var n = a[i];
if (n in o) {
o = o[n];
} else {
o[n] = {};
o = o[n];
}
}
o[a[a.length - 1]] = value;
}
function getValue(object, path) {
var o = object;
path = path.replace(/\[(\w+)\]/g, '.$1');
path = path.replace(/^\./, '');
var a = path.split('.');
while (a.length) {
var n = a.shift();
if (n in o) {
o = o[n];
} else {
return;
}
}
return o;
}
这个实现应该是非常高效的。 它避免了递归和函数调用,同时保持了简单性。
/**
* Set the value of a deep property, creating new objects as necessary.
* @param {Object} obj The object to set the value on.
* @param {String|String[]} path The property to set.
* @param {*} value The value to set.
* @return {Object} The object at the end of the path.
* @author github.com/victornpb
* @see https://dev59.com/GmYr5IYBdhLWcg3wYZSD#46060952
* @example
* setDeep(obj, 'foo.bar.baz', 'quux');
*/
function setDeep(obj, path, value) {
const props = typeof path === 'string' ? path.split('.') : path;
for (var i = 0, n = props.length - 1; i < n; ++i) {
obj = obj[props[i]] = obj[props[i]] || {};
}
obj[props[i]] = value;
return obj;
}
/*********************** EXAMPLE ***********************/
const obj = {
hello : 'world',
};
setDeep(obj, 'root', true);
setDeep(obj, 'foo.bar.baz', 1);
setDeep(obj, ['foo','quux'], '');
console.log(obj);
// ⬇︎ Click "Run" below to see output
setDeep(obj, 'foo.bar.baz[0]', 1);
- vsyncfunction setValue(object, path, value) {
var fullPath = path.split('.'),
way = fullPath.slice(),
last = way.pop();
way.reduce(function (r, a) {
return r[a] = r[a] || {};
}, object)[last] = value;
}
var object = {},
propName = 'foo.bar.foobar',
value = 'hello world';
setValue(object, propName, value);
console.log(object);