增加 Object.prototype 破坏道场

Augmenting Object.prototype breaks Dojo

我遇到了一个问题,它可能是错误,也可能只是预期的功能。我正在使用使用 Dojo 构建的第三方脚本。在我自己的应用程序中,我增加了 Function.prototype 和 Object.prototype (对于我的应用程序)方便的实用程序功能。包含第三方脚本总是导致错误。

Uncaught TypeError: Cannot set property _scopeName' of undefined
Uncaught TypeError: Cannot read property 'toString' of undefined

过了一会儿我意识到这可能在于我增强了这些原型。 Function.prototypes 似乎没有不良影响。但是,一旦我删除了所有 Object.prototype 方法,它就停止抛出错误。

一个简单的测试设置

<html lang="nl">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <script>
        Object.prototype.foo = function() {
           console.log('bar');
        }
    </script>
    <script src="//ajax.googleapis.com/ajax/libs/dojo/1.10.4/dojo/dojo.js"></script>
</body>
</html>

这是故意的吗?如果是这样,那么捕获这个错误并抛出一个更有意义的错误不是更好吗?

不要那样做。 :-)

您已将可枚举的 属性 添加到 Object.prototype,这意味着它显示在 所有对象 中(通过继承)在 for-in 循环等等:

// DON'T DO THIS (see text for why)
Object.prototype.foo = function() {
  console.log("foo");
};

// Looping over an object
var obj = {
  myOwnProperty: "bar"
};
for (var key in obj) {
  snippet.log("obj['" + key + "']: " + obj[key]);
}
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

请注意 foo 出现在我们的循环中。现在,通常您会希望在 for-in 循环中进行 hasOwnProperty 检查,但有时您不需要;将可枚举属性添加到 Object.prototype 打破了 hasOwnProperty 不合适的情况。

任何东西添加到Object.prototype通常被认为是一个非常糟糕的主意。强烈建议完全不要这样做。

但是,如果您有可靠的用例,请使用 非常独特的名称 定义 属性 并使其不可枚举:

Object.defineProperty(Object.prototype, "veryDistinctName", {
    value: function() {
        console.log("veryDistinctName");
    }
});

defineProperty 定义的属性在默认情况下是不可枚举的(默认情况下也是只读的),因此 veryDistinctName 不会出现在 for-in 循环中,例如:

// *IF* you absolutely, positively *have* to define a new
// property on Object.prototype, make it non-enumerable:
Object.defineProperty(Object.prototype, "veryDistinctName", {
  value: function() {
    console.log("veryDistinctName");
  }
});

// Looping over an object
var obj = {
  myOwnProperty: "bar"
};
for (var key in obj) {
  snippet.log("obj['" + key + "']: " + obj[key]);
}
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

如您所见,veryDistinctName 没有显示在循环中。


Is this intended?

可能不明确,不。他们只是假设你不会增加 Object.prototype.

And if so, would it not be better to then catch this error and throw a more meaningfull one?

这是一个见仁见智的问题,但是:可能不是,它有很多额外的开销,却收效甚微。一般来说,人们知道不增加Object.prototype。如果你这样做,那么很多事情都会很快崩溃,你很快就会学会不去做。所以迎合这种情况可能有点矫枉过正。

就是说,当 loading/initializing 库时,我可以看到一个检查的参数:

for (var key in {}) {
    throw new Error("Enumerable property '" + key + "' found on Object.prototype. Dojo doesn't support enumerable Object.prototype properties.");
}

当然,您仍然可以通过添加到 Object.prototype 稍后 来打破它。