j'essaie d'étendre l'objet Array en JavaScript avec des méthodes conviviales comme Array.Add () à la place Array.Push (), etc.
j'implémente 3 façons de faire cela . malheureusement, la 3ème façon ne fonctionne pas et je veux demander pourquoi? et comment le faire fonctionner.
//------------- 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
de la 3ème manière, je veux étendre l'objet Array en interne classe Array3 . Comment faire cela afin de ne pas obtenir "Push n'est pas une fonction" et "indéfini"?
Ici j'ajoute une 4ème voie.
//------------- 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]);
Là encore, je dois utiliser prototype . J'espérais éviter d'utiliser des lignes supplémentaires en dehors du constructeur de classe comme Array4.prototype .Je voulais avoir une classe définie compacte avec toutes les pièces au même endroit. Mais je pense que je ne peux pas le faire autrement.
Les noms de méthodes doivent être en minuscules. Le prototype ne doit pas être modifié dans le constructeur.
function Array3() { };
Array3.prototype = new Array;
Array3.prototype.add = Array3.prototype.Push
dans CoffeeScript
class Array3 extends Array
add: (item)->
@Push(item)
Si vous n'aimez pas cette syntaxe et que vous DEVEZ l'étendre à partir du constructeur, Votre seule option est:
// 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)
}
});
};
Tu pourrais aussi faire ça
ArrayExtenstions = {
Add: function() {
}
}
extend(ArrayExtenstions, Array.prototype);
function Array3() { }
Array3.prototype = ArrayExtenstions;
Autrefois, 'prototype.js' avait une méthode Class.create. Vous pouvez envelopper tout cela est une méthode comme ça
var Array3 = Class.create(Array, {
construct: function() {
},
Add: function() {
}
});
Pour plus d'informations à ce sujet et sur la mise en œuvre, consultez le code source de 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__
(ancienne réponse, non recommandée, peut causer des problèmes de performances )
function SubArray() {
var arr = [ ];
arr.Push.apply(arr, arguments);
arr.__proto__ = SubArray.prototype;
return arr;
}
SubArray.prototype = new Array;
Vous pouvez maintenant ajouter vos méthodes à SubArray
SubArray.prototype.last = function() {
return this[this.length - 1];
};
Initialiser comme des tableaux normaux
var sub = new SubArray(1, 2, 3);
Se comporte comme des tableaux normaux
sub instanceof SubArray; // true
sub instanceof Array; // true
Il y a quelque temps, j'ai lu le livre Javascript Ninja écrit par John Resig , le créateur de jQuery . Fondamentalement, seul length
est requis.
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'
Je ne veux pas dire que c'est bon ou mauvais. C'est une façon originale de faire des opérations Array
. L'avantage est que vous ne prolongez pas le Array prototype
. N'oubliez pas que obj
est un object
ordinaire, ce n'est pas un Array
. Par conséquent, obj instanceof Array
renverra false
. Pensez obj
comme une façade.
Si ce code vous intéresse, lisez l'extrait Listing 4.10 Simulation de méthodes de type tableau.
Dans votre troisième exemple, vous créez simplement une nouvelle propriété nommée prototype
pour l'objet Array3
. Lorsque vous faites new Array3
qui devrait être new Array3()
, vous instanciez cet objet dans la variable list3
. Par conséquent, la méthode Add
ne fonctionnera pas car this
, qui est l'objet en question, n'a pas de méthode valide Push
. J'espère que tu as compris.
Edit: Check out Comprendre le contexte JavaScript pour en savoir plus sur this
.
Essayez-vous de faire quelque chose de plus compliqué, puis ajoutez simplement un alias pour "Push" appelé "Ajouter"?
Sinon, il serait probablement préférable d'éviter de le faire. La raison pour laquelle je suggère que c'est une mauvaise idée est que, comme Array est un type JavaScript intégré, sa modification entraînera pour tous les scripts Array de type votre nouvelle méthode "Ajouter". Les risques de conflits de noms avec une autre tierce partie sont élevés et le script de cette tierce partie pourrait perdre sa méthode au profit de la vôtre.
Ma règle générale est de créer une fonction d'assistance pour travailler sur le tableau s'il n'existe pas déjà quelque part et d'étendre le tableau s'il est extrêmement nécessaire.
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
La solution est une solution de contournement compacte qui fonctionne comme prévu dans tous les navigateurs associés.
Vous NE POUVEZ PAS étendre l'objet Array en JavaScript.
Au lieu de cela, vous pouvez définir un objet contenant une liste de fonctions exécutées sur le tableau, injecter ces fonctions dans cette instance de tableau et renvoyer cette nouvelle instance. Ce que vous ne devriez pas faire, c'est changer le Array.prototype
pour inclure vos fonctions personnalisées dans la liste.
Exemple:
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",
}
Juste un exemple de code, vous pouvez le modifier et l'utiliser comme vous le souhaitez. Mais le concept sous-jacent que je vous recommande de suivre reste le même.
Vous pouvez également utiliser cette méthode dans ES6:
Object.assign(Array.prototype, {
unique() {
return this.filter((value, index, array) => {
return array.indexOf(value) === index;
});
}
});
Résultat:
let x = [0,1,2,3,2,3];
let y = x.unique();
console.log(y); // => [0,1,2,3]