Javascript prototyping awesomeness

Door Gamebuster op maandag 21 juni 2010 17:49 - Reacties (23)
Categorie: if(post.relatedTo("programming")), Views: 4.026

Om mijn portfolio eens aan te vullen heb ik besloten eens een leuke kleine javascript-based tetris te maken met een zo net mogelijke broncode en zonder gebruik van een framework.

Javascript kende ik als een vervelende taal waar werken zonder framework eigenlijk vragen om problemen is, maar na een half jaar niets met JS gedaan te hebben en nu weer begonnen te zijn bevalt het me zelfs beter dan het gebruik van een framework.

Prototyping is een leuke feature van javascript die ik eigenlijk nooit eerder kende. Vind het eigenlijk best vreemd dat ik nooit prototyping terugzie in andere talen of omgevingen, terwijl het juist wel geinig is. (C# / java / Objective-C + prototyping == awesomeness?)

Voor diegenen die prototyping in JS niet kennen: Prototyping is een feature van javascript waarbij je methodes kan toevoegen aan bestaande classes en alle instances van die class. In het onderstaande voorbeeld zie je hoe ik een simpele methode heb toegevoegd aan de Array-class en al zijn instances:

JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var nummertjes = [1,2,3,3,4];

/**
 * Count the number of occurrences of <code>element</code> in this array.
 * @param element The element to count.
 * @type Number
 * @return The number of occurrenced as an <code>int</code>.
 */
Array.prototype.count = function(element) {
    var c = 0;
    for(var i=0;i<this.length;i++) {
        if(this[i]===element) {
            c++;
        }
    }
    return c;
}

alert(nummertjes.count(3));



De bovenstaande code spuugt bij mij een irritante popup uit met een nette "2" erin, aangezien het getal "3" 2 keer voorkomt in de vers aangemaakte Array.

De code die ik zover heb geschreven werkt in alle browsers, inclusief Internet Explorer 6, zonder vage browser-specifieke tricks of hacks uit te voeren.

Hoe dan ook, als deze tetris eenmaal af is wordt dit een leuke aanvulling voor mijn portfolio :)

note: Ik ga nu verder aan de scripts en kutcomputer.nl is het domein waar ik mijn websites live op test. Het script kan dus falen tijdens het lezen van dit bericht. Op het moment van schrijven werkt het uiteraard.

[/more]

Volgende: hello from Javascript :D 09-'10 hello from Javascript :D
Volgende: Wereldwijd filesharing netwerk zonder centrale server 05-'10 Wereldwijd filesharing netwerk zonder centrale server

Reacties


Door Tweakers user ZpAz, maandag 21 juni 2010 17:54

Je zou in de ander genoemde talen toch een classe kunnen extenden waarmee je hetzelfde effect hebt? Dan weet je ook nog eens dat je niet gaat botsen met werk van anderen, die toevallig 'dezelfde naamgeving' hebben gebruikt, waardoor of jou werk of hun werk stuk gaat als je het samen gebruikt.

[Reactie gewijzigd op maandag 21 juni 2010 17:57]


Door Tweakers user Gamebuster, maandag 21 juni 2010 17:57

ZpAz schreef op maandag 21 juni 2010 @ 17:54:
Je zou in de ander genoemde talen toch een classe kunnen extenden waarmee je hetzelfde effect hebt? Dan weet je ook nog eens dat je niet gaat 'colliden' met werk van anderen, die toevallig 'dezelfde naamgeving' hebben gebruikt, waardoor of jou werk of hun werk stuk gaat als je het samen gebruikt.
Maar bij prototyping heb je de keuze om de bestaande classes en zijn instances uit te breiden. Het uitbreiden van bestaande objecten als String zou ik niet alleen in javascript leuk vinden, maar ook in andere talen, waaronder Java. Uiteraard, in Java kan je gewoon een nieuwe CharSequence implementatie schrijven als vervanger voor String, maar dit prototyping vind ik ook een leuke feature.

