Håll den globala namnrymden ren

Mina <pre>-taggar spiller över lite, så jag ska lösa det på något awesome sätt. Under tiden fungerar piljäveln som ligger uppe till höger för att förstora utrymmet :P

JavaScript har inte, som alla andra vanliga programmeringsspråk, block-level-scope och det är inte alltid tydligt på vad this pekar på. Istället använder sig JavaScript av scope på funktionsnivå, som kan förvirra när man börjar utveckla. För att koka ner det så långt jag kan:

function hello(){
    var foo = "bar";
}
hello();
alert(foo); //undefined

Eftersom att foo deklareras inne i funktionen hello() så har inte scopet utanför funktionen möjlighet att se foo. Det är alltså skillnad på lokalt scope och globalt scope (window-objektet).
När man utvecklar plugins för jQuery kan det ibland vara värt att skapa variabler utanför pluginets scope, men ändå dölja det från det globala scopet, för att undvika konflikter, överskrivna variabler och ett onödigt stort window-namespace.
Det enklaste sättet att göra det på är att lägga hela sitt plugin, med de variabler man behöver, i en anonym självanropande funktion.

(function($, window) { //http://antaru.org/self-invoking-functions-i-javascript
    //jQuery-plugins

    var foo = "bar"; //Variabel som kan kommas åt av alla plugins i scopet

    //Plugin utan closure
    $.fn.superPlugin = function() {
        //Pluginfunktionalitet
    }; 
    
    (function(){
        var hurr = "durr"; //Variabel som enbart existerar i det lokala scopet
        console.log(foo); //Skriver ut "bar"

        //Plugin med closure
        $.fn.closurePlugin = function() {
            //Pluginfunktionalitet
        };
    })();

    console.log(hurr); //undefined    

})(jQuery, this);

Man skulle kunna göra separata ”jQuery”-closures för varje plugin, men jag gillar att ha dem samlade och sedan var för sig, om det skulle krävas, ha ett eget closure; sin egna lilla värld.
Att definiera funktioner och globala variabler i JavaScript är oftast ingen bra idé.

Tips till alla Firebug-användare

Kör det här någon gång i början av era scripts:

window.log = function() {
    log.history = log.history || [];
    log.history.push(arguments);
    if (this.console) {
        console.log(Array.prototype.slice.call(arguments));
    }
};

De som har utvecklat för Firefox och använt Firebugs härliga console.log-funktion, sen testat det i någon annan webbläsare borde känna till problemet när funktionen anropas. Det går sönder. funktionen ovan löser det; plus, om den skapas den direkt kan man anropa log-metoden precis när som helst, och det går inte sönder, även om man råkar släppa koden skarpt.
Scriptet hittade jag på Paul Irish hemsida.
Edit: Testade lite mer, och att kunna anropa log.history i firebug är faktiskt riktigt sweet.

Associativa arrays är awesome

I JavaScript är allting objekt; strängar är objekt, siffror är objekt, till och med funktioner är objekt. Det härligaste objektet som finns är dock associativa arrayer, eller arrayer med en angiven nyckel istället för bara ett heltalsindex. Den enklaste formen av ett sånt här array är ett objekt med nycklar och värden tillsatta till den nyckeln. (Key, Value-pair för de som vill ha den tekniska termen)

var oh= { hai: "lol" };

Här skapas ett nytt objekt oh som innehåller en nyckel hai som har värdet ”lol”. För att senare komma åt värdet med nyckeln hai finns det en del sätt:

oh.hai; //fungerar
oh["hai"] //fungerar
oh[0] //fungerar inte

Det andra sättet att hitta värdet kan vara bra om nyckeln innehåller punkter, mellanslag eller andra konstiga tecken som skulle förstöra scriptet.

Syntaxen är väldigt enkel, skapa en variabel, indikera att det är ett objekt med måsvingar ({}), sen ange värdet på nycklar i objektet med kolon istället för likamedtecken. Det är även möjligt att lagra objekt i objekt, och funktioner i nycklar, vilket gör det hela än mer awesome.
Större objekt:

var oh = {
    hai: "lol",
    foo: "bar",
    sayHi: function(){
        alert("Hi");
    },
    hello: {
        world : "Hello World"
    }
};

Med det här objektet kan man säga hej till världen genom oh.hello.world, eller bara säga hej genom oh.sayHi().

