Pętle for

end3r #20

Zapewne wiele razy w swoim kodzie korzystałeś z pętli for, zazwyczaj wygląda ona tak:

for (var i = 0; i < array.length; i++) {
    // array[i]
}

Prawdopodobnie jest to najczęściej stosowana konstrukcja, ale warto pamiętać o tym, iż nie jedyna. Prede wszystkim zwróćmy uwagę na array.length, do którego odwołujemy się przy kolejnych iteracjach odczytując za każdym razem tę samą wartość. Skoro tak, to możemy lekko zmodyfikować naszą pętlę zapisując wielkość tablicy w zmiennej:

for (var i = 0, len = array.length; i < len; i++) {
    // array[i]
}

Jeśli potrzebujemy natomiast przeiterować tablicę od końca zamiast od początku, to możemy skorzystać z poniższej konstrukcji:

for (var i = array.length-1; i >= 0; i--) {
    // array[i]
}

Oczywiście są to tylko najprostsze przykłady - możemy dowolnie modyfikować pętle for dostosowując je do naszych potrzeb.

Poprawne dodawanie zdarzeń

varjs #19

Poprawną metodą dodawania zdarzeń zgodnie ze standardami jest funkcja addEventListener. Przykładowe użycie wygląda tak:

var element = document.getElementById("some");
element.addEventListener("click", function() {
    console.log("foobar");
}, false);

Dziedziczenie z Object.create

varjs #18

Dziedziczenie w JavaScript można uzyskać na kilka sposobów. Jedną z dostępnych metod jest użycie Object.create (nowa konstrukcja z ECMAScript 5), gdzie pierwszy argument to obiekt, na podstawie którego ma zostać utworzony nowy. Zaawansowani programiści z łatwością dostrzegą, że pierwszym argumentem funkcji Object.create jest tak naprawdę prototyp, który służy jako baza do utworzenia nowego obiektu.

var human = { 
    name: "", 
    gender: null, 
    getName: function() { return this.name; } 
}; 

var girl = Object.create(human); 
girl.gender = "female"; 
girl.name = "Veronica"; 
console.log(girl.getName()); // Veronica

Jak usunąć element z tablicy

varjs #17

W celu usunięcia elementu o danym indeksie w tablicy, używamy funkcji splice:

var arr = [1, 2, 3];
arr.splice(0, 1);
console.log(arr); // [2, 3]

Pierwszy argument oznacza numer indeksu, od którego chcemy zacząć operację usuwania, a drugi liczbę elementów, które chcemy usunąć. W powyższym przykładzie chcemy pozbyć się jednego elementu, poczynając od indeksu 0.

Warto dodać, że funkcja ta zwraca tablicę elementów, które usunęliśmy:

var arr = [3, 4, 6];
console.log(arr.splice(2, 1)); // [6]

Function.length vs arguments.length

lukas #16

Obiekt Function w JavaScript posiada własność length, która zwraca ilość oczekiwanych przez daną funkcję argumentów. Aby dowiedzieć się, ile argumentów zostało funkcji przekazanych, możemy użyć lokalnej dla danej funkcji zmiennej arguments:

var a = function(one, two, three, four) {
    return arguments.length;
};

a.length; // 4
a(1,2,3); // 3

Unix Timestamp

lukas #15

Aby uzyskać czas unixowy w milisekundach, mierzony od 1 stycznia 1970 00:00:00 UTC, używamy:

new Date().getTime();

lub gdy nie zależy nam na starszych przeglądarkach:

Date.now();

Istnieje również skrócona, jednak mniej czytelna wersja:

+new Date;

Łączenie wartości tablic

lukas #14

Gdy chcemy dodać zawartość tablicy do końca drugiej, jest na to dość prosty sposób:

var a = ["raz", "dwa"];
var b = ["trzy", "cztery"];

Array.prototype.push.apply(a,b);

Wartości z tablicy b zostaną dodane do a:

console.log(a); // ["raz", "dwa", "trzy", "cztery"]

Drugim sposobem, jeżeli nie chcemy modyfikować oryginalnych tablic lub mamy do połączenia więcej niż dwie tablice, jest concat:

