2011-01-21 10 views
10

Mi rendo conto che, in senso stretto, non si tratta di una sottoclasse del tipo di array, ma funzionerà nel modo in cui ci si potrebbe aspettare, o mi imbatterò ancora in alcuni problemi con .length e simili? Ci sono degli svantaggi che non avrei se la normale sottoclasse fosse un'opzione?È un modo ragionevole di "sottoclasse" di un array javascript?

 function Vector() 
     { 
      var vector = []; 
      vector.sum = function() 
      { 
       sum = 0.0; 
       for(i = 0; i < this.length; i++) 
       { 
        sum += this[i]; 
       } 
       return sum; 
      }    
      return vector; 
     } 

     v = Vector(); 
     v.push(1); v.push(2); 
     console.log(v.sum()); 
+0

quanti di questi * * Vector array avete in programma di un'istanza? 2? Centinaia? –

+0

Hai dimenticato una var. 'var vector = [];'. – Thai

+0

Più di migliaia. – shino

risposta

7

mi piacerebbe avvolgere una matrice all'interno di un adeguato tipo di vettore come questo:

window.Vector = function Vector() { 
    this.data = []; 
} 

Vector.prototype.push = function push() { 
    Array.prototype.push.apply(this.data, arguments); 
} 

Vector.prototype.sum = function sum() { 
    for(var i = 0, s=0.0, len=this.data.length; i < len; s += this.data[i++]); 
    return s; 
} 

var vector1 = new Vector(); 
vector1.push(1); vector1.push(2); 
console.log(vector1.sum()); 

In alternativa si può costruire nuove funzioni prototipo su array e poi basta usare array normali.

Se si è coerenti con la denominazione degli array in modo che tutti inizino con una v minuscola per esempio o qualcosa di simile che li contraddistinguono chiaramente vettori vettoriali e non normali, e si esegue lo stesso sulle funzioni prototipo specifiche del vettore, quindi dovrebbe essere abbastanza facile da tenere traccia di

Array.prototype.vSum = function vSum() { 
    for(var i = 0, s=0.0, len=this.length; i < len; s += this[i++]); 
    return s; 
} 

var vector1 = []; 
vector1.push(1); vector1.push(2); 
console.log(vector1.vSum()); 
+0

Sembra che questo funzionerà meglio per me; Grazie. Ottieni il cookie. :) – shino

+1

Ricordare che la creazione di nuove funzioni di prototipo su Array aggiungerà tali metodi a tutti gli array creati. Questo potrebbe non essere qualcosa che vuoi quindi è qualcosa da prendere in considerazione. –

+0

Questo, tuttavia, non consente di chiamare vector1 [0] e tornare indietro 1, sfortunatamente. –

5

EDIT - ho inizialmente scritto che si potrebbe creare una sottoclasse un Array come qualsiasi altro oggetto, che era sbagliato. Impara qualcosa di nuovo ogni giorno. Ecco una buona discussione

http://perfectionkills.com/how-ecmascript-5-still-does-not-allow-to-subclass-an-array/

In questo caso, funzionerebbe composizione migliore? crea semplicemente un oggetto Vector e fallo appoggiare su un array. Questo sembra essere il percorso in cui ti trovi, devi solo aggiungere la spinta e qualsiasi altro metodo al prototipo.

+0

Picchiami, ma sì, preferirei creare un oggetto piuttosto che mettere a rischio il modo in cui qualcos'altro interagisce con esso. – Robert

+1

Mi piacerebbe poter accedere agli elementi dell'array con la notazione []. Sono vecchie notizie: http://dean.edwards.name/weblog/2006/11/hooray/? – shino

+0

Pensa di aver dimenticato lo "script" ... –

0

@hvgotcodes risposta ha un awesome link. Volevo solo rendere estate la conclusione qui.

Wrappers. Prototype chain injection

Questo sembra essere il metodo migliore per estendere matrice dall'articolo.

