레벨 수에 관계없이 기존 속성을 가질 수있는 객체가 있습니다. 예를 들면 :
var obj = {
db: {
mongodb: {
host: 'localhost'
}
}
};
이에 대해 다음과 같이 속성을 설정 (또는 덮어 쓰기)하고 싶습니다.
set('db.mongodb.user', 'root');
// or:
set('foo.bar', 'baz');
속성 문자열은 깊이를 가질 수 있고 값은 모든 유형 / 사물 일 수 있습니다.
속성 키가 이미 존재하는 경우 값으로서의 객체 및 배열을 병합 할 필요가 없습니다.
이전 예제는 다음 객체를 생성합니다.
var obj = {
db: {
mongodb: {
host: 'localhost',
user: 'root'
}
},
foo: {
bar: baz
}
};
그러한 기능을 어떻게 실현할 수 있습니까?
답변
이 함수는 지정한 인수를 사용하여 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');
답변
답변
조금 늦었지만 여기에 도서관이 아닌 간단한 대답이 있습니다.
/**
* 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) {
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;
}
return a[b];
}, obj);
}
제가 만든이 기능은 당신이 필요로하는 것과 조금 더 정확하게 할 수 있습니다.
이 객체에 깊이 중첩 된 대상 값을 변경하고 싶다고 가정 해 보겠습니다.
let myObj = {
level1: {
level2: {
target: 1
}
}
}
따라서 함수를 다음과 같이 호출합니다.
setDeep(myObj, ["level1", "level2", "target1"], 3);
결과 :
myObj = {level1 : {level2 : {target : 3}}}
재귀 적으로 설정 플래그를 true로 설정하면 객체가 존재하지 않는 경우 설정됩니다.
setDeep(myObj, ["new", "path", "target"], 3, true);
결과는 다음과 같습니다.
obj = myObj = {
new: {
path: {
target: 3
}
},
level1: {
level2: {
target: 3
}
}
}
답변
재귀 함수를 사용할 수 있습니다.
/**
* 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)
}
더 간단합니다!
답변
목표를 달성하기 위해 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');
나는 상태를 업데이트하기 위해 반응에 많이 사용했으며 나에게 꽤 잘 작동했습니다.
답변
ES6에는 Computed Property Name 및 Rest Parameter를 사용하여이 작업을 수행하는 매우 멋진 방법이 있습니다 .
const obj = {
levelOne: {
levelTwo: {
levelThree: "Set this one!"
}
}
}
const updatedObj = {
...obj,
levelOne: {
...obj.levelOne,
levelTwo: {
...obj.levelOne.levelTwo,
levelThree: "I am now updated!"
}
}
}
에서 levelThree
속성을 설정하는 동적 속성 인 경우 에서 속성 의 이름을 보유하는 위치 levelTwo
를 사용할 수 있습니다 .[propertyName]: "I am now updated!"
propertyName
levelTwo
답변
Lodash에는 필요한 작업을 정확히 수행하는 update 라는 메서드 가 있습니다.
이 메소드는 다음 매개 변수를받습니다.
- 업데이트 할 개체
- 업데이트 할 속성의 경로 (속성은 깊게 중첩 될 수 있음)
- 업데이트 할 값을 반환하는 함수 (원래 값을 매개 변수로 제공)
귀하의 예에서는 다음과 같습니다.
_.update(obj, 'db.mongodb.user', function(originalValue) {
return 'root'
})