Javascript 中的原型对象破坏了 jQuery?

IT技术 javascript jquery prototype prototyping
2021-02-09 02:46:45

.js在我的页面中添加了一个简单的文件,文件在ObjectArray原型中添加了一些非常普通的常见任务类型的功能

通过反复试验,我发现将任何函数添加到Object.prototype.

罪魁祸首?

Object.prototype.foo = function() {
    /*do nothing and break jQuery*/
};

jquery-1.3.2.js在 attr:function { } 声明中得到第 1056 行的错误

/*Object doesn't support this property or method*/
name = name.replace(/-([a-z])/ig, function(all, letter) {
            return letter.toUpperCase();
        });

显然 G.replace 是未定义的。

虽然很明显有些东西我只是没有用原型设计来解决我的问题,但我很遗憾地无法弄清楚它是什么。

明确地说,我不是在寻找解决方法,我已经处理了......我正在寻找的是为什么?. 为什么要添加一个函数来Object.prototype破坏这段代码?

5个回答

如果这只是搞砸 for...in 循环的情况,您不能使用 Object.defineProperty 添加您的 fn 而不使其可枚举吗?

所以:

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

似乎对我有用。这仍然会被视为不良形式吗?

我不知道...很高兴知道它是否是错误的形式,但这对我来说非常有用。
2021-03-16 02:46:45
@NoOne 您的应用程序可能看起来像:Core Javascript(由浏览器拥有)-> 工具包(如 jquery、下划线等)-> 框架(主干、angular、react 等)-> 您的应用程序代码。每一层在以某种方式运行之前都依赖于这些层。在任何语言中,倒退并改变核心数据类型的工作方式总是一个问题。
2021-03-22 02:46:45
@NoOne 我不认为扩展 Object 原型与任何其他原型有什么不同。它只需要负责任地完成。网络的开源性质,以及所有可用的框架、插件和工具,意味着您的项目可能比您自己的项目更多的第三方代码。JavaScript 的一个核心租户是不要修改您不拥有的任何内容。如果你只是不假思索地扩展 Object,你可能会破坏一些期望它以某种方式运行的东西。
2021-04-04 02:46:45
@NoOne 有很多方法可以让您仅在应用程序代码中获得所需的功能。您可以使用 underscore.string 之类的库、使用 Object.create()、mixin 或工厂方法将功能构建到您的对象中。一本涵盖了很多相关技术的好书是 JavaScript Patterns ( amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752 )。
2021-04-09 02:46:45
您可以,但是 for..in 循环旨在枚举原型扩展。这就是您探索原型链的方式。它不会中断 for..in 循环,它会中断错误代码,这些代码盲目地假设迭代值总是属于某种类型,而由于 Object.prototype 链可以包含函数,大括号之间的代码可以在以下情况下抛出异常他们只需要标量和对象。
2021-04-10 02:46:45

你永远不应该扩展Object.prototype. 它不仅仅破坏了 jQuery;它完全打破了 Javascript 的“object-as-hashtables”特性。不要这样做。

你可以问 John Resig,他会告诉你同样的事情

@Crescent 比这要深得多。当然,你可以用这样的for...in循环来解决这个问题,但是在 Javascript 中使用对象作为哈希表可以做很多其他的事情。例如, toString,valueOf等就不一一列举了。确实有影响。此外,当你是一个被大量用户使用的库的首席开发人员时,你不能将他的决定归咎于懒惰。我认为一个更好的词是谨慎。
2021-03-18 02:46:45
@CrescentFresh 非常感谢您!!!几个月来我一直在寻找那个帖子!(我是那个帖子/代码差异的作者,也是与 Resig 合作修复 jQuery 中的错误的人。)我认为它永远消失了。作为更新,我很遗憾地报告,几个月前 Resig 正式关闭了无法修复的票证。这个缺陷在 UI 库中太普遍了,糟糕的编码实践在社区中太普遍了。这就是我不再使用 jQuery 的原因 :( 但 Sizzle 与 Object.prototype 扩展兼容,这真的是我最喜欢的 jQuery 部分。
2021-03-30 02:46:45
延长Object.prototype就好了。需要注意的是hasOwnPropertyfor..in循环中使用自 2.0 以来,包括 Safari 在内的所有主要浏览器都支持它。jQuery 不在其for..in循环中这样做只是懒惰性能影响可以忽略不计,Resig 知道这一点:osdir.com/ml/jquery-dev/2009-02/msg00543.html然而,只是我的意见。
2021-03-31 02:46:45
恕我直言,这个答案现在不正确,而且已经过时。在 ES5 中,您可以Object.prototype使用Object.defineProperty创建不可枚举属性的默认设置安全地扩展
2021-04-04 02:46:45
@JoshStodola - 实际上这不是懒惰,而是无知(大多数人不知道使用 hasOwnProperty ......)在 jQuery Resig 的早期根本不知道这样做。在意识到这个缺陷后不久,他一直认为这个修复是未来需要的工具,但遗憾的是它从未成为核心。
2021-04-06 02:46:45

我同意,添加一些东西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 发生冲突。

这似乎是最好的答案。似乎也不与 Google Maps API 发生冲突。
2021-04-11 02:46:45

我怀疑向 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
}}
好吧,如果我注释掉 Object.prototype.foo 声明,一切正常。此外,在它崩溃的时候,它甚至还没有到达超出该 foo 声明的任何代码。
2021-03-17 02:46:45
取决于你如何看待它。理想情况下,您应该能够毫无问题地扩展 Object,但实际上,是的,这是一个坏主意,而且很少有充分的理由。Crockford 将枚举添加到原型中的函数视为“语言中的错误”,因此最佳实践是防御性的,并且始终将 hasOwnProperty 添加到 for..in 循环中。这很糟糕,但我虔诚地这样做;)
2021-03-28 02:46:45
是的,它破坏了 jQuery,jQuery 将遍历您的 Object.prototype 扩展,但假设它不是一个函数。当该函数出现在迭代中时,它会引发异常。它不会破坏 JavaScript,它是 JavaScript 设计不可或缺的一部分。@jshalvi - 你总是可以创建一个像 jQuery 的 $.each 这样的交互器函数,并且只写一次。Crockford 对这门语言有一些误解,但这并不是他的错,他开创了西部 JavaScript 的狂野前沿,而且他在旅途中只犯了一些错误。:D
2021-04-02 02:46:45
你说得对,它不会直接破坏 jQuery,它会破坏 Javascript!
2021-04-08 02:46:45