Как создать объект JS с прототипом по умолчанию из объекта без прототипа?

Предыстория: модуль query-string, например, может разобрать key=value&hello=universe на объект {key: 'value', hello: 'universe'}. Однако автор модуля решил, что возвращаемый объект не имеет прототипа. Другими словами, этот "ублюдочный" объект создан Object.create(null).

Проблема: было бы удобно использовать parsed.hasOwnProperty('hello'), но это невозможно без прототипа объекта по умолчанию. Конечно, можно было бы Object.prototype.hasOwnProperty.call(parsed, 'hello'), но я думаю, что мы все можем согласиться с тем, что такое выражение убивает-сразу-после рождения уродливо.

Вопрос: как красиво преобразовать объект без прототипа, чтобы иметь прототип объекта по умолчанию и такие методы, как hasOwnProperty? Кроме того, можно ли это сделать без использования внушающий страх __proto__ или setPrototypeOf?


person Akseli Palén    schedule 03.10.2016    source источник


Ответы (4)


Было бы удобно использовать parsed.hasOwnProperty('hello'), но это невозможно без прототипа объекта по умолчанию.

Весь смысл создания такого «ублюдочного объекта» в том, что вы не можете этого сделать — что, если кто-то отправит строку запроса ?hasOwnProperty=oops на ваш сервер?

Как красиво преобразовать объект без прототипа, чтобы иметь прототип объекта по умолчанию и такие методы, как hasOwnProperty?

Не делайте этого. Вам следует либо использовать длинную форму с call, либо просто использовать in оператор, который делает именно то, что вам нужно:

'hello' in parsed

В среде ES6 вы также можете преобразовать объект в правильный Map и используйте этот has метод.

person Bergi    schedule 03.10.2016

Я бы не рекомендовал изменять прототип стороннего пакета, он может быть зависшим и подвержен ошибкам во время выполнения. Я бы либо использовал встроенный оператор in, как предложил @Bergi, либо API ES6 Reflect.

const _ = console.info

const parsed = (
  { __proto__: null
  , foo: 'fu'
  , bar: 'bra'
  }
)

_('foo' in parsed) // true

_('fu' in parsed) // false


/** ES6 (fully supported in current browsers) */

_(Reflect.has(parsed, 'foo')) // true

_(Reflect.has(parsed, 'fu')) // false

person cchamberlain    schedule 03.10.2016

Я не могу сказать, что когда-либо делал это раньше, но вот один из способов сделать это.

let bastard = Object.create(null);
bastard.father = 'vader';

let adopted = Object.assign({}, bastard);
console.log(adopted.hasOwnProperty('father')); // => true

person Mulan    schedule 03.10.2016
comment
Чувак, ты использовал Силу! Отлично, именно то, что я искал. Спасибо! - person Akseli Palén; 03.10.2016
comment
@AkseliPalén, вы должны прочитать сообщение Берги и подумать о том, чтобы принять его как правильный ответ. - person Mulan; 04.10.2016
comment
Ваш ответ был именно тем, что искал мой вопрос. Строка запроса предоставила только пример, и я не имел в виду ограничение контекста. К сожалению, в этом примере ваш ответ имеет недостатки. Мне жаль, что вы получили отрицательные голоса из-за этого. Тем не менее, я изменил ответ Берги, сделав его новым правильным, поскольку он дает ценную информацию. - person Akseli Palén; 05.10.2016
comment
@AkseliPalén без проблем. Берги очень хорошо осведомлен; У меня всегда был хороший успех, следуя его / ее совету. - person Mulan; 05.10.2016

setPrototypeOf() нечего бояться, но без него вы могли бы сделать следующее;

var o1 = Object.create(null),
    o2;
o1.test = "42";
o2 = Object.assign({},o1);
console.log(o2.test);
console.log(o2.constructor.prototype);

person Redu    schedule 03.10.2016