2009-01-08 6 views
0

Je crée un petit plugin de code qui vous permet de faire des choses avec des tableaux. Je ne veux pas ajouter les fonctions à l'objet de tableau en utilisant une construction de prototype, ce que je veux que les gens peuvent faire quelque chose comme:

arrayFunction([1, 2, 3]).someSpecialArrayFunction(); 

Ainsi en laissant l'objet de tableau normal non modifié.
Alors je suis venu avec la construction suivante (inspirée du code source jQuery):

var arrayFunction = window.arrayFunction = function(array) { 
    return new arrayFunction.fn.init(array); 
} 
arrayFunction.fn = arrayFunction.prototype = { 
    init: function(array){ 
     this.a = array; 
     //should I return something here? 
    }, 
    someSpecialArrayFunction: function(){ 
     //Super cool custom stuff here. 
    } 
} 

Toutefois, cela ne fonctionne pas (évidemment). Que devrait-il se passer dans la fonction init()?

L'erreur est maintenant droit que lorsque je tente:

arrayFunction(array).someSpecialArrayFunction(); 

il est dit que someSpecialArrayFunction() n'est pas une fonction?

Comment devrait-on faire cela?

modifier
Oui, cela est en effet un exemple simpliefied. La chose réelle a beaucoup plus de méthodes.

En outre, je pensais simplement à quel point ce serait génial si cela supportait aussi le chant, comment le feriez-vous?

+0

Le $ pour jquery est en fait un objet. – Malfist

+0

En Javascript, toutes les fonctions sont des objets - vous déclarez réellement des objets en utilisant le mot-clé de la fonction, ainsi le jQuery $ est à la fois un objet et une fonction qui renvoie des instances de cet objet. Cela peut prendre un peu de s'habituer à ... –

+0

Cherchez-vous ici un moyen de faire votre exemple * travail * - ou pour un motif général pour ajouter des méthodes à un objet encapsuleur en les ajoutant au prototype de l'encapsuleur, par exemple. donc vous pouvez gérer de grandes collections de méthodes d'extension? –

Répondre

2

Ou tout simplement :

var arrayFunction = function(array) { 
    var someSpecialArrayFunction = function() { 
     // do something with array 
    }; 
    return { 
     someSpecialArrayFunction: someSpecialArrayFunction 
    } 
}; 
arrayFunction([1, 2, 3]).someSpecialArrayFunction(); 

Bien être prudent avec cela, si vous vous retrouvez avec trop de méthodes Il est probablement préférable d'utiliser le prototype.

+0

Vous devriez annuler votre modification: cela ne fonctionne pas! La variable de tableau dans votre fermeture sera toujours liée au tableau passé comme argument au premier appel de myArrayFunction() ... – Christoph

+0

haha, vous avez raison :) –

1

Je ne suis pas sûr que ce soit la meilleure syntaxe pour obtenir ce que vous voulez, mais je suppose que cela est un dégrossi exemple ... est ici Anyways un moyen rapide de faire fonctionner

var arrayFunction = window.arrayFunction = function(array) { 
    return new arrayFunction.fn.init(array); 
} 
arrayFunction.fn = arrayFunction.prototype = { 
    init: function(array){ 
     var a = array; 
     return { 
      someSpecialArrayFunction: function(){ 
       alert (a.join(' - ')); //Super cool custom stuff here. 
      } 
     }; 
    }, 
} 
arrayFunction([1, 2, 3]).someSpecialArrayFunction(); 
0

sktrdie s answer est belle.

Une autre chose à prendre en compte serait d'utiliser le flyweight pattern au lieu de renvoyer une nouvelle instance d'objet à chaque appel de votre wrapper. La fonction ExtJS Ext.fly le fait; il renvoie une instance globalement partagée.

0

Essayez quelque chose comme ceci:

var mathWrapper = function(array) { 
    return { 
     mean : function(){ 
      if (array.length == 0) return(0); 
      var total = 0; 
      for (var i = 0; i < array.length; i++) total += array[i]; 
      return(total/array.length); 
     }, 
    }; 
} 

Invoquer via quelque chose comme

document.write(mathWrapper([1,2,3,4,5,6]).mean()); 

doit retourner la moyenne des éléments du tableau.

+0

Ceci n'est pas efficace en mémoire - utilisez un objet wrapper et ajoutez les méthodes à son prototype à la place ... – Christoph

+0

@Christoph - ah ... tout à coup tout un tas de choses qui me confondaient ont un sens! Merci. –

0

Si vous ne voulez pas changer t Array.prototype, la seule solution vraiment réalisable ajoute les méthodes de l'objet tableau spécifique:

function doSomething() {} 
function doOther() {} 

function wrap(array) { 
    array.doSomething = doSomething; 
    array.doOther = doOther; 
    return array; 
} 

Notez que je ne suis pas la définition doSomething() et doOther() au sein wrap() - autrement , nous créons de nouveaux objets de fonction sur chaque appel, ce qui est très inefficace.

Une variante plus sophistiquée serait la suivante:

function doSomething() {} 
function doOther() {} 

function wrap(array) { 
    if(this instanceof arguments.callee) { 
     this.doSomething = doSomething; 
     this.doOther = doOther; 
    } 
    else { 
     arguments.callee.prototype = array; 
     return new arguments.callee; 
    } 
} 

Ici, nous créons un nouvel objet d'emballage (et ne pas ajouter des propriétés au tableau lui-même). L'objet wrapper aura toujours accès à toutes les propriétés du tableau. Il y a une légère hic cependant:

var foo = wrap([1,2,3]); 
document.writeln(foo.length); // writes 3 
foo.push(4); 
document.writeln(foo.length); // writes 4 in FF, 3 in IE 
foo[4] = 5; 
foo[5] = 6; 
document.writeln(foo.length); // still writes 4?! 

L'utilisation foo[4] = accédera à notre objet d'emballage et les propriétés 4 et 5 seront là ensemble et non dans le tableau - par conséquent, sa propriété de longueur ne sera pas mis à jour. Dans IE, l'appel push() échouera déjà à correctement mettre à jour le tableau ...

Si votre objet wrapper n'a pas besoin de 'réacheminer' les appels à l'objet tableau, il existe d'autres solutions utilisant des fermetures - le premier exemple de sktrdie est un de ceux-ci. Je discuterais contre eux parce qu'ils créeront de nouveaux objets de fonction avec chaque appel aussi bien. Ce que je ferais:

function wrap(array) { 
    if(this instanceof arguments.callee) 
     this.array = array; 
    else return new arguments.callee(array); 
} 

wrap.prototype.doSomething = function() {}; 
wrap.prototype.doOther = function() {}; 

Ici, vous pouvez accéder au tableau dans doSomething() et doOther() via this.array.

0

Il suffit d'étendre l'objet Array et d'ajouter vos méthodes de fantaisie à votre objet. Vous pouvez ensuite créer une fonction de pont qui prend un tableau en argument et renvoie votre version de tableau. Cette méthode est de loin plus facile et plus utile.

Questions connexes