wrapper può essere utilizzato ... in cui la catena di prototipi dell'oggetto è aumentata, piuttosto che l'oggetto stesso.

function SubArray() { 
    var arr = [ ]; 
    arr.push.apply(arr, arguments); 
    arr.__proto__ = SubArray.prototype; 
    return arr; 
} 
SubArray.prototype = new Array; 

// Add custom functions here to SubArray.prototype. 
SubArray.prototype.last = function() { 
    return this[this.length - 1]; 
}; 

var sub = new SubArray(1, 2, 3); 

sub instanceof SubArray; // true 
sub instanceof Array; // true 

Unfortunally per me, questo metodo utilizza arr.__proto__, non supportato in IE 8, un browser devo sostenere.

Wrappers. Direct property injection.

Questo metodo è un po 'più lento di quanto sopra, ma funziona in IE 8-.

L'approccio Wrapper evita l'impostazione dell'ereditarietà o l'emulazione della relazione lunghezza/indici. Invece, una funzione di tipo fabbrica può creare un semplice oggetto Array e quindi aumentarlo direttamente con qualsiasi metodo personalizzato. Poiché l'oggetto restituito è di tipo Array, mantiene una relazione lunghezza/indici corretta, nonché [[Class]] di "Array". Inoltre eredita da Array.prototype, naturalmente.

function makeSubArray() { 
    var arr = [ ]; 
    arr.push.apply(arr, arguments); 

    // Add custom functions here to arr. 
    arr.last = function() { 
    return this[this.length - 1]; 
    }; 
    return arr; 
} 

var sub = makeSubArray(1, 2, 3); 
sub instanceof Array; // true 

sub.length; // 3 
sub.last(); // 3 
2

Solo un altro esempio del wrapper. Divertirsi con.

var _Array = function _Array() { 
    if (!(this instanceof _Array)) { 
     return new _Array(); 
    }; 
}; 

_Array.prototype.push = function() { 
    var apContextBound = Array.prototype.push, 
     pushItAgainst = Function.prototype.apply.bind(apContextBound); 

    pushItAgainst(this, arguments); 
}; 

_Array.prototype.pushPushItRealGood = function() { 
    var apContextBound = Array.prototype.push, 
     pushItAgainst = Function.prototype.apply.bind(apContextBound); 

    pushItAgainst(this, arguments); 
}; 

_Array.prototype.typeof = (function() { return (Object.prototype.toString.call([])); }()); 
0

C'è un modo che sembra un'eredità prototipica, ma è diverso in un solo modo.

In primo luogo permette di dare un'occhiata a uno dei standard ways di attuare eredità prototipo in javascript:

var MyClass = function(bar){ 
    this.foo = bar; 
}; 

MyClass.prototype.awesomeMethod = function(){ 
    alert("I'm awesome") 
}; 

// extends MyClass 
var MySubClass = function(bar){ 
    MyClass.call(this, bar); // <- call super constructor 
} 

// which happens here 
MySubClass.prototype = Object.create(MyClass.prototype); // prototype object with MyClass as its prototype 
// allows us to still walk up the prototype chain as expected 
Object.defineProperty(MySubClass.prototype, "constructor", { 
    enumerable: false, // this is merely a preference, but worth considering, it won't affect the inheritance aspect 
    value: MySubClass 
}); 

// place extended/overridden methods here 
MySubClass.prototype.superAwesomeMethod = function(){ 
    alert("I'm super awesome!"); 
}; 

var testInstance = new MySubClass("hello"); 
alert(testInstance instanceof MyClass); // true 
alert(testInstance instanceof MySubClass); // true 

Il prossimo esempio avvolge solo la struttura di cui sopra per tenere tutto pulito. E c'è un piccolo ritocco che sembra a prima vista compiere un miracolo. Tuttavia, tutto ciò che sta realmente accadendo è che ogni istanza della sottoclasse sta usando non il prototipo di Array come modello per la costruzione, ma piuttosto un'istanza di una matrice - così il prototipo della sottoclasse viene agganciato alla fine di un oggetto completamente caricato che passa l'anatra di un array - che poi copia. Se vedi ancora qualcosa di strano qui e ti infastidisce, non sono sicuro di poterlo spiegare meglio - quindi forse come funziona è un buon argomento per un'altra domanda. :)

