Способы расширения объекта 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.
Я хотел иметь компактный определенный класс со всеми частями в одном месте.
Но я думаю, что я не могу сделать это в противном случае.
Ответы
Ответ 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
(старый ответ, не рекомендуется, может вызывать проблемы )
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
Ответ - это компактное обходное решение, которое работает по назначению во всех поддерживающих браузерах.