1) Unikać tworzenia zmiennych bez słowa kluczowego var.
Każde wywołanie typu:zmienna = "tekst";
function Nic() { zmienna = "tekst"; }powoduje utworzenie zmiennej globalnej. Zmienna ta staje się właściwością obiektu globalnego. W przeglądarkach internetowych jest to obiekt window. Prowadzi to do zaśmiecania obiektu globalnego przypadkowymi właściwościami, w rezultacie czego może dojść do nadpisywania wartości i nieoczekiwanych zachowań w działaniu aplikacji.
Nie należy też korzystać z konstrukcji typu:
var x = y = 0;Efektem takiego zapisu jest stworzenie zmiennej globalnej y.
2) Deklaracja zmiennych na początku
Najbezpieczniej jest zadeklarować zmienne lokalne na początku funkcji. Jest to czytelne i nie doprowadza do niepotrzebnych pomyłek, np:var x = 1; function Nic() { alert(x);//tu będzie wartość undefined !!! var x = 2; alert(x); }
3) Optymalizacja w pętlach for
Przy poruszaniu się po elementach tablicy z wykorzystaniem pętli for, optymalnie jest wyliczyć max liczbę elementów RAZ, czyli:for( var i = 0, tab_max = tablica.length; i < tab_max; i++) { }
4) Uwaga na pętle for-in
Przy iteracji po właściwościach obiektu najbezpieczniej jest dodać warunek odfiltrowujący właściwości dodane przez prototypy (jeśli chcemy iterować tylko te własne).var person = { name: "jan", age : 21 }; for( var p in person) { if (person.hasOwnProperty(p)) { alert(p + " " + person[p]); } }
5) Niepotrzebne funkcje
Często spotykaną praktyką jest tworzenie pomocniczych funkcji wewnątrz funkcji konstruujących obiekty. Np:var Car = function(mark, model) { this.mark = mark; this.model = model; this.carName = function () { return this.mark+ " " + this.model; } } var car1 = new Car('ford', 'focus'); var car2 = new Car('ford', 'mondeo');Powoduje to tworzenie dodatkowej funkcji dla każdego obiektu Car. W tym jednak przypadku (jak i w wielu innych podobnych) można ją zastąpić funkcją dodaną przez prototyp.
var Car = function(mark, model) { this.mark = mark; this.model = model; } Car.prototype.carName = function() { return this.mark+ " " + this.model; }; var car1 = new Car('ford', 'focus'); var car2 = new Car('ford', 'mondeo');
6) Przestrzeń nazw
Złożoność kodu JS rośnie bardzo szybko, a wraz z nim pojawia się potrzeba podzielenia go na moduły. Bardzo często spotykaną praktyką jest tworzenie "przestrzeni nazw". Przeważnie robi się to tak:
var Company = {}; Company.Module1 = {}; ....
Jednak kiedy w kilku plikach będziemy mieć taką konstrukcję to drugi będzie nadpisywać utworznone wcześniej zmienne w pierwszym pliku. Można to łatwo obejść posługując się operatorem OR:
var Company = Company || {}; Company.Module1 = Company.Module1 || {}; ....
Dzięki temu jeśli zmienna np. Company nie będzie dostępna operator || zwróci pusty obiekt (zainicjujemy więc tylko wtedy gdy "Company" nie będzie istnieć).
Można pójść o krok dalej i stworzyć pomocniczą metodę, która będzie tworzyć przestrzenie nazw, co jest najlepszym rozwiązaniem:
var Company = Company || {}; Company.namespace = function(namespace_str) { var segments = namespace_str.split('.'); var part = Company; // nazwa firmy jest bazową przestrzenią która znajduje się już w zmiennej "part" if (segments[0] === 'Company') { segments = segments.slice(1); } // tworzenie kolejnych segmentów przestrzeni nazw o ile nie istnieją for(var i = 0, max = segments.length; i < max; i += 1) { if (typeof(part[segments[i]]) === 'undefined') { part[segments[i]] = {}; } part = part[segments[i]]; } return part; }; // przykłady użycia Company.namespace('Company.Module1'); Company.namespace('Module2'); Company.namespace('Company.Module2.Submodule1');
7) Moduły
Bardzo przydatny w praktyce jest wzorzec modułu. W połączeniu z przestrzeniami nazw zapewnia nam podział kodu na logiczne moduły oraz hermetyzację. Konstrukcja wykorzystuje funkcję natychmiastową, która od razu inicjuje nasz moduł.
Company.Module1.Submodule1 = (function(){ // odwolania do innych modulow var mod2 = Company.Module2.Obj; // zmienne prywatne var x,y,z; // metody prywatne var func1 = function(param1) { x = param1; }; // zwracany obiekt (metody publiczne) return { func1 : func1, func2 : function(param1){ return mod2.call(param1) === 'test'; } } })();
8) Tworzenie obiektów
Eleganckim sposobem jest stworzenie metody fabrykującej obiekty danego typu. Np:
Company.Factory = new function() { function Car(name) { var cName = name; this.getName = function () { return cName; } } this.makeCar = function(name) { return new Car(name); } } // przyklad uzycia var car = Company.Factory.makeCar('ford');