Прототипирование объекта в Javascript прерывает jQuery?

Я добавил простой файл .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 - undefined.

Хотя очевидно, что что-то, что я просто не обволакиваю головой прототипом, я с трудом могу понять, что это такое.

Чтобы быть ясным, я не ищу обходного пути, у меня это обработано... то, что я ищу, является ответом на Почему?. Почему добавление функции в Object.prototype прерывает этот бит кода?

Ответ 1

Вы никогда не должны расширять Object.prototype. Это намного больше, чем разрыв jQuery; он полностью разрушает функцию "объект-как-хэш-таблицы" Javascript. Не делайте этого.

Вы можете спросить Джона Ресига, и он скажет вам то же самое.

Ответ 2

Если это просто случай перебора для... в цикле, не можете ли вы использовать Object.defineProperty, чтобы добавить свой fn, не делая его перечислимым?

Итак:

Object.defineProperty(Object.prototype, "foo", { 
    value: function() {
        // do stuff
    },
    enumerable : false
});

Кажется, работает для меня. Будет ли это считаться плохой формой?

Ответ 3

Я согласен, добавив что-то к Object.prototype требует осторожности и его следует избегать. Ищите другие решения, такие как:

Добавление его в объект, а затем доступ к нему с помощью 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), и он читается как рассылка.

Но, как правило, избегайте изменения любого из крупных прототипов.

Ответ 4

Я ударил головой по этой проблеме, поскольку я хотел реализовать "реальную" ориентацию объекта во всех моих объектах, например:

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.

Ответ 5

Я сомневаюсь, что функция Object.prototype напрямую отключает jQuery. Просто убедитесь, что каждый из циклов .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
}}