var c = ["pięć", "sześć"];
var d = a.concat(b, c);
console.log(d); // ["raz", "dwa", "trzy", "cztery", "pięć", "sześć"]

Wartość NaN

varjs #13

Często w wyniku operacji arytmetycznych otrzymujemy wynik o wartości NaN. Skrót pochodzi od wyrażenia not a number. Wartość tę możemy dostać na przykład poprzez podzielenie liczby przez stringa:

var i = 10;
var result = i / "foobar";
console.log(result); // NaN

Jak więc sprawdzić, czy rezultalt to NaN, by uniknąć dalszych błędów w aplikacji? Można użyć funkcji isNaN:

isNaN(result); // true

Jest to problematyczne, o ile weźmiemy pod uwagę, że sprawdzana wartość będzie czymś innym niż NaN:

isNaN({}); // true

Można temu zaradzić definiując własną funkcję do sprawdzenia, czy zmienna to NaN. Otóż warto zauważyć, że NaN jako jedyna wartość nie daje prawdy przy porównaniu do samej siebie:

result === result; // false

Na tej podstawie konstruujemy własną funkcję sprawdzającą, alternatywną do isNaN:

var customIsNaN = function(i) {
	return i !== i;
}

Skrypty w <head> lub w <body> - różnice

varjs #12

Załóżmy, że dołączasz skrypty JavaScript w tradycyjny sposób, poprzez umieszczenie elementu <script> w <head>:

<head>
    <script src="main.js"></script>

Ta metoda ma jednak wady - opóźnia ona ładowanie stron w starszych przeglądarkach - browser czeka, dopóki załaduje się plik JavaScript, dopiero potem zaczyna renderować wszystko, co występuje po tagu <script>.

Jakie są alternatywy? Można użyć parametru async z HTML5, który pominie kolejność ładowania skryptów i załaduje je asynchronicznie:

<head>
    <script src="main.js" async="true"></script>

Warto też wiedzieć, że aby uniknąć oczekiwania i nie polegać na parametrze async, można również dołączyć swoje skrypty dopiero w <body> na samym końcu dokumentu HTML. Mamy wtedy pewność, że DOM jest załadowany i gotowy do użycia (a więc zapomnieć można o zdarzeniu DOMContentLoaded).

Więcej w temacie na MDN.

Losowa liczba z podanego zakresu

vokiel #11

Czasami musimy wygenerować losową liczbę całkowitą z podanego zakresu. Niestety dostępna funkcja Math.random(); generuje liczby z przedziału 0-1. Własna implementacja funkcji rand może wyglądać tak:


function rand( min, max ){
    min = parseInt( min, 10 );
    max = parseInt( max, 10 );

    if ( min > max ){
        var tmp = min;
        min = max;
        max = tmp;
    }

    return Math.floor( Math.random() * ( max - min + 1 ) + min );
}

Kolejność parametrów w zasadzie nie ma znaczenia.

Zaprzyjaźnij się z operatorem porównania '==='

lydiawil #10

W innych językach programowania przeważnie porównujemy ze sobą elementy za pomocą podwójnego znaku równości '=='. Jednak ten operator nie uwzględnia typu porównywanych obiektów (JS próbuje przekształcić obiekty na wspólny typ), z czego może wyniknąć wiele nieoczekiwanych błedów w kodzie.

0 == "0" // => true
![] == [] // => true
undefined == null // => true

Dobrą praktyką jest używanie potrójnego znaku równości, który uwzględnia także typ porównywanych elementów. Pozwala to na wyeliminowanie z kodu wielu niejasności.

0 === "0" // => false
![] === [] // => false
undefined === null // => false

Tworzenie wewnętrznego scope

varjs #9

Dzięki automatycznemu wywoływaniu anonimowych funkcji możesz łatwo wprowadzić wewnętrzny scope zmiennych, dzięki czemu będą one dostępne tylko w tej funkcji.

(function() {
    var privateVar = 1;

})();
console.log(privateVar); // undefined

Zapomnij o jQuery, jest querySelector

varjs #8

Największą zaletą frameworka jQuery był łatwy sposób pobierania elementów drzewa DOM według selektorów CSS. Na przykład:

var news = $("div.news");