Door Tweakers user ZpAz, maandag 21 juni 2010 18:00

Inderdaad, maar je hebt kans dat iemand anders (wiens code je gebruikt) ook dat in gedachten heeft, en dan kan je dus vreemde scenarios krijgen ;)

Door Tweakers user Gamebuster, maandag 21 juni 2010 18:04

ZpAz schreef op maandag 21 juni 2010 @ 18:00:
Inderdaad, maar je hebt kans dat iemand anders (wiens code je gebruikt) ook dat in gedachten heeft, en dan kan je dus vreemde scenarios krijgen ;)
Jah, dat klopt, beetje voorzichtig omgaan met prototyping. Eventueel een "backup" maken van de bestaande prototypes of namespaces simuleren. Wat je zegt kan ook gebeuren met classes of functies; je kan ook code van een ander gebruiken met een class/functie met dezelfde naam. Dan zit je ook met vreemde scenario's. Ik zie niet waarom dit bij prototyping anders is, of zie ik nu iets over het hoofd?

Door Tweakers user ZpAz, maandag 21 juni 2010 18:11

Met classes (of althans in de talen waar ik mee heb gewerkt) (Java/PHP/C++/Obj-C/C#) heb je zelf een include systeem of moet je de betreffende classe handmatig includen en werkt het enkel voor de objecten die daadwerkelijk de classe extenden.

Als je 2x dezelfde classe included (al dan niet met andere functies) krijg je netjes een error dat je dat probleem hebt.

In het geval van prototyping kan iedereen ergens in de code een method van een bestaande classe overriden, zonder dat je daar een warning van krijgt als dat al eerder is gebeurd.

[Reactie gewijzigd op maandag 21 juni 2010 18:12]


Door Tweakers user Gamebuster, maandag 21 juni 2010 18:16

Dat klopt; je krijgt geen melding, maar dat ligt aan de taal javascript en niet aan prototyping zelf. In JS kan je ook bestaande functies overschrijven zonder waarschuwing.

Als je prototyping zou toevoegen aan andere talen zou je inderdaad kunnen overwegen om errors te smijten bij overschrijven van bestaande prototypes, net als het overschrijven van classes of functies.

Door Tweakers user Blaise, maandag 21 juni 2010 18:22

Ha leuk! Ik heb ook eens Tetris geprogrammeerd om dezelfde reden.
Mijn versie: http://www.blaisekal.com/play/Tetris/

Jij hebt een iets gestructureerdere aanpak, zie ik als ik je broncode doorsnuffel :)

[Reactie gewijzigd op maandag 21 juni 2010 18:28]


Door Tweakers user Sebazzz, maandag 21 juni 2010 18:22

Waarom denk je dat Javascript ook geen object georienteerde taal is (zoals vaak wordt beweerd) maar een prototype-based taal? ;)
Of zoals wikipedia het verteld:
Paradigm Multi-paradigm: prototype-based, functional, imperative, scripting
In C# kan je overigens via extension methods het prototypen van Javascript emuleren:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
IEnumerable<int> integers = new[]{1,2,3,3,4};
Console.WriteLine(integers.CountElements(3)); // 2

// ergens anders
public static class Extensions {
    //<summary>Counts the occurances of the given item</summary>
    public static int CountElements<T>(this IEnumerable<T> iterable, T @object) {
         int n=0;
         foreach (T item in iterable) {
             if (item.Equals(@object)) { n++; }
         }
        return n;
    }
}

[Reactie gewijzigd op maandag 21 juni 2010 18:27]


Door Tweakers user SPee, maandag 21 juni 2010 18:29

Bij de OO talen kun je met abstracte klasses werken en subclasses. Met die subclasses kun je ook functies toevoegen of overrulen.
En voor Java heb je ook bytecode manipulators, waarmee je ook zulk soort aanpassingen kan doen. Maar dat gaat eigenlijk tegen de taal in.
Bij javascript is dat niet echt het geval.

