Zakres zmiennych, hoisting – co warto wiedzieć?

Elevator

Koniec wakacji, czas brać się do roboty 🙂 W tym wpisie postaram się krótko i treściwie omówić zakres zmiennych i hoisting w JavaScript.

Zakres zmiennych

Zakres zmiennych w JavaScript, to temat nieco skomplikowany. Programista, który dopiero zaczyna swoją przygodę z JSem, może być w niemałym szoku próbując okiełznać tajniki sztuki.

for (var a = 0; a < 5; a++) {}
console.log(a); // 5

Na początek stwórzmy standardową pętlę for, w której deklarujemy zmienną a = 0. Poniżej odwołujemy się do tej zmiennej i jako rezultat dostajemy 5.

Wniosek: Deklaracja zmiennej poprzez słowo kluczowe var powoduje zalokowanie miejsca w pamięci i zachowanie stanu pomimo zakończenia pętli. Zmienna jest widoczna w kontekście funkcji.

Na ratunek let i const

W standardzie ECMAScript 2015 (ES6) wprowadzone zostały nowe słowa kluczowe let i const. Służą do tego samego co var, ale mają ograniczony zasięg.

let is the new var.

for (let a = 0; a < 5; a++) {}
console.log(a); // Uncaught ReferenceError: a is not defined

Jak widzimy w powyższym przykładzie, zamiana var na let daje wymierny skutek. Nie mamy dostępu do zmiennej poza blokiem for. O to nam chodziło… wykorzystujemy zmienną z kontekstu blokowego.

Jak się ma do tego const?

Deklaruje nazwaną stałą tylko do odczytu – MDN

Nie możemy ponownie przypisać wartości do consta:

const a = 7;
a = 5; // Uncaught TypeError: Assignment to constant variable.

Nie możemy też ponownie zadeklarować stałej:

const a = 7;
const a = 5; // Uncaught SyntaxError: Identifier 'a' has already been declared

JS ma jednak swoje wymagania, a const może sporadycznie piszących w tym języku wprowadzić w błąd.

const a = [];
console.log(a); // []
a.push(2);
console.log(a); // [2]
a.push({ a: 3 });
console.log(a); // [2, {a: 3}]

W JavaScript const NIE oznacza deklaracji stałej wartości, lecz deklarację stałej referencji. W przypadku typów prymitywnych const zachowuje się tak jak oczekujemy. Przy typach złożonych mamy możliwość podmiany zawartości.

Idealnie obrazuje to przykład powyżej. Tworzymy stałą a = [], następnie poprzez metodę push dodajemy pierwszy element tablicy, itd.

Hoisting

Temat hoistingu jest często poruszany, zarówno na branżowych spotkaniach jak i rozmowach kwalifikacyjnych. To jeden z feature’ów JSa, o którym wszyscy słyszeli lub wkrótce usłyszą.

Hoisting, spolszczona nazwa windowanie, to mechanizm pozwalający na przeniesienie deklaracji zmiennych oraz metod na początek funkcji.

a = 5;
var a;
console.log(a); // 5

i

simpleFunction(); // hoisting

function simpleFunction() {
  console.log('hoisting');
}

W przykładzie pierwszym do zmiennej a przypisujemy 5, następnie ją deklarujemy. Log w konsoli daje rezultat 5. Drugi przykład, to wywołanie metody przed deklaracją. Rezultat taki sam jak wcześniej. Hoisting zadziałał.

Przy deklaracji zmiennych za pomocą słowa kluczowego let, hoisting zachowuje się bardziej przewidywalnie.

a = 5;
let a; // ReferenceError: a is not defined

Strict mode

Strict mode (tryb ścisły) to jeden z feature’ów ES5. Wprowadza kilka zmian do domyślnej semantyki JavaScript:

  1. Pozwala wyeliminować ciche błędy (ang. silent errors).
  2. Pozwala wyeliminować błędy, które uniemożliwiają optymalizację JSa przez przeglądarki.
  3. Uniemożliwia stosowanie składni mogącej wystąpić w kolejnych odsłonach ECMAScript.

Temat został pobieżnie wywołany, przy okazji hoistingu, nie bez przyczyny. Strict mode nie zezwala na skorzystanie ze zmiennej, dopóki nie zostanie zadeklarowana.

Warto przeczytać:

Daj się poznać 2017 – podsumowanie

