我能否在JavaScript中创建自己的数组对象?

7

我创建了一个 JavaScript 应用程序,其中包含很多数组操作(排序、过滤等)。

目前我的函数是这样的:

function (myArray, arg1, arg2,...)

在这里,myArray是我正在操作的数组,arg1、arg2等是函数用来修改该数组的参数。

我认为,像jQuery一样,在对象和参数之间有明确的分离会更加清晰:

myArray.function(arg1, arg2,...)

我知道可以使用Array.prototype向所有数组添加函数,但由于我添加的功能非常特定,且在一般情况下对数组没有意义,因此这似乎太重了。我也知道可以创建一个对象,但是那样我就无法受益于JavaScript中可用的数组方法(如indexOf、filter等)。
有没有办法创建自己的数组对象,继承默认的数组方法,并允许我添加自己的方法?

3
继续使用该函数,不需要将所有内容都写成面向对象的形式。 - dynamic
2
没错,但我喜欢它的简洁性,例如用于链接或定义默认选项/参数。 - Christophe
5个回答

10

你有两个选择:

第一个选项是通过向 Array 对象添加新方法来扩展它:

Array.prototype.myMethod = function(arg1, arg2)
{
    // Use 'this' to access the array.
}
优点是每个 JavaScript 数组现在都将拥有这个额外的方法。当多个(外部)JavaScript 库尝试添加相同的方法时,这也可能是一个缺点。此外,这个新方法会出现在 for(var item in myArray) 结构中,这可能会有问题。
选项二是为您的扩展数组创建一个“工厂方法”:
function MyExtendedArray = function()
{
    var array = [];
    array.myMethod = function(arg1, arg2) {
        // Use 'this' or 'array' to access the array.
    };

    return array;
};

现在你可以编写以下代码以创建新的扩展数组:

var arr = MyExtendedArray();

2
我认为工厂方法正是我需要的特定应用程序。这太明显了...只是我没看到它 :-) 谢谢! - Christophe

5

不可以对 Array 进行子类化,同时还希望其像数组一样工作。具体而言,length 属性不会随着添加或删除元素而改变。

function MyArray() {}
MyArray.prototype = [];
MyArray.prototype.constructor = MyArray;
var instance = new MyArray;
instance[0] = 0;
alert(instance.length);  // alerts 0

这种情况发生的原因是只有通过new Array或类似[]这样的语法糖创建的对象才具有长度特殊处理。
上面的new MyArray创建了一个常规对象,其原型是Array,但是new操作符并不检查对象的原型是否为Array,也没有设置特殊的length处理。

有趣的是,如果你使用.push()方法将数据存储到数组中,长度会正确更新。 - Zlatin Zlatev
1
@ZlatinZlatev,最近的EcmaScript候选版本的目标是允许对Array、RegExp和Date等内容进行子类化,因此这个答案可能不再正确。也许你正在看到一些最近JavaScript引擎的行为,它们正在实现对数组的子类化支持。 - Mike Samuel
好的,至少在Chrome的最新版本和Rhino引擎的最新版本(截至今天的日期-2015年8月31日)中,确实存在您和我描述的行为。 - Zlatin Zlatev

5
您可以直接将函数添加到对象上,而不是原型中:

您可以直接将函数添加到对象上,而不是原型中:

var myArray = new Array();
myArray.myFunc = function(){ /* do stuff! */ };
myArray.myFunc();

1
我创建了这个数组,是我的版本,但对其进行了一些修改,与原始数组不同的是,在此数组中,您无法更改长度。
let ary = [1,2,3];
console.log(ary.length); //3

ary.length = 999;
console.log(ary.length); //999

因为我使用了get函数来获取我的长度,并使用闭包来保存原始数组长度的值。
let myArray = new MyArray(1,10); //new MyArray(from,to)
console.log(myArray.length); // 10

myArray.length = 999;
console.log(myArray.length); // 10  //still 10 because .length is a get function 

我的数组代码是

let _getlength = {}, _inclength = {}, _declength = {};

class MyArray{

 constructor(from, to)
  {
    this.key = Symbol('ignore this key');

    //i make it a closer because i don't want any one to change the length
    // by this my length become private and can be only incremented by one by "_inclength()" function or
    [_getlength[this.key], _inclength[this.key], _declength[this.key]] = (
        () =>
        {
            let length = 0;

            let getLength = () =>
            {
                return length;
            };

            let inclength = () =>
            {
                length++;

                this[length - 1] = 0;

                return length;
            };

            let declength = () =>
            {
                return --length;
            };


            return [getLength, inclength, declength];
        }
    )();

    if (from != null || to != null)
    {
        for (let num = from; num <= to; num++)
        {
            this.push(num);
        }
    }

}

push(value)
{
    this[this.IncreaseLengthByOne() - 1] = value;
}

unshift(value)
{
    this.addAt(0, value)
}

addAt(index, value)
{
    this.IncreaseLengthByOne();
    for (let i = this.length - 2; i >= index; i--)
    {
        this[i + 1] = this[i];
    }

    this[index] = value;
}

removeAt(index)
{

    for (let i = index; i < this.length - 1; i++)
    {
        this[i] = this[i + 1];
    }

    this.pop();
}

pop()
{
    _declength[this.key]();
    delete this[this.length];
}

get length()
{
    return _getlength[this.key]();
}

IncreaseLengthByOne()
{
    return _inclength[this.key]();
}

forEach(callback)
{
    for (let i = 0; i < this.length; i++)
    {
        callback(this[i], i, this);
    }
}

map(callback)
{
    let myArray = new MyArray();
    for (let i = 0; i < this.length; i++)
    {
        myArray.push(callback(this[i], i, this));
    }

    return myArray;
}


// if you don't know what it is then go and learn what generators are! what Symbol(primitive type) is and what Symbol.iterator is then
// come back
* [Symbol.iterator]()
{
    for (let i = 0; i < this.length; i++)
    {
        yield this[i];
    }
}
}

示例: 创建一个名字数组,并向其中添加 "Ali"、"Hadi" 和 "Amber"

let names = new MyArray();

names.push('Ali');
names.push('Hadi');
names.push('Amber');
console.log(names); // MyArray {0: "Ali", 1: "Hadi", 2: "Amber"}

将每个名字修改为在末尾添加他们的姓氏“Nawaz”,例如“Ali”变为“Ali Nawaz”

let fullNames = names.map(nam => nam +' Nawaz');
console.log(fullNames); //MyArray {0: "Ali Nawaz", 1: "Hadi Nawaz", 2: "Amber Nawaz"}

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接