Door Tweakers user Gamebuster, maandag 21 juni 2010 18:33

Blaise schreef op maandag 21 juni 2010 @ 18:22:
Ha leuk! Ik heb ook eens Tetris geprogrammeerd om dezelfde reden.
Mijn versie: http://www.blaisekal.com/play/Tetris/

Jij hebt een iets gestructureerdere aanpak, zie ik als ik je broncode doorsnuffel :)
Mooi designtje :D

Ik heb nog geen design :( Zal waarschijnlijk gewoon een saaie groep divjes met borders worden :P

Jouw code is ook netjes; ik probeer bij mijn versie echter te focussen op een OOP aanpak, dus de code wordt wat groter.

Is overigens al mijn 3e tetris; de vorige 2 had ik tijden terug gemaakt toen ik net begon met javascript, maar ben ze kwijt.

[Reactie gewijzigd op maandag 21 juni 2010 18:37]


Door Tweakers user Gamebuster, maandag 21 juni 2010 18:43

Sebazzz schreef op maandag 21 juni 2010 @ 18:22:
Waarom denk je dat Javascript ook geen object georienteerde taal is (zoals vaak wordt beweerd) maar een prototype-based taal? ;)
Of zoals wikipedia het verteld:

[...]


In C# kan je overigens via extension methods het prototypen van Javascript emuleren:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
IEnumerable<int> integers = new[]{1,2,3,3,4};
Console.WriteLine(integers.CountElements(3)); // 2

// ergens anders
public static class Extensions {
    //<summary>Counts the occurances of the given item</summary>
    public static int CountElements<T>(this IEnumerable<T> iterable, T @object) {
         int n=0;
         foreach (T item in iterable) {
             if (item.Equals(@object)) { n++; }
         }
        return n;
    }
}

Geinig; kan helaas niet in Java zover ik weet. Wel aparte syntax; waarom staat de classname als 1e argument?

Iets als dit lijkt me logischer:

C#:
1
2
3
4
5
6
7
8
9
10
public extension IENumerable<T> {
    //<summary>Counts the occurances of the given item</summary>
    public int CountElements<T>(T @object) {
         int n=0;
         foreach (T item in this) {
             if (item.Equals(@object)) { n++; }
         }
        return n;
    }
}

[Reactie gewijzigd op maandag 21 juni 2010 18:44]


Door Tweakers user kipusoep, maandag 21 juni 2010 19:15

Wilde net zeggen, in C# heb je Extension Methods, die 100x more awesome zijn :D

Door Tweakers user Little Penguin, maandag 21 juni 2010 19:49

Die C# extension methods zijn overigens regelrecht afgekeken van Borland Embarcadero Delphi, die al eerder class helpers introduceerde. (Overigens wel het eerste in Delphi 4 dotnet, om zaken die wel in Delhi zitten maar niet in dotnet toch aan te kunnen bieden).

Verder is het AFAIK primair een truck op compile-niveau en niet op object/functie niveau (zoals het bij JavaScript prototyping wel is).

Door Tweakers user Gamebuster, maandag 21 juni 2010 19:53

Little Penguin schreef op maandag 21 juni 2010 @ 19:49:
Die C# extension methods zijn overigens regelrecht afgekeken van Borland Embarcadero Delphi, die al eerder class helpers introduceerde. (Overigens wel het eerste in Delphi 4 dotnet, om zaken die wel in Delhi zitten maar niet in dotnet toch aan te kunnen bieden).

Verder is het AFAIK primair een truck op compile-niveau en niet op object/functie niveau (zoals het bij JavaScript prototyping wel is).
Wat is bij C# (en alle andere talen) nou niet afgekeken?

C# is gewoon een java kloon met wat fancy uitbreidingen en volgens mij ook wat sneller.

Door Tweakers user Bigs, maandag 21 juni 2010 20:13

