Преобразовать строку в точечную запись, чтобы получить ссылку на объект
Рассмотрим этот объект в JavaScript,
var obj = { a : { b: 1, c: 2 } };
учитывая строку "obj.ab", как я могу получить объект, к которому это относится, чтобы я мог изменить его значение? т.е. я хочу быть в состоянии сделать что-то вроде
obj.a.b = 5;
obj.a.c = 10;
где "obj.ab" и "obj.ac" - строки (не ссылки на obj). Я наткнулся на этот пост, в котором я могу получить значение, которое строка точечной нотации ссылается на obj, но что мне нужно, так это способ, которым я могу получить сам объект?
Вложенность объекта может быть даже глубже, чем это. то есть возможно
var obj = { a: { b: 1, c : { d : 3, e : 4}, f: 5 } }
6 ответов
Чтобы получить значение, рассмотрите:
function ref(obj, str) {
str = str.split(".");
for (var i = 0; i < str.length; i++)
obj = obj[str[i]];
return obj;
}
var obj = { a: { b: 1, c : { d : 3, e : 4}, f: 5 } }
str = 'a.c.d'
ref(obj, str) // 3
или в более причудливой форме, используя команду уменьшить:
function ref(obj, str) {
return str.split(".").reduce(function(o, x) { return o[x] }, obj);
}
Возврат назначаемой ссылки на член объекта невозможен в javascript, вам придется использовать функцию, подобную следующей:
function set(obj, str, val) {
str = str.split(".");
while (str.length > 1)
obj = obj[str.shift()];
return obj[str.shift()] = val;
}
var obj = { a: { b: 1, c : { d : 3, e : 4}, f: 5 } }
str = 'a.c.d'
set(obj, str, 99)
console.log(obj.a.c.d) // 99
или использовать ref
приведенный выше, чтобы получить ссылку на содержащий объект, а затем применить []
Оператор к нему:
parts = str.split(/\.(?=[^.]+$)/) // Split "foo.bar.baz" into ["foo.bar", "baz"]
ref(obj, parts[0])[parts[1]] = 99
Аналогичен ответу thg435, но с проверкой аргументов и поддержкой уровней гнезд, где один из уровней предка еще не определен или не является объектом.
setObjByString = function(obj, str, val) {
var keys, key;
//make sure str is a string with length
if (!str || !str.length || Object.prototype.toString.call(str) !== "[object String]") {
return false;
}
if (obj !== Object(obj)) {
//if it's not an object, make it one
obj = {};
}
keys = str.split(".");
while (keys.length > 1) {
key = keys.shift();
if (obj !== Object(obj)) {
//if it's not an object, make it one
obj = {};
}
if (!(key in obj)) {
//if obj doesn't contain the key, add it and set it to an empty object
obj[key] = {};
}
obj = obj[key];
}
return obj[keys[0]] = val;
};
Использование:
var obj;
setObjByString(obj, "a.b.c.d.e.f", "hello");
Если это javascript
запускается в браузере, тогда вы можете получить доступ к объекту следующим образом:
window['obj']['a']['b'] = 5
Итак, учитывая строку "obj.a.b"
Вы должны разделить его на .
:
var s = "obj.a.b"
var e = s.split(".")
window[e[0]][e[1]][e[2]] = 5
Ниже приведена простая оболочка класса dict
:
class Dots(dict):
def __init__(self, *args, **kargs):
super(Dots, self).__init__(*args, **kargs)
def __getitem__(self, key):
try:
item = super(Dots, self).__getitem__(key)
except KeyError:
item = Dots()
self.__setitem__(key, item)
return Dots(item) if type(item) == dict else item
def __setitem__(self, key, value):
if type(value) == dict: value = Dots(value)
super(Dots, self).__setitem__(key, value)
__getattr__ = __getitem__
__setattr__ = __setitem__
Пример:
>>> a = Dots()
>>> a.b.c = 123
>>> a.b.c
123
>>> a.b
{'c': 123}
>>> a
{'b': {'c': 123}}
Недостающие ключи создаются на лету как пустые Dots()
:
>>> if a.Missing: print "Exists"
...
>>> a
{'Missing': {}, 'b': {'c': 123}}
Возврат назначаемой ссылки на член объекта невозможен в javascript. Вы можете присвоить значение члену глубокого объекта с помощью точечной нотации с одной строкой кода, подобной этой.
new Function('_', 'val', '_.' + path + ' = val')(obj, value);
В вашем случае:
var obj = { a : { b: 1, c: 2 } };
new Function('_', 'val', '_.a.b' + ' = val')(obj, 5); // Now obj.a.b will be equal to 5
var obj = { a : { b: 1, c: 2 } };
walkObject(obj,"a.b"); // 1
function walkObject( obj, path ){
var parts = path.split("."), i=0, part;
while (obj && (part=parts[i++])) obj=obj[part];
return obj;
}
Или, если вам нравится ваш код кратко:
function walkObject( o, path ){
for (var a,p=path.split('.'),i=0; o&&(a=p[i++]); o=o[a]);
return o;
}