jQuery tar tillvara på associativa arrayer på väldigt många ställen, som exempelvis css()-funktionen, eller bind(), vilket gör det mycket lättare att manipulera utseendet och uppförandet av DOM-element.
Kod för att knyta multipla events till ett element:

$("#foo").bind({
    "mouseenter": function(){
        //Funktionalitet för hover in
    },
    "mouseleave": function(){
        //Funktionalitet för hover ut
    },
    "click": function(){
        //Funktionalitet för musklick
    }
});

Associativa arrays är awesome.

Härlig villkorssyntax i JavaScript

På grund av JavaScripts flexibla natur så kan man få till riktigt snygga villkorssatser när man exempelvis hanterar variabler.

Säg till exempel att man vill sätta ett värde på en variabel beroende på om något existerar; och om det inte existerar sätta ett standardvärde på variabeln. Det skulle gå att lösa såhär (Använder jQuery också, det gör det lättare att läsa och förstå imo):

var input = $("#foo");

if (input.val() != "" && input.val().length > 0) {
    var anObject = input.val();
}
else {
    var anObject = "DefaultValue";
}

Inte så jättesnyggt. Inte så rätt heller, men det illustrerar min poäng. Det finns säkert någon som skulle ha skrivit det såhär. Jag personligen skulle ha skrivit det såhär:

var anObject = $("#foo").val() || "DefaultValue";

Antagligen hade jag cachat jQuery-objektet i en variabel, om det var del av en större funktion, men återigen så lyser min poäng igenom. Det magiska ligger i ”||” som helt enkelt säger ”Sätt värdet på anObject till det på min högra sida om det på min vänstra sida är false-ish, annars ta det på min vänstra sida”.

Med false-ish innebär det i det här fallet att om inputfältet är tomt kommer anObject tilldelas DefaultValue. För att ta hänsyn till om man försöker skicka in en tomsträng skulle man kunna anropa trim() på jQuery-objektet.

Jag vet inte riktigt vad den här tekniken heter, men jag gillar den verkligen.

Man skulle teoretiskt sett kunna göra såhär också:

var x = a || b || c || d || e;

Och x skulle få värdet av det första som kan omvandlas till ”true”, det vill säga det första värdet som inte är null, false, undefined, tomsträng eller siffran noll.

Vill man gå ett steg längre skulle man säkert kunna använda sig av funktioner med egen logik som returnerar false-ish beroende på yttre faktorer. Tänk exempelvis om a i föregående exempel var ett funktions-objekt som kollade om användaren kör Firefox. Det skulle vara häftigt. Om funktionen ens skulle köras… Kanske kunde man lägga in en anonym funktion där…
Känns som att jag måste experimentera lite mer.
Jag gillar JavaScript <3

Self invoking functions i JavaScript

Upptäckte en sexig lösning när jag fick i uppgift att blåsa upp en iframe till 100% av en sidas höjd (100% – en topbanners höjd). Själva koden för att göra det är inget speciellt, men det vackra i det hela är att använda en självanropande funktion för att skapa funktionen som ska användas för att ändra storlek på iframen.

var theFrame = $("#dinFrame");
(Resize = function() {
    theFrame.height($(window).height() - 100);
})();
$(window).resize(Resize);

Vad det här gör rent tekniskt är att köra en anonym funktion, som definierar en ny funktion och samtidigt kör den funktionen. Den cachar även DOM-elementet och lyssnar på resize-event, men det är inte det sexiga.

Samma kod skulle kunna skrivas:

var theFrame = $("#dinFrame");
var Resize = function() {
    theFrame.height($(window).height() - 100);
};
$(window).resize(Resize);
Resize();

Men enligt mig är det inte sexigt alls.

Samma princip används när man skriver jQuery-plugin och vill försäkra sig om att $-funktionen faktiskt pekar på jQuery och inget annat:

(function($) {

    //SAFE CLOSURE'D

})(jQuery);

För att vara extra säker kan man även lägga till window och undefined som parametrar, så ingen mixtrar med dem och förstör dina scripts. (Måste såklart köras när this pekar på det globala windowobjektet)

(function($, window, undefined) {

    //SAFER CLOSURE'D

})(jQuery, this);

Mest för att försäkra sig om att window är window och undefined verkligen är undefined.