matriz - Formas de extender el objeto Array en javascript
push array into array javascript (8)
Intento extender el objeto Array en javascript con algunos métodos fáciles de usar como Array.Add () en lugar de Array.push () etc ...
Implemento 3 formas de hacer esto. desafortunadamente, la tercera forma no funciona y quiero preguntar por qué? y cómo hacerlo funcionar
//------------- 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
en 3ra forma quiero extender el objeto Array internamente a la clase Array3. ¿Cómo hacer esto para no obtener "push" no es una función "y" undefined "?
Aquí agrego una 4ª manera.
//------------- 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]);
Aquí otra vez tengo que usar un prototipo. Esperaba evitar el uso de líneas adicionales fuera del constructor de clase como Array4.prototype. Quería tener una clase compacta definida con todas las piezas en un solo lugar. Pero creo que no puedo hacerlo de otra manera.
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
Usando __proto__
(La respuesta anterior, no recomendada, puede causar problemas de rendimiento )
function SubArray() {
var arr = [ ];
arr.push.apply(arr, arguments);
arr.__proto__ = SubArray.prototype;
return arr;
}
SubArray.prototype = new Array;
Ahora puede agregar sus métodos a SubArray
SubArray.prototype.last = function() {
return this[this.length - 1];
};
Inicializar como matrices normales
var sub = new SubArray(1, 2, 3);
Se comporta como matrices normales
sub instanceof SubArray; // true
sub instanceof Array; // true
¿Estás tratando de hacer algo más complicado que solo agregar un alias para "presionar" llamado "Agregar"?
Si no, probablemente sería mejor evitar hacer esto. La razón por la que sugiero que esto es una mala idea es que, dado que Array es un tipo de JavaScript incorporado, al modificarlo, todas las secuencias de comandos Tipo de matriz tendrán su nuevo método "Agregar". El potencial de conflictos de nombres con otro tercero es alto y podría hacer que el script de terceros pierda su método a favor de uno.
Mi regla general es hacer que una función auxiliar funcione en la matriz si ya no existe en alguna parte y solo extender la matriz si es extremadamente necesario.
En su tercer ejemplo, solo está creando una nueva propiedad llamada prototype
para el objeto Array3
. Cuando new Array3
que debería ser new Array3()
, estás instanciando ese objeto en la lista de variables3. Por lo tanto, el método Add
no funcionará porque this
, que es el objeto en cuestión, no tiene un método push
válido. Espero que entiendas.
Editar: consulte Entender el contexto de JavaScript para obtener más información al this
.
Hace un tiempo leí el libro Javascript Ninja escrito por John Resig , el creador de jQuery . Propuso una forma de imitar los métodos tipo array con un objeto JS simple. Básicamente, solo se requiere 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''
No me refiero a que sea bueno o malo. Es una forma original de hacer operaciones Array
. El beneficio es que no extiende el Array prototype
. Tenga en cuenta que obj
es un object
simple, no es una Array
. Por lo tanto, obj instanceof Array
devolverá false
. Piensa en obj
como una fachada .
Si ese código es de su interés, lea el extracto Listado 4.10. Simulación de métodos tipo array .
Los nombres de los métodos deben ser minúsculos. El prototipo no se debe modificar en el constructor.
function Array3() { };
Array3.prototype = new Array;
Array3.prototype.add = Array3.prototype.push
en CoffeeScript
class Array3 extends Array
add: (item)->
@push(item)
Si no le gusta esa sintaxis, y TIENE que extenderla desde el constructor, su única opción es:
// 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)
}
});
};
También podrías hacer esto
ArrayExtenstions = {
Add: function() {
}
}
extend(ArrayExtenstions, Array.prototype);
function Array3() { }
Array3.prototype = ArrayExtenstions;
En el pasado, ''prototype.js'' solía tener un método Class.create. Podrías envolver todo esto es un método como ese
var Array3 = Class.create(Array, {
construct: function() {
},
Add: function() {
}
});
Para obtener más información sobre esto y cómo implementarlo, busque en el código fuente de prototype.js
NO PUEDE extender el objeto Array en JavaScript.
En cambio, lo que puede hacer es definir un objeto que contendrá una lista de funciones que se realizan en la matriz, e inyectar estas funciones en esa instancia de matriz y devolver esta nueva instancia de matriz. Lo que no debe hacer es cambiar Array.prototype
para incluir sus funciones personalizadas en la lista.
Ejemplo:
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",
}
Solo un código de muestra, puede modificarlo y usarlo como lo desee. Pero el concepto subyacente que recomiendo seguir es el mismo.
También puedes usarlo de esta manera en ES6:
Object.assign(Array.prototype, {
unique() {
return this.filter((value, index, array) => {
return array.indexOf(value) === index;
});
}
});
Resultado:
let x = [0,1,2,3,2,3];
let y = x.unique();
console.log(y); // => [0,1,2,3]
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 respuesta es una solución compacta que funciona según lo previsto en todos los navegadores compatibles.