Object.prototype是Verboten?

Eli*_*gem 20 javascript prototype

概括:

好吧,自从我问这个问题以来已经有一段时间了.像往常一样,Object.prototype无论如何,尽管在网上和网上的其他地方都有反对它的所有有效论据,我还是进行了扩充.我想我就是那种顽固的混蛋.

我试图找出一种结论性的方法来防止新方法破坏任何预期的行为,这被证明是一个非常艰难但信息丰富的事情.
我学到了很多关于JavaScript的东西.至少我不会像在使用本机原型一样轻率地尝试任何东西(除了String.prototype.trimIE <9).

在这种特殊情况下,我不使用任何库,因此冲突不是我主要关注的问题.但是在使用本机原型时,我已经深入研究了可能的不幸事件,我不太可能将这个代码与任何lib结合使用.

通过研究这种原型方法,我对模型本身有了更好的理解.我将原型作为一种灵活的传统抽象类处理,使我坚持传统的OOP思维.这个观点并没有真正做到原型模型的正义.道格拉斯·克罗克福德(Douglas Crockford)写到了这个陷阱,遗憾的是,粉红色的背景使我无法阅读完整的文章.

我决定更新这个问题,因为读这篇文章的人很想看到自己.我只能这样说:一定要做到.我希望你能像我一样学习一些巧妙的东西,然后再决定放弃这个相当愚蠢的想法.一个简单的函数可能也可以正常工作,甚至更好,尤其是在这种情况下.毕竟,真正的美妙之处在于,通过添加3行代码,您可以使用相同的功能来增强特定对象的原型.


我知道我将问一个已存在很长一段时间的问题,但是:为什么Object.prototype被认为是不受限制的?就在那里,它可以像任何其他原型一样进行扩充.那么,为什么你不应该利用这一点.在我看来,只要你知道你在做什么,就没有理由避开Object原型.
以此方法为例:

if (!Object.prototype.getProperties)
{
    Object.prototype.getProperties = function(f)
    {
        "use strict";
        var i,ret;
        f = f || false;
        ret = [];
        for (i in this)
        {
            if (this.hasOwnProperty(i))
            {
                if (f === false && typeof this[i] === 'function')
                {
                    continue;
                }
                ret.push(i);
            }
        }
        return ret;
    };
}
Run Code Online (Sandbox Code Playgroud)

基本上,它是一个相同的旧for...in循环,你要么在一个函数中保持安全,要么一遍又一遍地写.我知道它会被添加到所有对象中,因为几乎JavaScript中的每个继承链都可以追溯到Object.prototype,但在我的脚本中,我认为它是两个邪恶中的较小者.

也许,有人会在告诉我,我是错的比做得更好这第一章,等等.
在寻找人们没有触及Object原型的原因的同时,有一件事情不断出现:它打破了for..in循环,但又一次:许多框架也做了,更不用说你自己的继承链了.因此.hasOwnProperty,在我的脑海中不要在循环访问对象的属性时包含检查是不好的做法.

我也发现很有趣.再说一句:一条评论非常明确:扩展原生原型是不好的做法,但如果V8人这样做,我该说他们错了?
我知道,这个论点并没有完全叠加.

关键是:我真的看不到上面代码的问题.我喜欢它,使用它很多,到目前为止,它没有让我失望过一次.我甚至想把更多的函数附加到Object原型上.除非有人能告诉我为什么不应该这样做,那就是.

T.J*_*der 14

事实是,只要您知道自己在做什么以及成本是多少就可以了.但这是一个很大的 "如果".一些成本的例子:

  • 您需要对您选择使用的任何库进行大量测试,因为压倒性的约定是空白对象没有可枚举的属性.通过添加可枚举属性,您将使该约定成为false.例如,这很常见:Object.prototypeObject.prototype

    var obj = {"a": 1, "b": 2};
    var name;
    for (name in obj) {
        console.log(name);
    }
    
    Run Code Online (Sandbox Code Playgroud)

    ...... 压倒性的惯例是只显示"a"和"b",而不是"getProperties".

  • 任何从事该代码工作的人都必须接受这样的事实,即不遵守该惯例(上述).

你可以通过使用Object.defineProperty(和类似的)如果支持来缓解上述情况,但要注意即使在2014年,像IE8 这样不能正常支持它的浏览器仍然有很大的用途(尽管我们希望现在XP正式EOL会很快改变) "D).这是因为使用Object.defineProperty,你可以添加不可枚举的属性(那些不会出现在for-in循环中的属性),这样你就可以减少麻烦(此时,你主要是担心名称冲突) - 但它只是适用于正确实现的系统Object.defineProperty(并且正确的实现不能"填充").

在你的榜样,我也不会加入getPropertiesObject.prototype; 我将它添加到Object并接受该对象作为参数,就像ES5所做的那样getPrototypeOf.

请注意,Array.prototype由于影响for..in循环的方式,Prototype库会因扩展而受到很多限制.那就是Arrays(你不应该使用for..in它(除非你使用的是hasOwnProperty后卫,很可能String(Number(name)) === name也是如此).

......如果V8人这样做,我该说他们错了?

在V8上,您可以信赖Object.defineProperty,因为V8是完全符合ES5标准的引擎.

请注意,即使属性不可枚举,也存在问题.多年前,Prototype(间接)定义了一个filter函数Array.prototype.它完成了你所期望的:调用迭代器函数并根据函数选择的元素创建一个新数组.然后ECMAScript5出现并定义Array.prototype.filter为做同样的事情.但是有一个问题:很多相同的事情.特别是,被调用的迭代器函数的签名是不同的(ECMAScript5包含Prototype没有的参数).它可能比那更糟糕(我怀疑 - 但不能证明 - TC39意识到Prototype并故意避免与它发生太多冲突).

所以:如果您打算这样做,请注意风险和成本.由于尝试使用现成的库,您可能遇到的丑陋,边缘案例错误可能真的花费您的时间......