Ładowanie całego jQuery tylko dla takiej funkcjonalności jest często przerostem formy nad treścią. Z łatwością możesz skorzystać z document.querySelectorAll:

var news = document.querySelectorAll("div.news"); // wszystkie elementy div.news
var news = document.querySelector("div.news"); // tylko pierwszy element

Sprawdź wsparcie dla querySelector wśród współczesnych przeglądarek na canIUse.com.

Jak sprawdzić, czy zmienna jest tablicą?

varjs #7

Sprawdzenie, czy zmienna jest tablicą było w JavaScript nie do końca prostym zadaniem. Niestety, typeof nie daje nam jednoznacznej odpowiedzi, ponieważ zwraca to samo dla tablic i obiektów:

var arr = [1, 2, 3];
var obj = {};
typeof arr; // "object"
typeof obj; // "object"

W ECMAScript 3 sprawdzaliśmy, czy zmienna jest tablicą następująco:

var arr = [1, 2, 3];
if (Object.prototype.toString.call(arr) === "[object Array]") {}

Na szczęście najnowsza wersja ECMAScript 5 wprowadza funkcję Array.isArray:

var arr = [1, 2, 3];
if (Array.isArray(arr)) {}

Jak uzyskać pustą tablicę bez tworzenia nowej?

varjs #6

Załóżmy, że dysponujesz gotową tablicą i chcesz usunąć jej wszystkie elementy. Z reguły robi się to tak:

var arr = [1, 2, 3];
// ...
arr = [];

Jest to dobry pomysł, ale jeśli zależy nam na optymalizacji nawet tak trywialnego przypadku (sprawdza się to w kontekście developmentu gier, gdzie najlepiej zużywać jak najmniej pamięci) możemy skorzystać z właściwości length:

var arr = [1, 2, 3];
arr.length = 0;
console.log(arr); // []

W ten sposób korzystamy zawsze z tej samej struktury danych i przy okazji unikamy tworzenia nowej tablicy.

Największy i najmniejszy element w tablicy

varjs #5

Przyjmijmy, że mamy do czynienia z następującą tablicą:

var arr = [1, 2, 3];

Jak znaleźć jej największą wartość? Zapewne do głowy przychodzi Ci pętla i dodatkowa zmienna przechowująca aktualnie największy element. W JavaScript można to zrobić kompleksowo, przy pomocy Math.max:

var arr = [1, 2, 3];
Math.max.apply(null, arr); // 3

Podobnie da się zrobić z najmniejszą wartością, wykorzystując Math.min:

var arr = [1, 2, 3];
Math.min.apply(null, arr); // 1

parseInt("08")

varjs #4

Pamiętaj, że parseInt traktuje stringa jako liczbę w systemie ósemkowym, jeśli na jego początku pojawi się "0". Dobrą praktyką jest umieszczanie zawsze "10" jako drugiego argumentu, który mówi, że powinniśmy sparsować liczbę w systemie dziesiętnym.

parseInt("08"); // 0
parseInt("08", 10); // 8

"for in" nie dla tablic

varjs #3

Pamiętaj, że pętle for in stworzone są tylko i wyłącznie do iteracji po obiektach:

var obj = { key : 1 };
for (var i in obj) {
    console.log(i); // "key"
}

For in używany z tablicami będzie iterował również przez własności .prototype tablicy, co jest efektem niepożądanym.

Tworzenie tablic i obiektów

varjs #2

Zapomnij o tworzeniu tablic i obiektów w, wydawałoby się, klasyczny sposób:

var arr = new Array();
var obj = new Object();

W JavaScript robi się to następująco:

var arr = [];
var obj = {};

JavaScript umożliwia tworzenie tych struktur natywnie, nie musimy dodatkowo wołać ich konstruktora. Poza tym można je nadpisać, co może przysporzyć dużo problemów:

var Object = null;

JSLint Twoim przyjacielem

varjs #1

Bardzo popularnym rozwiązaniem pozwalającym sprawdzać poprawność kodu pod względem dobrych praktyk jest JSLint autorstwa Douglasa Crockforda.

Alternatywnym projektem dla JSLint jest... JSHint.

Oba projekty można użyć w systemach continuous integration, które mogą np. sprawdzać po każdym commicie, czy kod jest poprawny.