将自定义函数添加到Array.prototype中

时间:2009-06-04 02:46:36

标签: javascript arrays internet-explorer

我正在开发一个支持AJAX的asp.net应用程序。 我刚刚向Array.prototype添加了一些方法,比如

Array.prototype.doSomething = function(){
   ...
}

这个解决方案对我有用,可以以“漂亮”的方式重用代码。

但是当我测试它与整个页面一起工作时,我遇到了问题.. 我们有一些自定义的ajax扩展器,并且它们开始表现为意外:一些控件在其内容或值周围显示“未定义”。

原因可能是什么?我错过了修改标准对象原型的一些内容吗?

注意:我很确定在修改Array的原型时会出现错误。它应该只与IE兼容。

6 个答案:

答案 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