ruin

Złe strony JavaScriptu – new oraz this

Cześć!

Słowem wstępu…

Obiecałem wam ostatnio, że dodam wpis w ciągu dwóch tygodni. Jednak pisząc ostatniego posta zapomniałem, że za chwilę mam ślub i podróż poślubną…

Ah ten czas szybko leci! Wydarzenia te wydłużyły proces produkcji tego artykułu. Za co z góry przepraszam!

Co dzisiaj?

Rozważymy dwa problematyczne elementy JavaScriptu. Operator new oraz słowo kluczowe this.

Brak operatora new

Konstruktor to zwykła funkcja. Co się stanie gdy pominiesz operator new?

function Example() {
  return this
}

console.log(Example() instanceof Example) // false
console.log(Example() === window) // true

Operator new ustawia nową instancję obiektu jako wartość this. Lecz gdy go nie użyjemy, konstruktor nie ma kontekstu, a więc this będzie obiektem globanym – w przeglądarce window. Jedyną odmienną sytuacją jest tryb strict – w tym trybie this przyjmie wartość undefined.

Przypisanie metody obiektu do zmiennej

Metodę obiektu przypisujesz do zmiennej, następnie wywołujesz metodę poprzez zmienną. Czym będzie this?

var example = {
  test: function() {
    return this
  }
}

var test = example.test

console.log(test() === example) // false
console.log(test() === window) // true

Metoda obiektu po przypisaniu do zmiennej zachowuje się jak zwykła funkcja – brakuje jej kontekstu. Więc i tym razem this będzie obiektem globalnym / undefined.

Przekazanie metody obiektu

Przekazujesz metodę obiektu do funkcji która wywoła ową metodę. Co się stanie z this?

var example = {
  test: function() {
    return this
  }
}

run(example.test)

function run(callback) {
  console.log(callback() === example) // false
  console.log(callback() === window) // true
}

I tym razem metoda gubi kontekst więc zachowuje się jak zwykłą funkcja.

Co robić, jak żyć?

Operator new

Nie używaj go. Czy naprawdę tego potrzebujesz? JavaScript pozwala na tworzenie obiektów w locie. Przykładowe rozwiązanie:

function createExample() {
  var example = {}

  example.name = 'name'

  example.test = function() {
    console.log(example.name)
  }

  return example
}

Ok, a co jeśli potrzebujemy dziedziczenia? Również łatwo to osiągnąć:

function createParent() {
  var object = {}

  object.name = 'parent'
  object.sayHello = function() {
    console.log(object.name)
  }

  return parent
}

function createChild() {
  var object = createParent()
  var parentSayHello = object.sayHello

  object.name = 'child of a ' + object.name
  object.sayHello = function() {
    parentSayHello()
    alert(object.name)
  }

  return object
}

Najpierw deklarujemy funkcję która tworzy obiekt rodzica. Następnie kolejną funkcję która wywołuje pierwszą, uzupełnia zwrócony obiekt o potrzebne dane i go zwraca. Proste i skuteczne. A dodatkowo kuloodporne. Można je uruchamiać z operatorem new jak i bez niego.

Słowo kluczowe this

Również go nie używaj. Jeśli zastosujesz powyższe propozycje tworzenia obiektów, this będzie Ci kompletnie zbędne. Ja staram się go nie używać. Przekazujesz funkcję do obserwatora zdarzeń? Zamiast this lepiej użyj event.target. Tworzysz obiekty? Używaj notacji klamerkowej – {}. Kod będzie piękniejszy i prostszy. Dodatkowo nie będziesz musiał używać metod magicznych .call(), .bind() oraz .apply().

Podsumowanie

Mam nadzieję że przekonałem Cię do nie używania obu rzeczy. Sam Douglas Crockford je odradza. Kto jak kto, ale on zna się na JavaScript. Przejrzyj swój kod i zobacz ile rzeczy może być ładniejszych i prostszych bez tych dwóch rzeczy. Jeśli masz wątpliwości, uwagi, a może masz zupełnie odmienne zdanie – zostaw komentarz! Pozdrawiam Cię drogi czytelniku i życzę miłego dnia / wieczora / nocy 🙂

Damian.