与えられただけだとしましょう
var obj = {};
var propName = "foo.bar.foobar";
obj.foo.bar.foobar
プロパティを特定の値(「helloworld」など)に設定するにはどうすればよいですか?したがって、これを実現したいのですが、文字列にはプロパティ名しかありません。
obj.foo.bar.foobar = "hello world";
与えられただけだとしましょう
var obj = {};
var propName = "foo.bar.foobar";
obj.foo.bar.foobar
プロパティを特定の値(「helloworld」など)に設定するにはどうすればよいですか?したがって、これを実現したいのですが、文字列にはプロパティ名しかありません。
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");
この質問は誤答が多いようですので、類似質問の正解を参考にさせていただきます
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');
編集:受け入れられた回答を自分のバージョンと比較するために、 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");
</ p>
</ p>
Here's one that returns the updated object
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;
}
この実装は非常にパフォーマンスが高いはずです。シンプルさを維持しながら、再帰と関数呼び出しを回避します。
/**
* 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://stackoverflow.com/a/46060952/938822
* @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
既存の値を上書きせず、読みやすく、これを思いつくことができた答えを探していました。同じニーズを持つ他の人を助ける場合に備えて、これをここに残します
function setValueAtObjectPath(obj, pathString, newValue) {
// create an array (pathComponents) of the period-separated path components from pathString
var pathComponents = pathString.split('.');
// create a object (tmpObj) that references the memory of obj
var tmpObj = obj;
for (var i = 0; i < pathComponents.length; i++) {
// if not on the last path component, then set the tmpObj as the value at this pathComponent
if (i !== pathComponents.length-1) {
// set tmpObj[pathComponents[i]] equal to an object of it's own value
tmpObj[pathComponents[i]] = {...tmpObj[pathComponents[i]]}
// set tmpObj to reference tmpObj[pathComponents[i]]
tmpObj = tmpObj[pathComponents[i]]
// else (IS the last path component), then set the value at this pathComponent equal to newValue
} else {
// set tmpObj[pathComponents[i]] equal to newValue
tmpObj[pathComponents[i]] = newValue
}
}
// return your object
return obj
}