var extend = function(child, parent, optionalArgs){ //... 
    if(parent.toString() === "function "+parent.name+"() { [native code] }"){ 
     optionalArgs = [parent].concat(Array.prototype.slice.call(arguments, 2)); 
     child.prototype = Object.create(new parent.bind.apply(null, optionalArgs)); 
    }else{ 
     child.prototype = Object.create(parent.prototype); 
    } 
    Object.defineProperties(child.prototype, { 
     constructor: {enumerable: false, value: child}, 
     _super_: {enumerable: false, value: parent} // merely for convenience (for future use), its not used here because our prototype is already constructed! 
    }); 
}; 
var Vector = (function(){ 
    // we can extend Vector prototype here because functions are hoisted 
    // so it keeps the extend declaration close to the class declaration 
    // where we would expect to see it 
    extend(Vector, Array); 

    function Vector(){ 
     // from here on out we are an instance of Array as well as an instance of Vector 

     // not needed here 
     // this._super_.call(this, arguments); // applies parent constructor (in this case Array, but we already did it during prototyping, so use this when extending your own classes) 

     // construct a Vector as needed from arguments 
     this.push.apply(this, arguments); 
    } 

    // just in case the prototype description warrants a closure 
    (function(){ 
     var _Vector = this; 

     _Vector.sum = function sum(){ 
      var i=0, s=0.0, l=this.length; 
      while(i<l){ 
       s = s + this[i++]; 
      } 
      return s; 
     }; 
    }).call(Vector.prototype); 

    return Vector; 
})(); 

var a = new Vector(1,2,3);       // 1,2,3 
var b = new Vector(4,5,6,7);      // 4,5,6,7 
alert(a instanceof Array && a instanceof Vector); // true 
alert(a === b);         // false 
alert(a.length);         // 3 
alert(b.length);         // 4 
alert(a.sum());         // 6 
alert(b.sum());         // 22 

Presto avremo classe e la possibilità di estendere le classi native in ES6, ma che può essere un altro anno ancora. Nel frattempo spero che questo aiuti qualcuno.

0
function SubArray(arrayToInitWith){ 
    Array.call(this); 
    var subArrayInstance = this; 
    subArrayInstance.length = arrayToInitWith.length; 
    arrayToInitWith.forEach(function(e, i){ 
    subArrayInstance[i] = e; 
    }); 
} 

SubArray.prototype = Object.create(Array.prototype); 
SubArray.prototype.specialMethod = function(){alert("baz");}; 

var subclassedArray = new SubArray(["Some", "old", "values"]); 
0

Ci sono molti buoni modi tutti suggeriti qui. Personalmente penso che il modo migliore per creare una sottoclasse di una "matrice" non sia una sottoclasse di una matrice reale, ma piuttosto una sottoclasse di un "oggetto simile a un array". Ce ne sono molti là fuori, personalmente io uso Collection.

http://codepen.io/dustinpoissant/pen/AXbjxm?editors=0011

var MySubArray = function(){ 
    Collection.apply(this, arguments); 
    this.myCustomMethod = function(){ 
    console.log("The second item is "+this[1]); 
    }; 
}; 
MySubArray.prototype = Object.create(Collection.prototype); 

var msa = new MySubArray("Hello", "World"); 
msa[2] = "Third Item"; 
console.log(msa); 
msa.myCustomMethod(); 
0

Al giorno d'oggi è possibile utilizzare sottoclassi con le classi ES6:

class Vector extends Array { 
    sum(){ 
    return this.reduce((total, value) => total + value) 
    } 
} 

let v2 = new Vector(); 
v2.push(1); 
v2.push(2); 
console.log(v2.sum()) 
Problemi correlati