Я читал черновик для ES6 и заметил это примечание в разделе Object.prototype.toString
:
Исторически эта функция иногда использовалась для доступа к строковому значению внутреннего свойства [[Class]], которое использовалось в предыдущих редакциях этой спецификации в качестве тега номинального типа для различных встроенных объектов. Это определение toString сохраняет возможность использовать его в качестве надежного теста для определенных видов встроенных объектов, но не обеспечивает надежного механизма проверки типов для других типов встроенных или определяемых программой объектов.
Судя по этой ветке на es-discuss, это звучит например, [[Class]]
заменяется на [[NativeBrand]]
в проекте ES6, чтобы они могли указать его как нерасширяемый (это было как минимум мысли Аллена Вирфс-Брока).
Любопытно, я провел быстрый тест в FireFox и Chrome (с включенным экспериментальным JavaScript):
Object.prototype.toString.apply(new WeakMap());
=> '[object WeakMap]'
"WeakMap"
не является одним из [[NativeBrand]]
, указанных в проекте ES6. Однако этот тест вернул "[object WeakMap]"
в обоих браузерах.
Так что я в замешательстве. У меня есть несколько вопросов.
<сильный>1. Правильно ли ведут себя Chrome и Firefox?
При одном прочтении черновика кажется, что они должны возвращать [object Object]
(и все это довольно ново, поэтому я не удивлюсь, увидев это изменение в будущих версиях этих браузеров). Однако мне сложно понять замысел этого раздела черновика, тем более, что есть места с "???"
.
Есть ли у кого-нибудь, кто более ревностно следит за es-discuss, какая-либо соответствующая информация? Или кто-нибудь, кто может лучше понять черновой язык?
<сильный>2. Есть ли альтернатива Object.prototype.toString
?
Из примечания, процитированного выше, получается, что Object.prototype.toString
сохранено по устаревшим причинам, как будто теперь есть что-то новое, что следует использовать вместо него. Особенно та часть узла, которая читается как "it does not provide a reliable type testing mechanism for other kinds of built-in ... objects"
. Означает ли это, что будущие встроенные функции нельзя тестировать с помощью этого метода?
Возьмем конкретный пример.
Если я хочу убедиться, что объект, который я получил из неизвестного источника, является объектом String
(фактически сконструированным объектом String
, а не примитивной строкой), я мог бы сделать:
if (Object.prototype.toString.apply(unknownObject) != '[object String]')
throw new TypeError('String object expected.');
Это позволяет мне узнать, является ли unknownObject
объектом String
независимо от того, в каком фрейме он был построен.
Мой вопрос в том, следует ли использовать такой подход при переходе к ES6? Или есть альтернатива? Что-то вроде Object.getNativeBrandOf
?
<сильный>3. Поскольку [[NativeBrand]]
похоже, что он не будет включать в себя будущие типы объектов, как можно проверить эти объекты?
Будет ли это работать?
if (Object.prototype.toString.apply(unknownObject) != '[object Symbol]')
throw new TypeError('Symbol expected.');
...при условии, что Symbol
- это возможное имя для частных имен.
Должен ли я использовать это?
if (Object.prototype.toString.apply(unknownObject) != '[object WeakMap]')
throw new TypeError('WeakMap expected.');
... или что-то другое?
Причина, по которой я спрашиваю, заключается в том, что в настоящее время я пишу код, который я хочу как можно проще перевести на ES6 через год или два, когда это будет возможно. Если есть замена Object.prototype.toString
, то я могу просто вставить ее и продолжить оттуда. Спасибо!
Обновлять
Ответ бенви предоставил мне правильный термин для поиска и понимания ответов на мои вопросы.
Я нашел электронное письмо от Аллена Вирфс-Брока на es-discuss а> по этому вопросу.
Вот что я нашел, для тех, кто задает те же вопросы:
<сильный>1. Правильно ли ведут себя Chrome и Firefox?
Да, почему, поясняется ниже.
<сильный>2. Есть ли альтернатива Object.prototype.toString
?
Как и сейчас, будет пара «альтернатив» в смысле возможностей, но не в смысле замен.
a. Использование символа @@toStringTag
. Однако, как я понимаю, Object.prototype.toString
, вероятно, следует использовать. @@toStringTag
позволяет расширить результаты, которые могут быть возвращены из Object.prototype.toString
. Если у вас есть прототип, к которому вы хотите добавить свой собственный строковый тег, вы можете использовать @@toStringTag
, чтобы установить значение для любой строки. Object.prototype.toString
вернет это значение, за исключением случаев, когда это значение является одним из встроенных в ES5, и в этом случае строковый тег будет начинаться с «~».
b. Использование закрытых символов для пользовательских объектов. Я прочитал одно электронное письмо, в котором рекламировалось, что это лучший способ сделать такой же тип проверки для пользовательского объекта. Однако я не понимаю, как это действительно решает проблему, поскольку я не понимаю, как это может быть межфреймовое решение, и оно не позволяет вам проверять встроенные модули ES6.
Поэтому, несмотря на то, что есть некоторые альтернативы, хорошо придерживаться Object.prototype.toString
сейчас и в будущем, с одной оговоркой:
Это сработает, если у вас есть встроенный ES5, например String
, но не будет надежной гарантией, что у вас есть встроенный ES6, потому что их можно подделать с помощью @@toStringTag
. Я не уверен, почему это так, и я могу что-то упустить, или это может измениться по мере развития спецификации.
<сильный>3. Поскольку [[NativeBrand]]
похоже, что он не будет включать в себя будущие типы объектов, как можно проверить эти объекты?
Как упоминалось выше, Object.prototype.toString
все еще можно использовать во встроенных модулях ES6, но это не является надежным, так как любой, у кого есть доступ к символу @@toStringTag
, может подделать его. Однако, возможно, не должно быть защиты от дурака, поскольку Object.prototype.toString(weakmap) == '[object WeakMap]'
не означает, что weakmap instanceof WeakMap
(и не должно!). weakmap
мог быть взят из другого кадра, или это мог быть созданный пользователем объект, похожий на слабую карту. Единственное, что вы действительно знаете, это то, что он сообщает, что он функционально эквивалентен WeakMap.
Кажется, возникает вопрос, почему вы не можете иметь пользовательский объект, который сообщает, что он функционально эквивалентен String
или Array
(без префикса "~"
).
~
был удален в версии 32. - person Knu   schedule 16.03.2015NativeBrand
, поэтому полагаю, чтоclass
не заменяется наNativeBrand
. - person Mocuishle   schedule 28.04.2018