2012-07-05 56 views
32

我尝试在JavaScript扩展Array对象有一些用户友好的方法,如Array.Add()代替的Array.push()等数组对象...方式来扩展在JavaScript

我实现了3种方式来做到这一点。 不幸的是,第三种方式不工作,我想问为什么?以及如何做到这一点。

//------------- 1st way 
Array.prototype.Add=function(element){ 
    this.push(element); 
}; 

var list1 = new Array(); 
list1.Add("Hello world"); 
alert(list1[0]); 

//------------- 2nd way 
function Array2() { 
    //some other properties and methods 
}; 

Array2.prototype = new Array; 
Array2.prototype.Add = function(element){ 
    this.push(element); 
}; 

var list2 = new Array2; 
list2.Add(123); 
alert(list2[0]); 

//------------- 3rd way 
function Array3() { 
    this.prototype = new Array; 
    this.Add = function(element){ 
     this.push(element); 
    }; 
}; 

var list3 = new Array3; 
list3.Add(456); //push is not a function 
alert(list3[0]); // undefined 

在第三种方式我想扩展Array对象内部的Array3类。 如何做到这一点,以免得到“推动不是一个功能”和“未定义”?

这里我添加了第四种方式。

//------------- 4th way 
function Array4() { 
    //some other properties and methods 
    this.Add = function(element){ 
     this.push(element); 
    }; 
}; 
Array4.prototype = new Array(); 

var list4 = new Array4(); 
list4.Add(789); 
alert(list4[0]); 

在这里再次我必须使用原型。 我希望避免在类构造函数之外使用额外的行作为Array4.prototype。 我想在一个地方有一个紧凑的定义类与所有作品。 但我想我不能这样做,否则。

+0

如果你添加一个方法到数组,你将破坏数组的foreach() – SpacedMonkey

+0

你看过咖啡脚本吗?我将用示例更新我的答案 – SMathew

+0

我不会像第一个示例中那样向Array.prototype添加方法。这是一个考验。我将创建一个将扩展Array对象的类。例如jsArray。 jsArray对象将是数组,但具有更多功能。 – demosthenes

回答

27

方法名称应该是小写。原型不应该在构造函数中修改。

function Array3() { }; 
Array3.prototype = new Array; 
Array3.prototype.add = Array3.prototype.push 
在CoffeeScript中

class Array3 extends Array 
    add: (item)-> 
    @push(item) 

如果你不喜欢的语法,你必须把它从构造函数中延伸, 你唯一的选择是:

// define this once somewhere 
// you can also change this to accept multiple arguments 
function extend(x, y){ 
    for(var key in y) { 
     if (y.hasOwnProperty(key)) { 
      x[key] = y[key]; 
     } 
    } 
    return x; 
} 


function Array3() { 
    extend(this, Array.prototype); 
    extend(this, { 
     Add: function(item) { 
     return this.push(item) 
     } 

    }); 
}; 

你也可以这样做

ArrayExtenstions = { 
    Add: function() { 

    } 
} 
extend(ArrayExtenstions, Array.prototype); 



function Array3() { } 
Array3.prototype = ArrayExtenstions; 

过去,'prototype.js'曾经有一个Class.create方法。你可以换这一切就是这样

var Array3 = Class.create(Array, { 
    construct: function() { 

    },  
    Add: function() { 

    } 
}); 

有关此的详细信息以及如何实现的方法,看在prototype.js中源代码

+0

是的,这是第二种方式。我使用目的添加,而不是添加,因为我打算写一些扩展方法,如视觉基本的外观和感觉。 – demosthenes

+0

好吧我不能使用构造函数内的原型。有什么办法在构造函数中扩展Array对象吗? – demosthenes

+1

是的,但如果必须实例化大量对象,则代价很高。有关示例实现,请参阅http://api.jquery.com/jQuery.extend/。使用这种技术,你可以。函数Array3(){extend(this,{add:function(item){return this.push(item)}})}; – SMathew

2

在第三个示例中,您只需为对象Array3创建一个名为prototype的新属性。当你做new Array3这应该是new Array3(),你正在将该对象实例化为变量list3。因此,Add方法将不起作用,因为this(有关对象)没有有效的方法push。希望你能理解。

编辑:检查出Understanding JavaScript Context了解更多关于this

+0

我看到,this.prototype被视为Array3的属性,谢谢 – demosthenes

+1

也不要忘记在实例化对象时添加'()'。 'Array'也是一个对象,所以'new Array()'(或者简单地说'']')。它的作用是因为浏览器很聪明。 – elclanrs

+0

好吧,我会加()感谢提示elclanrs :) – demosthenes

0

你是否想要做更复杂的事情,然后添加一个别名称为“添加”的“推”?

如果没有,最好避免这样做。我建议这是一个坏主意的原因是,因为数组是一个内置的JavaScript类型,修改它会导致所有脚本数组类型有你的新的“添加”方法。与其他第三方发生名称冲突的可能性很高,可能会导致第三方脚本失去支持您的方法。

我的一般规则是,如果辅助函数不存在于某个地方,那么可以使用辅助函数来处理数组,如果它非常必要的话,那么只能扩展数组。

+0