DSP 2017

Nastał ten dzień. Konkurs Daj się poznać 2017 został oficjalnie zakończony.

O konkursie

W tegorocznej edycji konkursu Daj się poznać, wystartowało 981 uczestników. Jednym ze śmiałków, byłem także ja. Niespełna tysiąc programistów, przez 3 miesiące, mierzyło się z własnymi słabościami. Efekt – oszałamiający – prawie 8000 postów!

Prawie TYSIĄC programistów, prawie TYSIĄC blogów! Do polskiej dev-blogosfery wskoczyło prawie 8000 postów– Maciej Aniserowicz

Do wymarzonego finału zakwalifikowało się 183 najwytrwalszych. To z nich wybierzemy niebawem laureatów tegorocznej edycji.

Gala finałowa Daj się poznać

Podsumowanie konkursu zostało zaanonsowane na 17 czerwca. Gala Finałowa odbędzie się w biurze Microsoft.

17 czerwca spotkamy się w ok 150 osób na Gali Finałowej w biurze Microsoft na Alejach Jerozolimskich. Tam calutki dzień zapełniony będzie ciekawymi wystąpieniami, emocjami i rozmowami. – Maciej Aniserowicz

Ja w konkursie

Głównym celem, który dodawał mi sił, podczas trwania konkursu, była… NAUKA nowych technologii. Tak, to właśnie dlatego przystąpiłem do konkursu. Tak, to właśnie dlatego, sporo razy budziłem się niewyspany. Tak, to właśnie dlatego byłem czasem zdenerwowany i ponury. Teraz, po tych niespełna trzech miesiącach, zdaję sobie sprawę z tego, że pisanie kodu i przelewanie swoich doświadczeń na bloga jest najzwyczajniej w świecie męczące. Zdobyłem jednak dzięki temu, tak cenne doświadczenie, że śmiało mogę polecić start każdemu w kolejnej (daj Boże) edycji Daj się poznać.

Angular, Go i Mongo

Kolejnym celem, było wykorzystanie poznanego wcześniej języka TypeScript do napisania aplikacji front-endowej, w oparciu o framework Angular. Udało mi się postawić szkielet aplikacji, obsłużyć kilka końcówek i przewertować kilka tomów dokumentacji 🙂 Generalnie, jestem bardzo zadowolony. Wcześniej byłem nieco sceptycznie nastawiony, ale teraz dostrzegam potencjał jaki drzemie w odświeżonym frameworku Google’a.

Go golang sprawdził się idealnie do backendu mojej aplikacji. Wystawienie tych kilku endpointów, to była najprawdziwsza przyjemność. Prosta składnia, przejrzysta dokumentacja i tutoriale oraz ogrom bibliotek sprawił, że praca postępowała szybko i bezboleśnie. Ogromne brawa należą się także community zgromadzonemu wokół języka. Robią kawał dobrej i solidnej roboty.

W pakiecie do Angulara i Go była jeszcze MongoDB. Nierelacyjna baza danych była uzupełnieniem mojej pracy full-stack developera. Podczas trwania projektu musiałem się co nieco o niej dowiedzieć, ale była to bardzo wybiórcza wiedza. Z tyłu głowy jednak zostawiam Mongo i obiecuję wrócić do nauki wkrótce.

Chatbot

Prace nad projektem Shopping Manager, zostały w pewnym momencie zepchnięte na dalszy plan. Powodem był inny projekt, który musiałem wtenczas zrealizować. Temat dotyczył chatbotów. Wydał mi się na tyle interesujący, a pierwszy post spotkał się z tak zadziwiająco dobrym przyjęciem, że postanowiłem pójść za ciosem i stworzyć miniserię poświęconą tworzeniu chatbotów. Temat niezwykle ciekawy i bardzo modny. Na pewno będzie kontynuacja, bo pomysłów w tej dziedzinie mam niezwykle dużo.

Na koniec

Kończąc moją wypowiedź, chciałbym podziękować wszystkim, którzy odwiedzali mojego bloga. Dostałem sporo feedbacku odnośnie moich postów, większość na Slack Devs PL oraz poprzez formularz kontaktowy. Pojawiły się zarówno miłe słowa, jak i konstruktywna krytyka. Za wszystkie komentarze, wiadomości i maile, serdeczne dzięki!

Chatbot, Wit.ai – tworzenie chatbota – Speech API

