Я попытался создать прототип метода length () для Object и сломал jQuery - как? - PullRequest
4 голосов
/ 14 апреля 2010

Я написал следующее:

Object.prototype.length = function(){
    var count = -1;
    for(var i in this) count++;
    return count;
}

Это работает. Но когда я выполняю свою страницу, даже без использования этой функции, Firebug говорит мне, что jQuery .appendTo() больше не является функцией. С чего бы это?

Ответы [ 2 ]

7 голосов
/ 14 апреля 2010

Это расширение прототипа нарушает метод $.each, поскольку этот метод обнаруживает между массивами и объектами, используя свойство length jQuery 1.4.2 ):

// core.js Line 533
each: function( object, callback, args ) {
    var name, i = 0,
        length = object.length, // <--- your function from Object.prototype
        isObj = length === undefined || jQuery.isFunction(object);
//...

Как видите, переменная isObj будет иметь значение true, только если она не содержит свойства length (или значение свойства undefined).

Если isObj равно false, jQuery попытается выполнить итерацию, используя обычный цикл for:

for ( var value = object[0];
    i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {}

Затем метод appendTo создается с использованием $.each, поэтому не определен:

//...
jQuery.each({
    appendTo: "append",
    prependTo: "prepend",
    insertBefore: "before",
    insertAfter: "after",
    replaceAll: "replaceWith"
},
//...

Я всегда буду рекомендовать , чтобы избежать расширения Object.prototype, когда вы расширяете этот прототип ALL объекты получают эти дополнительные свойства.

Это особенно проблематично, поскольку при переборе свойств объекта эти новые свойства появляются, вызывая все виды неожиданного поведения.

4 голосов
/ 14 апреля 2010

Вероятно, это потому, что jQuery .appendTo зависит (косвенно) от Object.length, который встроен в JavaScript и не является функцией.
Если вы действительно хотите добавить этот метод в Object, назовите его чем-нибудь, что не будет мешать существующим ранее методам; что-то вроде objLength или obj_length (или как угодно).
Вы также можете сделать что-то вроде этого, чтобы проверить, существует ли атрибут, который вы хотите добавить к объекту, для этого объекта (снятый прямо из Крокфорда):

Object.prototype.method = function (name, func) {
    if (!this.prototype[name]){
        this.prototype[name] = func;
        return this;
    }
};

И примените свою функцию так:

Object.method('myLength', function () {
    var count = -1;
    for (var i in this) {
        count += 1;
    }
    return count;
});

И я знаю, что у моего цикла есть скобки вокруг одного оператора, но это улучшает удобочитаемость и удобство обслуживания. Я слышал, что это хорошие вещи.

...