In Ruby kun je dit geintje zelfs uithalen op instanties, dus:

bla = MijnClass.new()

def bla.nieuwe_method
# doe iets met een private instance variable ofzo
end

In tegenstelling tot wat je misschien zou denken kan dit ook voor niet-kwaadaardige dingen gebruikt worden.

Door Tweakers user Gamebuster, maandag 21 juni 2010 20:57

Bigs schreef op maandag 21 juni 2010 @ 20:13:
In Ruby kun je dit geintje zelfs uithalen op instanties, dus:

bla = MijnClass.new()

def bla.nieuwe_method
# doe iets met een private instance variable ofzo
end

In tegenstelling tot wat je misschien zou denken kan dit ook voor niet-kwaadaardige dingen gebruikt worden.
Bij javascript ook:


JavaScript:
1
2
3
4
5
6
7
var a = "string1";
var b = "string2";
a.schreeuw = function() {
  alert(this);
}
a.schreeuw(); //Spuugt "string1" uit in popup.
b.schreeuw(); //geeft error "b.schreeuw is undefined".


Door Tweakers user Sebazzz, maandag 21 juni 2010 21:01

Gamebuster schreef op maandag 21 juni 2010 @ 19:53:
[...]
C# is gewoon een java kloon met wat fancy uitbreidingen en volgens mij ook wat sneller.
C# is behoorlijk wat verder ge-evolueert dan een Java kloon. Het ontwikkeld zich sneller dan de meeste talen en ik vind het persoonlijk fijn werken omdat je veel dingen korter en duidelijker kan opschrijven dan Java. Maar dit is een discussie die ik liever niet op een Tweakblog start, want zonder gemod loopt het al snel in een welles/nietes spelletje uit. Dus ik zie je topic op GoT graag tegemoet :)
Gamebuster schreef op maandag 21 juni 2010 @ 18:43:
[...]

Iets als dit lijkt me logischer:

C#:
1
}

Die syntax is niet raar want het is gewoon een statische methode in een statische class. Je kan hem ook direct aanroepen, dus zo bijvoorbeeld (regel 1):

C#:
1
2
Console.WriteLine(Extensions.CountElements(new[]{1,2,3,3,4}, 3));
Console.WriteLine(new[]{1,2,3,3,4}.CountElements(3));


Door Tweakers user guanche, maandag 21 juni 2010 23:18

Een korte noot over de programmeertaal vs programmeertaal; We weten dat alles op alles geÔnspireerd is en Java de eerste was op veel fronten, maar ook zijn quirks had/heeft. Ontopic blijvend kunnen we alleen zijn als we javascript behandelen, omdat het de enige clientside programmeertaal in de browser is.

Ik bedoel niet dat de discussie niet interessant is, maar blijft een beetje appels en peren.

Daarop volgend zat ik al op de namespaces opmerking te wachten. Als je het heeel netjes wilt doen, met het oog op uitgebreide multi-developer applicaties dan zijn namespaces wel nodig.

Door Tweakers user himlims_, dinsdag 22 juni 2010 10:02

Verbinding met server mislukt

Door Tweakers user Icelus, dinsdag 22 juni 2010 10:48

In Objective-C kan dit d.m.v. ‘categories’.

Door Leon, dinsdag 22 juni 2010 10:53

Overgens zijn extensions gevaarlijk, want als Microsoft de functie implementeerd in zijn object, dan krijg je onverwachts resultaat.

Door Tweakers user AW_Bos, dinsdag 22 juni 2010 14:49

Ik ben geen kenner in classes, maar wat als je een prefix er aanhangt, Leon ;)

Door Tweakers user HMS, dinsdag 22 juni 2010 16:21

Je bedoelt iets als het nieuwe dynamic in C# 4.0? ;)

http://msdn.microsoft.com/en-us/library/dd264736.aspx

Reageren is niet meer mogelijk