Подтвердить что ты не робот

Способы расширения объекта 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

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

Использование __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

Ответ 3

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

Изменить: Ознакомьтесь с "Контекст JavaScript" , чтобы узнать больше о this.

Ответ 4

Некоторое время назад я читал книгу Javascript Ninja, написанную John 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. Моделирование подобных массиву методов.

Ответ 5

Вы также можете использовать этот путь в 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]

Ответ 6

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

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

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

Ответ 7

Вы НЕ МОЖЕТЕ расширить объект массива в JavaScript.

Вместо этого вы можете определить объект, который будет содержать список функций, которые выполняются в массиве, и вводить эти функции в этот экземпляр массива и возвращать этот новый экземпляр 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",
}

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

Ответ 8

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

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