Artificial Intelligence

Rozpoznawanie głosu to temat trudny, nawet dla największych wyjadaczy. Z pomocą przychodzi jednak Wit.ai, wraz ze swoim Speech API. Dzięki dedykowanej aplikacji oraz wykorzystaniu WebRTCWebSockets możemy w prosty sposób przekonwertować mowę na tekst oraz skomunikować się z naszym chatbotem.

Trochę teorii

Wit.ai Speech API powstało w lutym 2014 roku jako rozwinięcie projektu Wit.ai. Zasada działania jest prosta, przesyłamy na backend (w tym wypadku na zewnętrzny serwer Wit.ai) plik audio. Dźwięk jest przetwarzany i konwertowany. Dostajemy w zwrotce JSON z intencją oraz wartościami, które zostaną wychwycone.

speech2json

Wit.ai Speech API łączy w sobie różne techniki przetwarzania języka naturalnego oraz silniki rozpoznawania mowy. Potrafi odseparować szumy z otoczenia, dostosować poziom głośności i wydobyć właściwe dźwięki.

Microphone

W ramach tego wpisu zapoznamy się z nakładką wit-ai/microphone. Biblioteka jest dewelopowana przez zespół zajmujący się  Wit.ai. Została napisana w CoffeeScript, wykorzystuje WebRTC i WebSockets, dzięki czemu nie musimy zapisywać plików audio lokalnie. Cały kod jest jawny, a jego rdzeń możemy znaleźć tutaj.

Implementacja Speech API

Po wpięciu biblioteki obsługującej mikrofon i komunikującej się z Wit.ai API, pozostało obsłużyć mikrofon na stronie internetowej.

Zaczynamy od stworzenia instancji Microphone:

const microphone = new Wit.Microphone(document.getElementById('microphone'));

Jak widać, odwołujemy się do elementu posiadającego id microphone. W ten sam sposób dodajemy info oraz error:

const info = message => {
  document.getElementById('info').innerHTML = message;
};
const error = message => {
  document.getElementById('error').innerHTML = message;
};

Teraz, korzystając z dokumentacji, stwórzmy kilka metod obsługujących naszą aplikację. Poinformujmy użytkownika, że można rozpocząć nagrywanie:

microphone.onready = () => {
  info('Mikrofon gotowy do nagrywania');
}

Po starcie, zmiana statusu z informacją:

microphone.onaudiostart = () => {
  info('Nagrywanie rozpoczęte');
};

Oraz po zakończeniu nagrywania:

microphone.onaudioend = () => {
  info('Nagrywanie zakończone, trwa konwertowanie');
};

Pamiętajmy, że w razie niepowodzenia, warto o tym poinformować użytkownika. Wykorzystujemy więc metodę onerror:

microphone.onerror = errorMessage => {
  error('Błąd: ' + errorMessage);
};

W momencie nawiązywania oraz zamykania połączenia mamy dwa dodatkowe callbacki: onconnectingondisconnected. Wykorzystujemy je do stworzenia dodatkowych statusów informujących:

microphone.onconnecting = () => {
  info('Trwa weryfikowanie mikrofonu');
};
microphone.ondisconnected = () => {
  info('Mikrofon nie jest podłączony');
};

Została nam jeszcze obsługa onresult. Analogicznie jak w wersji node’owej, tutaj też po zidentyfikowaniu osoby, spróbujemy wyszukać o niej informacji na wikipedii:

microphone.onresult = (intent, entities) => {
  if (entities.fullName === undefined) {
    document.getElementById('result').innerHTML = 'Nie zrozumiałem, spróbuj jeszcze raz!';
  } else {
    let fullName = entities.fullName.value;
    document.getElementById('result').innerHTML = fullName + '? Szukam na wikipedii...';
    window.open('https://pl.wikipedia.org/wiki/' + fullName.replace(' ', '_'));
  }
};

W metodzie connect przekazujemy token, który możemy wygenerować w ustawieniach aplikacji.

Speech API token

Podsumowanie

Po implementacji i deployu na Heroku, możemy sprawdzić jak się zachowuje aplikacja. Przykładowy screen z testu zamieszczam poniżej. Cały kod dostępny jest na moim githubie, zachęcam też do przetestowania aplikacji samodzielnie.

Spy chatbot - Speech API

Przydatne linki