ich versuche, Array-Objekt in Javascript mit einigen benutzerfreundlichen Methoden wie Array.Add () statt Array.Push () usw. zu erweitern.
ich implementiere 3 Wege, dies zu tun . Leider funktioniert der 3. Weg nicht und ich möchte fragen, warum? und wie es funktioniert.
//------------- 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
auf dritte Weise möchte ich das Array-Objekt intern erweitern Array3-Klasse . Wie mache ich das, um nicht "Push ist keine Funktion" und "undefined" zu bekommen?
Hier füge ich einen vierten Weg hinzu.
//------------- 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]);
Auch hier muss ich prototype ..__ verwenden. Ich habe gehofft, zusätzliche Zeilen außerhalb des Klassenkonstruktors als Array4.prototype ..__ zu vermeiden. Aber ich denke, ich kann es nicht anders machen.
Methodennamen sollten Kleinbuchstaben sein. Prototyp sollte im Konstruktor nicht geändert werden.
function Array3() { };
Array3.prototype = new Array;
Array3.prototype.add = Array3.prototype.Push
in CoffeeScript
class Array3 extends Array
add: (item)->
@Push(item)
Wenn Ihnen diese Syntax nicht gefällt, und Sie MÜSSEN sie innerhalb des Konstruktors erweitern, Ihre einzige Option ist:
// 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)
}
});
};
Sie könnten das auch tun
ArrayExtenstions = {
Add: function() {
}
}
extend(ArrayExtenstions, Array.prototype);
function Array3() { }
Array3.prototype = ArrayExtenstions;
In früheren Tagen hatte 'prototype.js' eine Class.create-Methode. Sie könnten das alles so einwickeln
var Array3 = Class.create(Array, {
construct: function() {
},
Add: function() {
}
});
Weitere Informationen hierzu und zur Implementierung finden Sie im Quellcode von prototype.js
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__
(alte Antwort, nicht empfohlen, kann zu Leistungsproblemen führen )
function SubArray() {
var arr = [ ];
arr.Push.apply(arr, arguments);
arr.__proto__ = SubArray.prototype;
return arr;
}
SubArray.prototype = new Array;
Jetzt können Sie Ihre Methoden zu SubArray
hinzufügen.
SubArray.prototype.last = function() {
return this[this.length - 1];
};
Initialisieren Sie wie bei normalen Arrays
var sub = new SubArray(1, 2, 3);
Verhält sich wie normale Arrays
sub instanceof SubArray; // true
sub instanceof Array; // true
Vor einiger Zeit las ich das Buch Javascript Ninja von John Resig , dem Ersteller von jQuery . Er schlug vor, Array-ähnliche Methoden mit einem einfachen JS-Objekt nachzuahmen. Grundsätzlich ist nur length
erforderlich.
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'
Ich meine nicht, dass es gut oder schlecht ist. Es ist eine originelle Art, Array
-Operationen auszuführen. Der Vorteil ist, dass Sie den Array prototype
..__ nicht erweitern. Denken Sie daran, dass obj
eine einfache object
ist, es ist keine Array
. Deshalb gibt obj instanceof Array
false
zurück. Stellen Sie sich obj
als Fassade vor.
Wenn dieser Code für Sie von Interesse ist, lesen Sie den Auszug Listing 4.10 Array-ähnliche Methoden simulieren.
In Ihrem dritten Beispiel erstellen Sie nur eine neue Eigenschaft mit dem Namen prototype
für das Objekt Array3
. Wenn Sie new Array3
tun, der new Array3()
sein soll, instantiieren Sie dieses Objekt in der Variablen list3
. Daher funktioniert die Add
-Methode nicht, da this
, das betreffende Objekt, keine gültige Methode Push
hat. Ich hoffe du verstehst.
Edit: Check out JavaScript-Kontext verstehen , um mehr über this
zu erfahren.
Versuchen Sie, etwas komplizierter zu machen, als nur einen Alias für "Push" mit dem Namen "Hinzufügen" hinzuzufügen?
Wenn nicht, wäre es wahrscheinlich am besten, dies zu vermeiden. Ich schlage vor, dass dies eine schlechte Idee ist, weil Array ein eingebauter Javascript-Typ ist, wenn Sie ihn modifizieren, werden alle Scripts-Array-Typen mit Ihrer neuen Methode "Hinzufügen" versehen. Das Potenzial für Namenskollisionen mit anderen Drittanbietern ist hoch und könnte dazu führen, dass das Skript eines Drittanbieters seine Methode zugunsten Ihres Skripts verliert.
Meine allgemeine Regel ist, eine Hilfsfunktion für die Arbeit mit den Arrays zu erstellen, falls diese nicht bereits vorhanden ist, und Array nur dann zu erweitern, wenn es extrem notwendig ist.
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
Die Antwort ist eine kompakte Problemumgehung, die in allen unterstützten Browsern wie beabsichtigt funktioniert.
Sie können das Array-Objekt NICHT in JavaScript erweitern.
Stattdessen können Sie ein Objekt definieren, das eine Liste von Funktionen enthält, die für das Array ausgeführt werden, diese Funktionen in diese Array-Instanz einfügen und diese neue Array-Instanz zurückgeben. Was Sie nicht tun sollten, ist Array.prototype
so zu ändern, dass Ihre benutzerdefinierten Funktionen in die Liste aufgenommen werden.
Beispiel:
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",
}
Nur ein Beispielcode, Sie können ihn ändern und verwenden, wie Sie möchten. Das zugrunde liegende Konzept, das ich Ihnen empfehlen möchte, bleibt jedoch gleich.
Sie können diesen Weg auch in ES6 verwenden:
Object.assign(Array.prototype, {
unique() {
return this.filter((value, index, array) => {
return array.indexOf(value) === index;
});
}
});
Ergebnis:
let x = [0,1,2,3,2,3];
let y = x.unique();
console.log(y); // => [0,1,2,3]