Joh*_* B. 59 javascript ecmascript-5
我有一个对象,可以是任意数量的级别,可以有任何现有的属性.例如:
var obj = {
db: {
mongodb: {
host: 'localhost'
}
}
};
Run Code Online (Sandbox Code Playgroud)
在那我想设置(或覆盖)属性,如下所示:
set('db.mongodb.user', 'root');
// or:
set('foo.bar', 'baz');
Run Code Online (Sandbox Code Playgroud)
属性字符串可以有任何深度,值可以是任何类型/东西.
如果属性键已存在,则不需要合并作为值的对象和数组.
上一个示例将生成以下对象:
var obj = {
db: {
mongodb: {
host: 'localhost',
user: 'root'
}
},
foo: {
bar: baz
}
};
Run Code Online (Sandbox Code Playgroud)
我怎么才能实现这样的功能呢?
bpm*_*on1 77
此函数使用您指定的参数,应添加/更新obj容器中的数据.请注意,您需要跟踪obj模式中的哪些元素是容器,哪些是值(字符串,整数等),否则您将开始抛出异常.
obj = {}; // global object
function set(path, value) {
var schema = obj; // a moving reference to internal objects within obj
var pList = path.split('.');
var len = pList.length;
for(var i = 0; i < len-1; i++) {
var elem = pList[i];
if( !schema[elem] ) schema[elem] = {}
schema = schema[elem];
}
schema[pList[len-1]] = value;
}
set('mongo.db.user', 'root');
Run Code Online (Sandbox Code Playgroud)
ahe*_*ann 51
Lodash有一个_.set()方法.
_.set(obj, 'db.mongodb.user', 'root');
_.set(obj, 'foo.bar', 'baz');
Run Code Online (Sandbox Code Playgroud)
Bru*_*uim 18
我只是用ES6+递归写了一个小函数来达到目的。
updateObjProp = (obj, value, propPath) => {
const [head, ...rest] = propPath.split('.');
!rest.length
? obj[head] = value
: this.updateObjProp(obj[head], value, rest.join('.'));
}
const user = {profile: {name: 'foo'}};
updateObjProp(user, 'fooChanged', 'profile.name');
Run Code Online (Sandbox Code Playgroud)
我在反应更新状态时经常使用它,它对我来说效果很好。
Phi*_*l_t 11
有点晚了,但这里是一个非库,更简单的答案:
/**
* Dynamically sets a deeply nested value in an object.
* Optionally "bores" a path to it if its undefined.
* @function
* @param {!object} obj - The object which contains the value you want to change/set.
* @param {!array} path - The array representation of path to the value you want to change/set.
* @param {!mixed} value - The value you want to set it to.
* @param {boolean} setrecursively - If true, will set value of non-existing path as well.
*/
function setDeep(obj, path, value, setrecursively = false) {
let level = 0;
path.reduce((a, b)=>{
level++;
if (setrecursively && typeof a[b] === "undefined" && level !== path.length){
a[b] = {};
return a[b];
}
if (level === path.length){
a[b] = value;
return value;
} else {
return a[b];
}
}, obj);
}
Run Code Online (Sandbox Code Playgroud)
我所做的这个功能可以完全满足您的需求和更多功能.
假设我们想要更改深度嵌套在此对象中的目标值:
let myObj = {
level1: {
level2: {
target: 1
}
}
}
Run Code Online (Sandbox Code Playgroud)
所以我们会像这样调用我们的函数:
setDeep(myObj, ["level1", "level2", "target1"], 3);
Run Code Online (Sandbox Code Playgroud)
将导致:
myObj = {level1:{level2:{target:3}}}
将set recursively flag设置为true将设置对象(如果它们不存在).
setDeep(myObj, ["new", "path", "target"], 3);
Run Code Online (Sandbox Code Playgroud)
会导致这个:
obj = myObj = {
new: {
path: {
target: 3
}
},
level1: {
level2: {
target: 3
}
}
}
Run Code Online (Sandbox Code Playgroud)
Hen*_*ons 11
我想出了我自己的解决方案,使用纯 es6 和递归,不会改变原始对象。
const setNestedProp = (obj = {}, [first, ...rest] , value) => ({
...obj,
[first]: rest.length
? setNestedProp(obj[first], rest, value)
: value
});
const result = setNestedProp({}, ["first", "second", "a"],
"foo");
const result2 = setNestedProp(result, ["first", "second", "b"], "bar");
console.log(result);
console.log(result2);Run Code Online (Sandbox Code Playgroud)
灵感来自@ bpmason1的答案:
function leaf(obj, path, value) {
const pList = path.split('.');
const key = pList.pop();
const pointer = pList.reduce((accumulator, currentValue) => {
if (accumulator[currentValue] === undefined) accumulator[currentValue] = {};
return accumulator[currentValue];
}, obj);
pointer[key] = value;
return obj;
}
Run Code Online (Sandbox Code Playgroud)
例:
const obj = {
boats: {
m1: 'lady blue'
}
};
leaf(obj, 'boats.m1', 'lady blue II');
leaf(obj, 'boats.m2', 'lady bird');
console.log(obj); // { boats: { m1: 'lady blue II', m2: 'lady bird' } }
Run Code Online (Sandbox Code Playgroud)
Lodash有一个名为update的方法,可以完全满足您的需求.
此方法接收以下参数:
在您的示例中,它看起来像这样:
_.update(obj, 'db.mongodb.user', function(originalValue) {
return 'root'
})
Run Code Online (Sandbox Code Playgroud)
我们可以使用递归函数:
/**
* Sets a value of nested key string descriptor inside a Object.
* It changes the passed object.
* Ex:
* let obj = {a: {b:{c:'initial'}}}
* setNestedKey(obj, ['a', 'b', 'c'], 'changed-value')
* assert(obj === {a: {b:{c:'changed-value'}}})
*
* @param {[Object]} obj Object to set the nested key
* @param {[Array]} path An array to describe the path(Ex: ['a', 'b', 'c'])
* @param {[Object]} value Any value
*/
export const setNestedKey = (obj, path, value) => {
if (path.length === 1) {
obj[path] = value
return
}
return setNestedKey(obj[path[0]], path.slice(1), value)
}
Run Code Online (Sandbox Code Playgroud)
更简单!
ES6也有一个很酷的方法,即使用计算属性名称和Rest参数来执行此操作。
const obj = {
levelOne: {
levelTwo: {
levelThree: "Set this one!"
}
}
}
const updatedObj = {
...obj,
levelOne: {
...obj.levelOne,
levelTwo: {
...obj.levelOne.levelTwo,
levelThree: "I am now updated!"
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果levelThree是动态属性,即要在中设置任何属性levelTwo,则可以使用[propertyName]: "I am now updated!"where来propertyName保存属性的名称levelTwo。
| 归档时间: |
|
| 查看次数: |
45368 次 |
| 最近记录: |