【问题标题】:I tried to prototype a length() method to Object and broke jQuery – how?我试图为 Object 设计一个 length() 方法的原型并破坏了 jQuery——如何?
【发布时间】:2010-04-14 15:00:26
【问题描述】:

我写了以下内容:

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

它有效。但是当我执行我的页面时,即使没有使用这个函数,Firebug 也会告诉我 jQuery 的 .appendTo() 不再是一个函数。为什么会这样?

【问题讨论】:

    标签: javascript jquery prototype object methods


    【解决方案1】:

    该原型扩展破坏了$.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 变量只有在不包含 length 属性(或属性值为 undefined)时才为真。

    如果isObj 为假,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,当您扩展此原型时,所有对象都会收到这些附加属性。

    这尤其成问题,因为当您迭代对象的属性时 这些新属性出现,导致各种意外行为。

    【讨论】:

    • 对。我对 Objects 比较陌生,所以它并没有打击到我——我正在做的事情是弄巧成拙,因为我首先污染了我想要整理的 Objects。感谢您为我逐步完成。
    • 我理解扩展 Object.prototype 的问题。但是,如果我仍然想向 Object.prototype 添加一个属性,这是一种我想让所有人都可以访问的通用函数,该怎么办?我怎样才能让它不出现在for循环中。我看到我的方法出现在 proto 对象中,该对象中定义了许多其他函数,但它们没有作为 for 循环中的键出现?帮我添加一个不可枚举的函数
    【解决方案2】:

    这可能是因为 jQuery 的 .appendTo (间接)依赖于 Object.length,它是 JavaScript 内置的,不是函数。
    如果您真的想将该方法添加到 Object 中,请将其命名为不会干扰现有方法的名称;像 objLength 或 obj_length (或其他)。
    您还可以执行以下操作来检查要添加到对象的属性是否已经存在于该对象(直接从 Crockford 提取):

    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;
    });

    而且我知道我的循环在一个完整的语句周围有括号,但它提高了可读性和可维护性。我听说这些都是好东西。

    【讨论】:

    • 这完全是题外话,但是谁告诉你额外的括号可以提高可读性或可维护性?可读性可能会引起争论,但我看不出它是如何更易于维护的,而不是纯粹因为可能更具可读性。我不相信将来可能需要额外的牙套。添加可能需要的代码是一种可怕的做法。我发现简洁的代码更容易阅读。 IMO 额外的 {} == 页面上的更多杂乱和更少的代码。
    • @jcoffland 在像for 这样的语句周围省略括号是不好的做法,因为它允许根据代码的格式设置控制流的歧义。三元运算符也是如此,缺少缩进,使用非描述性标识符,将所有内容放在一行上,并在可选的地方省略分号。如果只是为了简洁而不是跨开发人员可读性的合理标准,我们将使用字节码来编写脚本。任何认真对待代码风格的开发人员都会同意:link
    • @Beejor,我对代码风格很认真,我不同意。你是说如果我没有使用额外的括号并且我没有一致地缩进,那么代码可能看起来不明确。对此,我同意。我不同意的是解决方案是添加不必要的括号。恕我直言,正确的解决方案是始终正确缩进您的代码,并明智地使用空格。然后你不需要添加废话代码。我们这里正处于一场宗教战争的边缘,所以我将把它留在那里。