Javascript 在javascript中扩展Array对象的方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11337849/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 05:30:40  来源:igfitidea点击:

Ways to extend Array object in javascript

javascriptarraysclassextend

提问by demosthenes

i try to extend Array object in javascript with some user friendly methods like Array.Add() instead Array.push() etc...

我尝试使用一些用户友好的方法(例如 Array.Add() 而不是 Array.push() 等)在 javascript 中扩展 Array 对象...

i implement 3 ways to do this. unfortunetly the 3rd way is not working and i want to ask why? and how to do it work.

我实现了 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

in 3rd way i want to extend the Array object internally Array3 class. How to do this so not to get "push is not a function" and "undefined"?

在第三种方式中,我想在内部扩展 Array 对象 Array3 类。如何做到这一点,以免“推送不是函数”和“未定义”?

Here i add a 4th way.

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

//------------- 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]);

Here again i have to use prototype. I hoped to avoid to use extra lines outside class constructor as Array4.prototype. I wanted to have a compact defined class with all pieces in one place. But i think i cant do it otherwise.

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

采纳答案by SMathew

Method names should be lowercase. Prototype should not be modified in the constructor.

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

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

in CoffeeScript

在 CoffeeScript 中

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

If you don't like that syntax, and you HAVE to extend it from within the constructor, Your only option is:

如果您不喜欢这种语法,并且必须从构造函数中扩展它,那么您唯一的选择是:

// 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)
      }

   });
};

You could also do this

你也可以这样做

ArrayExtenstions = {
   Add: function() {

   }
}
extend(ArrayExtenstions, Array.prototype);



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

In olden days, 'prototype.js' used to have a Class.create method. You could wrap all this is a method like that

在过去,'prototype.js' 曾经有一个 Class.create 方法。你可以把所有这些都包装成这样的方法

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

    },    
    Add: function() {

    }
});

For more info on this and how to implement, look in the prototype.js source code

有关此以及如何实现的更多信息,请查看prototype.js 源代码

回答by laggingreflex

ES6

ES6

class SubArray extends Array {
    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__

使用 __proto__

(old answer, not recommended, may cause performance issues)

(旧答案,不推荐,可能会导致性能问题

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

Now you can add your methods to SubArray

现在您可以将您的方法添加到 SubArray

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

Initialize like normal Arrays

像普通数组一样初始化

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

Behaves like normal Arrays

表现得像普通数组

sub instanceof SubArray; // true
sub instanceof Array; // true

回答by roland

A while ago I read the book Javascript Ninjawritten by John Resig, the creator of jQuery. He proposed a way to mimic array-like methods with a plain JS object. Basically, only lengthis required.

不久前,我阅读了jQuery的创建者John Resig撰写的Javascript Ninja一书。他提出了一种用普通 JS 对象模拟类数组方法的方法。基本上,只需要。length

var obj = {
    length: 0, //only length is required to mimic an Array
    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'

I don't mean it's good or bad. It's an original way of doing Arrayoperations. The benefit is that you do not extend the Array prototype. Keep in mind that objis a plain object, it's not an Array. Therefore obj instanceof Arraywill return false. Think objas a fa?ade.

我的意思不是说它是好是坏。这是一种原始的Array操作方式。好处是您无需扩展Array prototype. 请记住,这obj是一个普通的object,它不是一个Array. 因此obj instanceof Array会返回false。认为obj是一种门面

If that code is of interest to you, read the excerpt Listing 4.10 Simulating array-like methods.

如果您对该代码感兴趣,请阅读代码清单 4.10 模拟类似数组的方法

回答by elclanrs

In your third example you're just creating a new property named prototypefor the object Array3. When you do new Array3which should be new Array3(), you're instantiating that object into variable list3. Therefore, the Addmethod won't work because this, which is the object in question, doesn't have a valid method push. Hope you understand.

在您的第三个示例中,您只是创建了一个以prototypeobject命名的新属性Array3。当您执行new Array3which should be 时new Array3(),您正在将该对象实例化为 variable list3。因此,该Add方法将不起作用,因为this所讨论的对象没有有效的方法push。希望你能理解。

Edit:Check out Understanding JavaScript Contextto learn more about this.

编辑:查看了解 JavaScript 上下文以了解有关this.

回答by duyker

Are you trying to do something more complicated then just add an alias for "push" called "Add"?

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

If not, it would probably be best to avoid doing this. The reason I suggest this is a bad idea is that because Array is a builtin javascript type, modifying it will cause all scripts Array type to have your new "Add" method. The potential for name clashes with another third party are high and could cause the third party script to lose its method in favour of your one.

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

My general rule is to make a helper function to work on the Array's if it doesnt exist somewhere already and only extend Array if its extremely necessary.

我的一般规则是创建一个辅助函数来处理数组,如果它在某处不存在,并且只有在非常必要时才扩展数组。

回答by Boopathi Rajaa

You CANNOT extend the Array Object in JavaScript.

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

Instead, what you can do is define an object that will contain a list of functions that perform on the Array, and inject these functions into that Array instance and return this new Array instance. What you shouldn't do is changing the Array.prototypeto include your custom functions upon the list.

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

Example:

例子:

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",
}

Just a sample code, you can modify it and use however you want. But the underlying concept I recommend you to follow remains the same.

只是一个示例代码,您可以修改它并随意使用。但是我建议您遵循的基本概念保持不变。

回答by selahattinunlu

You can also use this way in ES6:

你也可以在 ES6 中使用这种方式:

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

Result:

结果:

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

回答by Neni

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

The answer is a compact workaround which works as intended in all supporting browsers.

答案是一种紧凑的解决方法,它在所有支持的浏览器中都能按预期工作。