Есть ли способ доказательства в будущем для добавления свойств в собственные объекты браузера с учетом поведения "строгого" поведения?
Недавно я заметил, что когда режим "use strict";
включен в браузерах, многие свойства на нативных объектах становятся неурегулированными.
Например
function() {
"use strict";
var div = document.createElement("div");
div.offsetLeft = 0;
}();
Игнорируйте тот факт, что установка offsetLeft
глупа. Это не главное.
Если вы запустите это в Chrome или Firefox, вы получите сообщение об ошибке
Uncaught TypeError: Cannot set property offsetLeft of #<HTMLElement> which has only
a getter(…)
Удалите "use strict";
, и ошибка исчезнет.
Итак, вот проблема. Позвольте изменить offsetLeft
на то, что я могу использовать в своем собственном коде
function createElementAndAssociateData(data) {
"use strict";
var div = document.createElement("div");
div.userdata = data;
};
Это отлично работает, за исключением 2 лет с новой спецификации HTML5 и решает, что для всех HTMLElements атрибут userdata
доступен только для чтения. Внезапно мой код разбивается везде, где я использовал "use strict";
.
Ожидается ли это бомба замедленного действия, поскольку все больше и больше свойств добавляются к собственным объектам HTML5?
Существует ли безопасный способ использования "use strict";
и добавления пользовательских свойств к собственным объектам HTML5 или добавление какого-либо свойства к собственному объекту браузера никогда не будет выполнено?
Примечание. Я не считаю, что устранение имен свойств является приемлемым решением. Конечно, я мог бы изменить userdata
на mycompanyname_myappname_userdata
, но такой вид рядом с точкой. Есть ли какое-то другое решение или добавляет пользовательские свойства к собственным объектам HTML5 в строгом режиме анти-шаблон?
Ответы
Ответ 1
Да: символы ES6
Проблема со свойствами заключается в том, что их имя является строкой. Затем два разных кода могут использовать одно и то же имя для разных целей, и результат может быть катастрофическим.
Чтобы решить эту проблему, ECMAScript 6 вводит новый тип: Symbol.
Вы можете использовать его следующим образом:
var s1 = Symbol("My property");
object[s1] = "Some data 1";
object[s1]; // "Some data 1"
Тогда, даже если какой-либо другой код решит использовать символ с тем же описанием, столкновения не будет:
var s2 = Symbol("My property"); // Same description :S
object[s2] = "Some data 2";
object[s2]; // "Some data 2"
object[s1]; // "Some data 1" -- No problem :)
Ответ 2
Предполагаемый способ добавления пользовательских свойств - HTMLElement.dataset
.
var div = document.createElement("div");
div.dataset.yourCustomProperty = 'some data';
div; // <div data-your-custom-property="some data">
div.dataset.yourCustomProperty; // "some data"
Это отражает пользовательские атрибуты data-*
.
Обратите внимание, что .dataset.camelCase
отражает data-camel-case
и наоборот.
Ответ 3
В общем, ваш код также сломается, если вы удалите "use strict";
, потому что ваше свойство не имеет значения, которое вы хотели бы иметь.
В общем, расширение родных объектов - не очень хорошая идея.
Вот несколько вариантов:
-
Используйте один разнесенный по имени ключ, например _myframeworkElemID
, который не будет указан.
-
Создайте динамический ключ (аналогично 1.):
Например, jQuery создает такой ключ: $.expando = 'jQuery' + Date.now();
-
Используйте jQuery.data или реализуйте аналогичное решение.
-
современные способы
a) Символы (см. этот ответ)
b) WeakMap:
window.elementData = new WeakMap();
//later than
//set data
elementData.set(element, data)
//get data
elementData.get(element);
Все это сказало. С моей точки зрения в настоящее время лучший способ сделать это выглядит следующим образом:
var expando = window.Symbol && Symbol() || '_myId' + Date.now();
//set data
element[expando] = data;
//get data
var data = element[expando];
Таким образом, вы используете функцию ES6 Symbol в браузерах, которые ее поддерживают, а в старых браузерах вы получаете уникальную строку, которая никогда не будет указана.
Вы также можете написать помощника, который возвращает символ.