Создание прототипа объекта в Javascript нарушает jQuery?
-
11-09-2019 - |
Вопрос
Я добавил простой .js
файл на мою страницу, на которой есть некоторые довольно обыденные функции общего типа, добавленные в Object
и Array
прототипы.
Методом проб и ошибок я выяснил, что добавление любой функции в Object.prototype
, независимо от его названия или того , что он делает , вызывает ошибки Javascript в jQuery:
Преступник?
Object.prototype.foo = function() {
/*do nothing and break jQuery*/
};
Ошибка, которую я получаю в строке 1056 из jquery-1.3.2.js
, в объявлении attr:function { }:
/*Object doesn't support this property or method*/
name = name.replace(/-([a-z])/ig, function(all, letter) {
return letter.toUpperCase();
});
По-видимому, G.replace не определено.
Хотя очевидно, что есть что-то, о чем я просто не задумываюсь при создании прототипа, я с треском проваливаюсь в попытках понять, что это такое.
Чтобы было ясно, я не ищу обходной путь, я с этим справился...то, что я ищу, - это ответ на Почему?.Почему добавление функции в Object.prototype
сломать этот фрагмент кода?
Решение
Вы никогда не должны расширять Object.prototype
.Это делает гораздо больше, чем просто нарушает jQuery;это полностью нарушает функцию Javascript "объект как хэш-таблицы".Не делай этого.
Вы можете спросить Джона Ресига, и он расскажет вам то же самое.
Другие советы
Если это просто случай путаницы for...in циклы, разве вы не можете использовать Object.defineProperty для добавления вашего fn, не делая его перечислимым?
Итак:
Object.defineProperty(Object.prototype, "foo", {
value: function() {
// do stuff
},
enumerable : false
});
Кажется, у меня это работает.Будет ли это по-прежнему считаться дурным тоном?
Я согласен, добавив кое-что к Object.prototype
требует осторожности, и его следует избегать.Ищите другие решения, такие как:
Добавление его в Object и затем доступ к нему с помощью call
или apply
, по мере необходимости.Например:
Object.foo = function () { return this.whatever()}
Затем вызовите это для объекта с помощью:
Object.foo.call(Objname); // this invokes the function as though it were a
// method of Objname. That is, its like Objname.foo()
Для развлечения вы можете добавить следующее (да, я знаю, что это немного опасно ...):
Function.using = Function.call; // syntactic sugar
Теперь вы можете писать Object.foo.using(Objname)
и это читается как приговор.
Но, как правило, держитесь подальше от изменения каких-либо крупных прототипов.
Я ломал голову над этой проблемой, поскольку хотел реализовать "реальную" объектную ориентацию во всех моих объектах, вот так:
interface Object
{
GetType: () => string;
ToString: () => string;
GetHashcode: () => number;
Equals: (obj: any) => boolean;
}
Поскольку Object.prototype нарушает jQuery, я по умолчанию использовал вышеупомянутое решение, чтобы использовать defineProperty, но это не принимает никаких аргументов.
Хорошей новостью является то, что вы можете взломать defineProperty и фактически принять параметры.Вот моя реализация:
Object.defineProperty(Object.prototype, "Equals",
{
value: function (obj: any)
{
return obj == null && this == null
? true
: obj != null && this == null
? false
: obj == null && this != null
? false
: this.GetHashcode() == obj.GetHashcode();
},
enumerable: false
});
Это работает и не противоречит jQuery.
Я сомневаюсь, что добавление функции в Object.prototype напрямую нарушает jQuery.Просто убедитесь, что каждый for..in цикл, который у вас есть на вашем сайте, проходит проверку hasOwnProperty, поскольку вы добавили функцию глобально, и результат итерации по ней может быть непредсказуемым:
Object.prototype.foo = function() {};
var myObject = {m1: "one", m2: "two" };
for(var i in myObject) { if(myObject.hasOwnProperty(i)) {
// Do stuff... but not to Object.prototype.foo
}}