Способы расширения объекта Array в javascript

я пытаюсь расширить объект Array в JavaScript с помощью некоторых удобных для пользователя методов, таких как Array.Add () вместо Array.push () и т. д.

Я реализую 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

3-м способом я хочу расширить объект Array внутри класса Array3. Как это сделать, чтобы не получать "push - это не функция"? и & quot; неопределенный & quot ;?

Здесь я добавляю 4-й способ.

//------------- 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. Я хотел иметь компактный определенный класс со всеми частями в одном месте. Но я думаю, что не могу сделать это иначе.

 demosthenes06 июл. 2012 г., 11:29
Я видел сегодня сценарий кофе. мне не понравился его синтаксис.
 SMathew05 июл. 2012 г., 23:23
Вы смотрели на сценарий кофе? Я обновлю свой ответ с примером
 demosthenes06 июл. 2012 г., 12:16
@SpacedMonkey, если кто-то использует мой пользовательский js lib, может настроить его foreach (), чтобы он не включал последние 2 элемента перечисления, потому что это тип объекта и его длина.
 SpacedMonkey05 июл. 2012 г., 11:08
Если вы добавите метод в Array, вы сломаете foreach () для массивов
 demosthenes06 июл. 2012 г., 11:23
я не буду добавлять метод в Array.prototype, как в первом примере. Это был тест. Я создам класс, который будет расширять объект Array. Например, jsArray. Объекты jsArray будут массивами, но с большим количеством функций.

Ответы на вопрос(8)

Некоторое время назад я прочитал книгуJavascript Ninja написаноJohn Resig, создательjQuery. He proposed a way to mimic array-like methods with a plain JS object. Basically, only 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'

Я не имею в виду, хорошо это или плохо. Это оригинальный способ сделатьArray операции. Преимущество заключается в том, что вы не продлитеArray prototype. Keep in mind that obj это равнинаobjectэто неArray, Следовательноobj instanceof Array вернусьfalse, Считатьobj какfaçade.

Если этот код вас интересует, прочитайте выдержкуListing 4.10 Simulating array-like methods.

Вы пытаетесь сделать что-то более сложное, чем просто добавить псевдоним для & quot; push & quot; называется & quot; Добавить & quot ;?

Если нет, то, вероятно, лучше избегать этого. Причина, по которой я полагаю, что это плохая идея, состоит в том, что, поскольку Array является встроенным типом javascript, его изменение приведет к тому, что у всех типов сценариев Array будет ваш новый & quot; Добавить & quot; метод. Вероятность конфликта имен с другой третьей стороной велика и может привести к тому, что сторонний скрипт потеряет свой метод в пользу вашего.

Мое общее правило состоит в том, чтобы сделать вспомогательную функцию для работы с массивом, если он где-то еще не существует, и расширять массив только в случае крайней необходимости.

 demosthenes05 июл. 2012 г., 07:28
конечно, я использую его в другом пространстве имен
 demosthenes05 июл. 2012 г., 07:05
сейчас я просто узнаю кое-что новое о Дж. Я хочу написать несколько расширенных методов для js, чтобы они выглядели как основные функции Visual Basic. Это больше подходит и проще для меня при написании веб-проектов.
 demosthenes05 июл. 2012 г., 13:32
нет, я не буду использовать какой-либо другой сторонний API. Это будет независимым.
 05 июл. 2012 г., 07:08
Похоже, отличное упражнение! Как раз то, что вам нужно, чтобы узнать больше JS.
 05 июл. 2012 г., 11:20
круто, удачи с этим. Я просто не хотел, чтобы вы сталкивались с распространенной ошибкой, которую допускают люди, заключающейся в расширении встроенного типа и блокировании стороннего расширения и потрате часы, пытаясь выяснить, почему библиотека не работает (что я делал раньше: S)

Вы также можете использовать этот способ в 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]
 19 сент. 2017 г., 15:20
Это расширяет прототип Array и не должно быть сделано (потому что это влияет на весь сайт)
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__

(старый ответ, не рекомендуется, может привести кпроблемы с производительностью)

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
 13 февр. 2016 г., 19:09
При использовании__proto__ поддерживается в большинстве реализаций JavaScript, он не был стандартной функцией, пока не был отмечен как устаревшая функция в es6. Также это может вызвать проблемы с производительностью при интенсивном использовании. Использование это вообще плохая идея.
 15 окт. 2016 г., 00:33
Вы должны передать значения в вашемconstructor вsuper, как это:constructor(...items) {super(...items) }
 14 февр. 2016 г., 02:45
@ TBotV63 согласился. в es6 вы можете просто расширить класс Array. обновил мой ответ

Вы НЕ МОЖЕТЕ расширять объект Array в 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",
}

Просто пример кода, вы можете изменить его и использовать по своему усмотрению. Но основная концепция, которой я рекомендую следовать, остается прежней.

 09 июн. 2014 г., 03:51
Я считаю плохой практикой назначатьprototype, Всегда лучше назначить свойства существующегоprototype объект.
 19 февр. 2015 г., 10:26
Вы говорите, что не можете расширить объект Array, но признаете, что добавление функций в Array.prototype возможно ... ваш ответ кажется мне противоречивым
 19 сент. 2017 г., 12:12
@Purefan - Это может быть противоречивым, но оно помогает понять, что делает (и не делает) Javascript, что противоречит интуитивно понятным людям из-за пределов JS-мира.
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

Ответ - компактный обходной путь, который работает так, как задумано во всех поддерживающих браузерах.

Решение Вопроса

Имена методов должны быть строчными. Прототип не должен быть изменен в конструкторе.

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

 demosthenes06 июл. 2012 г., 11:31
его синтаксис является чем-то новым для меня. я чувствую JavaScript более знакомым
 05 июл. 2012 г., 08:26
О, вы также можете использовать «Object.defineProperty» настроить геттеры и сеттеры.developer.mozilla.org/en/JavaScript/Reference/Global_Objects/…
 demosthenes05 июл. 2012 г., 07:31
Хорошо, я не могу использовать прототип внутри конструктора. Есть ли способ расширить объект Array внутри конструктора?
 05 июл. 2012 г., 08:17
Да, но это дорого, если вам приходится создавать множество объектов. Увидетьapi.jquery.com/jQuery.extend для реализации примера. Используя эту технику, вы можете. function Array3 () {extend (this, {add: function (item) {return this.push (item)}})};
 demosthenes05 июл. 2012 г., 07:09
да это 2-й способ. Я использую в целях Add вместо add, потому что я намереваюсь написать некоторые методы расширения, такие как визуальный базовый внешний вид.

В третьем примере вы просто создаете новое свойство с именемprototype для объектаArray3, Когда вы делаетеnew Array3 который должен бытьnew Array3()вы создаете экземпляр этого объекта в переменнуюlist3, СледовательноAdd метод не будет работать, потому чтоthis, который является рассматриваемым объектом, не имеет допустимого методаpush, Надеюсь, вы понимаете.

Edit: Проверять, выписыватьсяПонимание JavaScript контекста узнать больше оthis.

 demosthenes05 июл. 2012 г., 06:59
я вижу, this.prototype обрабатывается как свойство Array3, спасибо
 05 июл. 2012 г., 07:03
Также не забудьте добавить() когда вы создаете объектыArray также объект такnew Array() (или просто[]). Это работает, потому что браузеры умны.
 demosthenes05 июл. 2012 г., 08:12
хорошо, я добавлю () спасибо за подсказку elclanrs :)

Ваш ответ на вопрос