问题:
只要我将下面的代码添加到我的html页面,我就会得到:
Line: 4
Error: Object doesn't support the property or method "exec".
这是导致错误的原型:
Object.prototype.allKeys = function () {
var keys = [];
for (var key in this)
{
// Very important to check for dictionary.hasOwnProperty(key)
// otherwise you may end up with methods from the prototype chain..
if (this.hasOwnProperty(key))
{
keys.push(key);
//alert(key);
} // End if (dict.hasOwnProperty(key))
} // Next key
keys.sort();
return keys;
}; // End Extension Function allKeys
这是重现错误所需的最少代码(浏览器问题:IE9):
<!DOCTYPE html>
<html>
<head>
<title>TestPage</title>
<script type="text/javascript" src="jquery-1.9.1.min.js"></script>
<script type="text/javascript">
/*
Object.prototype.getName111 = function () {
var funcNameRegex = /function (.{1,})\(/;
var results = (funcNameRegex).exec((this).constructor.toString());
return (results && results.length > 1) ? results[1] : "";
}; // End Function getName
*/
Object.prototype.allKeys = function () {
var keys = [];
for (var key in this)
{
// Very important to check for dictionary.hasOwnProperty(key)
// otherwise you may end up with methods from the prototype chain..
if (this.hasOwnProperty(key))
{
keys.push(key);
//alert(key);
} // End if (dict.hasOwnProperty(key))
} // Next key
keys.sort();
return keys;
}; // End Extension Function allKeys
</script>
</head>
<body>
<select id="selLayers" name="myddl">
<option value="1">One</option>
<option value="2">Twooo</option>
<option value="3">Three</option>
<option value="4">Text1</option>
<option value="5">Text2</option>
</select>
<script type="text/javascript">
//var dict = { "de": { "Text1": "Ersetzung 1", "Text2": "Ersetzung 2" }, "fr": { "Text1": "Replacement 1", "Text2": "Réplacement 2" }, "it": { "Text1": "Replacemente 1", "Text2": "Replacemente 2" }, "en": { "Text1": "Replacement 1", "Text2": "Replacement 2"} };
/*
var languages = dict.allKeys();
for (var j = 0; j < languages.length; ++j)
{
var strCurrentLanguage = languages[j];
var dictReplacements = dict[strCurrentLanguage]
var keys = dictReplacements.allKeys();
//alert(JSON.stringify(dictReplacements));
//alert(JSON.stringify(keys));
for (var i = 0; i < keys.length; ++i) {
var strKey = keys[i];
var strReplacement = dictReplacements[strKey];
alert(strKey + " ==> " + strReplacement);
//alert('#selLayers option:contains("' + strKey + '")');
//$('#selLayers option:contains("' + strKey + '")').html(strReplacement);
//$('#selLayers option:contains("Text1")').html("foobar");
}
}
*/
$('#selLayers option:contains("Twooo")').text('Fish');
//alert(dict.allKeys());
//alert(dict["de"]["abc"]);
/*
$('#selLayers option[value=2]').text('Fish');
$('#selLayers option:contains("Twooo")').text('Fish');
$('#selLayers option:contains("Twooo")').html('Étage');
// http://stackoverflow.com/questions/7344220/jquery-selector-contains-to-equals
$("#list option[value=2]").text();
$("#list option:selected").each(function () {
alert($(this).text());
});
$("#list").change(function() {
alert($(this).find("option:selected").text()+' clicked!');
});
*/
</script>
</body>
</html>
我尝试重命名原型函数,以防它与任何jquery原型冲突,但这根本没有帮助。
答案 0 :(得分:6)
因为这会向每个对象添加一个可枚举的项目。 Sizzle(jQuery使用)使用对象文字来配置它们的选择器解析。当它循环这些配置对象以获取所有令牌时,它不会期望您的功能。在这种情况下,它可能会尝试将您的函数用作RegExp
。
想象一下这种情况:
var obj = { a: 1, b: 2, c: 3 };
var result = 0;
for (var prop in obj) {
// On one of these iterations, `prop` will be "allKeys".
// In this case, `obj[prop]` will be a function instead of a number.
result += obj[prop] * 2;
}
console.log(result);
如果您在Object
的原型中添加了任何不能用作数字的内容,那么您的结果将获得NaN
。
此问题的一个很好的解决方案是将allKeys
函数添加到Object
而不是Object.prototype
。这模仿Object.keys
:
Object.allKeys = function (obj) {
var keys = [];
for (var key in obj)
{
// Very important to check for dictionary.hasOwnProperty(key)
// otherwise you may end up with methods from the prototype chain..
if (obj.hasOwnProperty(key))
{
keys.push(key);
//alert(key);
} // End if (dict.hasOwnProperty(key))
} // Next key
keys.sort();
return keys;
}; // End Extension Function allKeys
答案 1 :(得分:3)
因为在枚举对象时,jQuery不会使用.hasOwnProperty()
检查来阻止其代码。
这样做是为了防止不良编码做法。他们要求用户遵守良好做法,而不是权衡他们的代码以适应此类做法,而不是在Object.prototype
上放置可枚举的属性。
换句话说...不要向Object.prototype
添加可枚举属性,除非您希望所有代码都针对这些属性运行防护,并且从不想要枚举继承的属性。
FWIW,如果你真的想在普通对象上调用方法,只需创建一个构造函数,以便有一个可以安全扩展的中间原型对象。
function O(o) {
if (!(this instanceof O))
return new O(o)
for (var p in o)
this[p] = o[p]
}
O.prototype.allKeys = function() {
// ...
};
现在您可以像这样创建对象:
var foo = O({
foo: "foo",
bar: "bar",
baz: "baz"
});
...而且Object.prototype
保持不变,所以普通物体仍然是安全的。枚举.hasOwnProperty()
对象时,您只需要使用O
后卫。
for (var p in foo) {
if (foo.hasOwnProperty(p)) {
// do stuff
}
}
对于要解析的JSON数据,您可以使用reviver函数将O
对象替换为普通对象。
var parsed = JSON.parse(jsondata, function(k, v) {
if (v && typeof v === "object" && !(v instanceof Array)) {
return O(v)
}
return v
});
答案 2 :(得分:3)
您可以使用允许设置描述符的defineProperty
来克服这种副作用。
Object.defineProperty(Object.prototype, 'propName', {value: 'your value', enumerable: false});