我正在开发一个支持AJAX的asp.net应用程序。 我刚刚向Array.prototype添加了一些方法,比如
Array.prototype.doSomething = function(){
...
}
这个解决方案对我有用,可以以“漂亮”的方式重用代码。
但是当我测试它与整个页面一起工作时,我遇到了问题.. 我们有一些自定义的ajax扩展器,并且它们开始表现为意外:一些控件在其内容或值周围显示“未定义”。
原因可能是什么?我错过了修改标准对象原型的一些内容吗?
注意:我很确定在修改Array的原型时会出现错误。它应该只与IE兼容。
答案 0 :(得分:43)
修改内置对象原型通常是一个坏主意,因为它总是有可能与同一页面上的其他代码发生冲突。
对于Array对象原型,这是一个特别糟糕的主意,因为它有可能干扰迭代任何数组成员的任何代码片段,例如for .. in
。< / p>
使用示例(借鉴here)来说明:
Array.prototype.foo = 1;
// somewhere deep in other javascript code...
var a = [1,2,3,4,5];
for (x in a){
// Now foo is a part of EVERY array and
// will show up here as a value of 'x'
}
反之亦然 - 你应该避免使用..如果某些n00b修改了Array原型,你应该避免修改Array原型,以防某些n00b在数组上使用for..in。
最好使用doSomething函数创建自己类型的对象构造函数,而不是扩展内置数组。
Object.defineProperty
怎么样?
现在存在Object.defineProperty
作为扩展对象原型而不会使新属性可枚举的一般方法,但我仍然不会将此作为扩展内置类型的理由,因为即使除for..in
之外,仍有可能与其他脚本发生其他冲突。考虑使用两个Javascript框架的人,他们都尝试以类似的方式扩展Array并选择相同的方法名称。或者,考虑有人分支您的代码,然后将原始版本和分叉版本放在同一页面上。 Array对象的自定义增强功能是否仍然有效?
这是Javascript的现实,以及为什么你应该避免修改内置类型的原型,即使使用Object.defineProperty
。使用自己的构造函数定义自己的类型。
答案 1 :(得分:36)
虽然有可能与其他位冲突o&#39;代码覆盖原型上的函数仍然是一个风险,如果你想用现代版本的JavaScript做到这一点,你可以使用Object.defineProperty方法,关闭可枚举的位,例如。
// functional sort
Object.defineProperty(Array.prototype, 'sortf', {
value: function(compare) { return [].concat(this).sort(compare); }
});
答案 2 :(得分:10)
谨慎!也许你这样做了:fiddle demo
让我们说一个返回第一个元素的数组和方法foo:
var myArray = ["apple","ball","cat"];
foo(myArray) // <- 'apple'
function foo(array){
return array[0]
}
以上是可以的,因为在解释时间内功能被提升到顶部。
但是,这不起作用:(因为原型没有定义)
myArray.foo() // <- 'undefined function foo'
Array.prototype.foo = function(){
return this[0]
}
为此,只需在顶部定义原型:
Array.prototype.foo = function(){
return this[0]
}
myArray.foo() // <- 'apple'
是的!你可以覆盖原型!这是允许的。您甚至可以为阵列定义自己的
add
方法。
答案 3 :(得分:1)
一般来说,搞乱核心javascript对象是一个坏主意。你永远不会知道任何第三方库可能会有什么期望,并且在javascript中更改核心对象会改变它们的所有内容。
如果你使用Prototype,它会特别糟糕,因为原型混乱也具有全局范围,并且很难判断你是否会发生碰撞。实际上,即使在javascript中修改任何语言的核心部分通常也是一个坏主意。
(lisp可能是那里的小例外)
答案 4 :(得分:1)
你可以说扩充泛型类型。您可能已经覆盖了其他一些lib的功能,这就是它停止工作的原因。
假设您正在使用的某些lib使用函数Array.remove()扩展Array。加载lib后,您还可以将remove()添加到Array的原型中,但具有您自己的功能。当lib将调用你的函数时,它可能会以预期的方式工作并打破它的执行......这就是这里发生的事情。
答案 5 :(得分:0)
使用递归
function forEachWithBreak(someArray, fn){
let breakFlag = false
function breakFn(){
breakFlag = true
}
function loop(indexIntoSomeArray){
if(!breakFlag && indexIntoSomeArray<someArray.length){
fn(someArray[indexIntoSomeArray],breakFn)
loop(indexIntoSomeArray+1)
}
}
loop(0)
}
测试1 ...未调用中断
forEachWithBreak(["a","b","c","d","e","f","g"], function(element, breakFn){
console.log(element)
})
产生 一种 b C d Ë F g
测试2 ...在元素c之后调用break
forEachWithBreak(["a","b","c","d","e","f","g"], function(element, breakFn){
console.log(element)
if(element =="c"){breakFn()}
})
产生 一种 b c