Данный объект JS
var obj = { a: { b: '1', c: '2' } }
и строка
"a.b"
как я могу преобразовать строку в точечную запись, чтобы я мог пойти
var val = obj.a.b
Если бы строка была просто 'a'
, я мог бы использовать obj[a]
. Но это сложнее. Я предполагаю, что есть какой-то простой метод, но в настоящее время он избегает.
javascript
nevf
источник
источник
eval
злой; не используйте этоОтветы:
Вот изящная однострочная, которая в 10 раз короче, чем другие решения:
[править] Или в ECMAScript 6:
(Не то, чтобы я думал, что eval всегда плох, как другие предполагают, что это так (хотя обычно это так), но тем не менее, эти люди будут рады, что этот метод не использует eval. Выше будет найдена
obj.a.b.etc
даннаяobj
строка"a.b.etc"
)В ответ на тех, кто все еще боится использовать,
reduce
несмотря на то, что он находится в стандарте ECMA-262 (5-е издание), вот рекурсивная реализация из двух строк:В зависимости от оптимизаций, выполняемых JS-компилятором, вы можете убедиться, что любые вложенные функции не переопределяются при каждом вызове с помощью обычных методов (помещая их в замыкание, объект или глобальное пространство имен).
редактировать :
Чтобы ответить на интересный вопрос в комментариях:
(sidenote: к сожалению, не может вернуть объект с помощью Setter, так как это нарушило бы соглашение о вызовах; кажется, что вместо этого commenter ссылается на общую функцию стиля сеттера с побочными эффектами, такими как
index(obj,"a.b.etc", value)
выполнениеobj.a.b.etc = value
.)reduce
Стиль не очень подходит к этому, но мы можем изменить рекурсивную реализацию:Демо-версия:
... хотя лично я бы рекомендовал сделать отдельную функцию
setIndex(...)
. Я хотел бы закончить дополнительным замечанием, что первоначальный вопросник мог (должен?) Работать с массивами индексов (которые они могут получить.split
), а не со строками; хотя обычно нет ничего плохого с удобной функцией.Комментатор спросил:
Javascript - очень странный язык; в общем случае у объектов могут быть только строки в качестве ключей их свойств, поэтому, например, если бы это
x
был общий объект типаx={}
, тоx[1]
стал быx["1"]
... вы правильно прочитали ... да ...Javascript Arrays (которые сами являются экземплярами Object) специально поддерживают целочисленные ключи, даже если вы можете сделать что-то вроде
x=[]; x["puppy"]=5;
.Но в целом (и есть исключения),
x["somestring"]===x.somestring
(когда это разрешено; вы не можете сделатьx.123
).(Имейте в виду, что любой JS-компилятор, который вы используете, может выбрать, может быть, скомпилировать его для более разумных представлений, если он может доказать, что он не нарушит спецификацию.)
Таким образом, ответ на ваш вопрос будет зависеть от того, допускаете ли вы, что эти объекты принимают только целые числа (из-за ограничения в вашей проблемной области), или нет. Давайте предположим, что нет. Тогда допустимое выражение - это объединение базового идентификатора плюс несколько
.identifier
s плюс несколько["stringindex"]
sТогда это будет эквивалентно
a["b"][4]["c"]["d"][1][2][3]
, хотя мы, вероятно, должны также поддержатьa.b["c\"validjsstringliteral"][3]
. Вы должны проверить раздел грамматики ecmascript для строковых литералов, чтобы увидеть, как анализировать действительный строковый литерал. Технически вы также хотели бы проверить (в отличие от моего первого ответа), которыйa
является действительным идентификатором JavaScript .Хотя простой ответ на ваш вопрос, если ваши строки не содержат запятых или скобок , будет состоять в том, чтобы соответствовать последовательности символов длиной 1+, которых нет в наборе
,
или,[
или]
:Если ваши строки не содержат escape-символов или
"
символов и поскольку IdentifierNames являются подъязыком StringLiterals (я думаю ???), вы можете сначала преобразовать свои точки в []:Конечно, всегда будьте осторожны и никогда не доверяйте своим данным. Некоторые плохие способы сделать это, которые могут работать для некоторых случаев использования, также включают в себя:
Специальный 2018 год редактировать:
Давайте пройдем полный круг и сделаем самое неэффективное, ужасно запрограммированное решение, которое мы можем придумать ... в интересах синтаксической
чистоты. С объектами ES6 Proxy! ... Давайте также определим некоторые свойства, которые (imho прекрасны и замечательны, но) могут нарушать неправильно написанные библиотеки. Возможно, вам следует опасаться использовать это, если вы заботитесь о производительности, здравомыслии (ваше или других), вашей работе и т. Д.Демо-версия:
Вывод:
неэффективная идея: Вы можете изменить вышеприведенное для отправки на основе входного аргумента; либо используйте
.match(/[^\]\[.]+/g)
метод для поддержкиobj['keys'].like[3]['this']
, либо ifinstanceof Array
, затем просто примите Array в качестве входных данныхkeys = ['a','b','c']; obj.H[keys]
.Предполагается, что, возможно, вы захотите обработать неопределенные индексы в «более мягком» стиле NaN (например,
index({a:{b:{c:...}}}, 'a.x.c')
вернуть undefined, а не uncaught TypeError) ...:1) Это имеет смысл с точки зрения «мы должны вернуть undefined, а не выбросить ошибку» в ситуации с одномерным индексом ({}) ['eg'] == undefined, поэтому «мы должны вернуть undefined вместо того, чтобы бросать ошибка "в N-мерной ситуации.
2) Это не имеет смысла с точки зрения того, что мы делаем
x['a']['x']['c']
, что приведет к ошибке TypeError в приведенном выше примере.Тем не менее, вы бы сделали эту работу, заменив функцию сокращения на:
(o,i)=>o===undefined?undefined:o[i]
или(o,i)=>(o||{})[i]
.(Вы можете сделать это более эффективным, используя цикл for и прерывая / возвращая всякий раз, когда подрезультат, в который будет добавлен следующий индекс, не определен, или используя try-catch, если вы ожидаете, что такие ошибки будут достаточно редкими.)
источник
reduce
не поддерживается во всех используемых в настоящее время браузерах.Array.reduce
является частью стандарта ECMA-262. Если вы действительно хотите поддерживать устаревшие браузеры, вы можете определитьArray.prototype.reduce
пример реализации, приведенный где-то (например, developer.mozilla.org/en/JavaScript/Reference/Global_Objects/… ).var setget = function( obj, path ){ function index( robj,i ) {return robj[i]}; return path.split('.').reduce( index, obj ); }
Если вы можете использовать lodash , есть функция, которая делает именно это:
_.get (объект, путь, [defaultValue])
источник
_.get(object, path)
не ломается, если путь не найден.'a.b.etc'.split('.').reduce((o,i)=>o[i], obj)
делает. Для моего конкретного случая - не для каждого случая - именно то, что мне нужно. Спасибо!defaultValue
. В_.get()
методе возвращает значение по умолчанию , если_.get()
решает , чтобыundefined
, таким образом установить его на то , что вы хотите , и часов для установленного значения._.set(object, path, value)
.Немного более сложный пример с рекурсией.
источник
Вы также можете использовать lodash.get
Вы просто устанавливаете этот пакет (npm i --save lodash.get), а затем используете его следующим образом:
источник
Если вы ожидаете разыменования одного и того же пути много раз, построение функции для каждого пути точечной нотации на самом деле имеет наилучшую производительность (более подробно о тестах производительности, на которые ссылается Джеймс Уилкинс в комментариях выше).
Использование конструктора Function имеет некоторые из тех же недостатков, что и eval (), с точки зрения безопасности и производительности в худшем случае, но IMO - это инструмент, который недостаточно используется для случаев, когда вам требуется сочетание экстремального динамизма и высокой производительности. Я использую эту методологию для построения функций фильтра массива и вызова их внутри дайджест-цикла AngularJS. Мои профили последовательно показывают шаг array.filter (), который занимает менее 1 мс для разыменования и фильтрации около 2000 сложных объектов с использованием динамически определенных путей глубиной 3-4 уровня.
Конечно, аналогичная методология может быть использована для создания сеттер-функций:
источник
Много лет со дня первоначального поста. Теперь есть отличная библиотека под названием «объект-путь». https://github.com/mariocasciaro/object-path
Доступно на NPM и BOWER https://www.npmjs.com/package/object-path
Это так же просто, как:
И работает для глубоко вложенных свойств и массивов.
источник
Я предлагаю разделить путь, повторить его и уменьшить объект, который у вас есть. Это предложение работает со значением по умолчанию для отсутствующих свойств.
источник
Обратите внимание, что если вы уже используете Lodash, вы можете использовать функции
property
илиget
:У Underscore также есть
property
функция, но она не поддерживает точечную запись.источник
Другие предложения немного загадочны, поэтому я решил внести свой вклад:
источник
Вы можете использовать библиотеку, доступную на npm, что упрощает этот процесс. https://www.npmjs.com/package/dot-object
источник
Это большой код по сравнению с гораздо более простым
eval
способом сделать это, но, как говорит Саймон Уиллисон, вы никогда не должны использовать eval .Кроме того, JSFiddle .
источник
Я расширил элегантный ответ с помощью ninjagecko, чтобы функция обрабатывала как точечные, так и / или массивные ссылки, и чтобы пустая строка приводила к возвращению родительского объекта.
Ну вот:
Смотрите мой рабочий пример jsFiddle здесь: http://jsfiddle.net/sc0ttyd/q7zyd/
источник
[]
нотация всегда для массивов. также могут быть представлены ключи объектов, например,obj['some-problem/name'].list[1]
чтобы исправить это, я должен был обновитьarr_deref
функцию следующим образомjavascript function arr_deref(o, ref, i) { return !ref ? o : (o[(ref.slice(0, i ? -1 : ref.length)).replace(/^['"]|['"]$/g, '')]); }
источник
Вы можете получить значение элемента объекта с помощью точечной нотации с одной строкой кода:
В вашем случае:
Для простоты вы можете написать такую функцию:
Объяснение:
Конструктор Function создает новый объект Function. В JavaScript каждая функция на самом деле является объектом Function. Синтаксис для создания функции явно с помощью конструктора функций:
где
arguments(arg1 to argN)
должна быть строка, которая соответствует действительному идентификатору javaScript иfunctionBody
является строкой, содержащей операторы javaScript, составляющие определение функции.В нашем случае мы используем преимущество строковой функции body для получения члена объекта с точечной нотацией.
Надеюсь, поможет.
источник
GET / SET ответ, который также работает в реагировать нативно (вы не можете назначить в
Object.prototype
настоящее время):Использование:
источник
Я скопировал следующее из ответа Рикардо Томази и изменил его, создав также подобъекты, которые еще не существуют по мере необходимости. Это немного менее эффективно (больше
if
s и создание пустых объектов), но должно быть довольно хорошо.Кроме того, это позволит нам делать то, что
Object.prop(obj, 'a.b', false)
мы не могли раньше. К сожалению, это все еще не позволит нам назначитьundefined
... Не знаю, как это сделать.источник
Если вы хотите преобразовать любой объект, содержащий ключи точечной нотации, в массив этих версий ключей, вы можете использовать это.
Это преобразует что-то вроде
в
источник
Вот мой код без использования
eval
. Его тоже легко понять.источник
Да, это было задано 4 года назад, и да, расширение базовых прототипов обычно не является хорошей идеей, но, если вы храните все расширения в одном месте, они могут быть полезны.
Итак, вот мой способ сделать это.
Теперь вы сможете получить вложенное свойство везде без импорта модуля с функцией или функцией копирования / вставки.
UPD.Example:
UPD 2. Следующее расширение ломает мангуста в моем проекте. Также я читал, что это может сломать jquery. Итак, никогда не делай это следующим образом
источник
Вот моя реализация
Реализация 1
Реализация 2 (использование массива Reduce вместо Slice)
Примеры:
он также может обрабатывать объекты внутри массивов, как для
источник
Это мое расширенное решение, предложенное: ninjagecko
Для меня простой строковой нотации было недостаточно, поэтому ниже версия поддерживает такие вещи, как:
index (obj, 'data.accounts [0] .address [0] .postcode');
источник
Рискуя побить мертвую лошадь ... Я считаю, что это наиболее полезно при обходе вложенных объектов для ссылки, где вы находитесь, относительно базового объекта или аналогичного объекта с такой же структурой. Для этого это полезно с функцией обхода вложенных объектов. Обратите внимание, что я использовал массив для хранения пути. Было бы тривиально изменить это, чтобы использовать либо путь строки, либо массив. Также обратите внимание, что вы можете присвоить значению «undefined», в отличие от некоторых других реализаций.
источник
Я использовал этот код в своем проекте
Использование:
источник
Несколько лет спустя я обнаружил, что это обрабатывает область и массив. например
a['b']["c"].d.etc
источник
Непонятно, каков твой вопрос. Учитывая ваш объект,
obj.a.b
вы получите «2», как есть. Если вы хотите манипулировать строкой, используя скобки, вы можете сделать это:источник
a.b.c
, и на самом деле не выполняет то, что они хотят .. Они хотят ценность, а неeval
путь.a.b.c
, но вы правы, по-видимому, он хотел получить / установить значение свойства вobj.a.b
. Вопрос сбил меня с толку, так как он сказал, что хочет «преобразовать строку» ....вот мои 10 центов к случаю, ниже приведенная функция будет получена / настроена на основе предоставленного пути, .. конечно, вы можете улучшить его, удалите || и замените его на,
Object.hasOwnProperty
если вы по ошибке заботитесь о ложных значениях,Я проверил это с
a.b.c
и ab2.c,{a:{b:[0,1,{c:7}]}}
и он работает как для настройки, так и для получения :).cheerz
источник