现在我只是学习一些关于js的新东西。我想写一些扩展方法让js看起来像Visual Basic核心函数。这对我写作网站项目来说更适合和更容易。 – demosthenes

+0

听起来很不错!正是你需要了解更多的JS。 – elclanrs

+0

当然我用它在不同的名字空间 – demosthenes

0

不能扩展数组对象在JavaScript中。

相反,您可以做的是定义一个对象,该对象将包含在Array上执行的函数列表,并将这些函数注入该Array实例并返回这个新的Array实例。你不应该做的是改变Array.prototype以包括你的自定义功能的列表。

例子:

function MyArray() { 
    var tmp_array = Object.create(Array.prototype); 
    tmp_array = (Array.apply(tmp_array, arguments) || tmp_array); 
    //Now extend tmp_array 
    for(var meth in MyArray.prototype) 
    if(MyArray.prototype.hasOwnProperty(meth)) 
     tmp_array[meth] = MyArray.prototype[meth]; 
    return (tmp_array); 
} 
//Now define the prototype chain. 
MyArray.prototype = { 
    customFunction: function() { return "blah blah"; }, 
    customMetaData: "Blah Blah", 
} 

只是一个示例代码,你可以修改它,但是你想使用。但我建议你遵循的基本概念仍然是一样的。

+0

我发现分配'prototype'是不好的做法。分配现有'prototype'对象的属性总是更好。 – jchook

+1

你说你不能扩展数组对象,但承认向Array.prototype添加函数是可能的......你的答案似乎与我矛盾 – Purefan

+1

@Purefan - 这可能是矛盾的,但它有助于理解Javascript做什么(和不)做 - 这对JS世界以外的人来说是违反直觉的。 –

9

ES6

class SubArray extends Array { 
    constructor(...args) { 
     super(...args); 
    } 
    last() { 
     return this[this.length - 1]; 
    } 
} 
var sub = new SubArray(1, 2, 3); 
sub // [1, 2, 3] 
sub instanceof SubArray; // true 
sub instanceof Array; // true 

Using __proto__

(旧答案,不推荐使用,可能会导致performance issues

function SubArray() { 
    var arr = [ ]; 
    arr.push.apply(arr, arguments); 
    arr.__proto__ = SubArray.prototype; 
    return arr; 
} 
SubArray.prototype = new Array; 

现在,您可以将您的方法来SubArray

SubArray.prototype.last = function() { 
    return this[this.length - 1]; 
}; 

初始化像正常的阵列

var sub = new SubArray(1, 2, 3); 

行为像正常的阵列

sub instanceof SubArray; // true 
sub instanceof Array; // true 
+1

虽然在大多数JavaScript实现中都支持'__proto__',但在被标记为es6中的遗留功能之前,它不是标准功能。如果使用量很大,它也会导致性能问题。使用它通常是一个坏主意。 – Insomniac

+0

@ TBotV63同意。在es6中,您可以简单地扩展Array类。更新我的回答 – laggingreflex

+1

你应该在你的'constructor'值传递给'super',像这样: '构造函数(...项){超(...项)}' –

0

前段时间我读过约翰写的书的JavaScript忍者 Resig的创作者的jQuery。 他提出了一种使用普通对象模仿类似数组的方法。基本上只需要length

var obj = { 
    length: 0, 
    add: function(elem){ 
     Array.prototype.push.call(this, elem); 
    }, 
    filter: function(callback) { 
     return Array.prototype.filter.call(this, callback); //or provide your own implemetation 
    } 
}; 

obj.add('a'); 
obj.add('b'); 
console.log(obj.length); //2 
console.log(obj[0], obj[1]); //'a', 'b' 

我并不是说它的好坏。这是执行Array操作的原始方式。好处是你不会扩展Array prototype。 请记住,obj是一个普通的object,它不是Array。因此obj instanceof Array将返回false。将obj认为是立面

如果代码是你的兴趣,阅​​读摘录4.10模拟阵列状的方法

1

您还可以在ES6用这样的方式:

Object.assign(Array.prototype, { 
    unique() { 
     return this.filter((value, index, array) => { 
     return array.indexOf(value) === index; 
     }); 
    } 
}); 

结果:

let x = [0,1,2,3,2,3]; 
let y = x.unique(); 
console.log(y); // => [0,1,2,3] 
+0

这扩展了数组原型,不应该完成(因为它会影响整个站点) –

0
var SubArray = function() {           
    var arrInst = new Array(...arguments); // spread arguments object 
    /* Object.getPrototypeOf(arrInst) === Array.prototype */ 
    Object.setPrototypeOf(arrInst, SubArray.prototype);  //redirectionA 
    return arrInst; // now instanceof SubArray 
}; 

SubArray.prototype = { 
    // SubArray.prototype.constructor = SubArray; 
    constructor: SubArray, 

    // methods avilable for all instances of SubArray 
    add: function(element){return this.push(element);}, 
    ... 
}; 

Object.setPrototypeOf(SubArray.prototype, Array.prototype); //redirectionB 

var subArr = new SubArray(1, 2); 
subArr.add(3); subArr[2]; // 3 

答案是一个紧凑的解决方法,因为打算在所有支持的浏览器,其工作原理。