Dodatek

Dziedziczenie prototypowe

Z wyjątkiem null i undefined każdy podstawowy typ danych ma parametr prototype, odpowiadający mu kod obiektu, który udostępnia metody pracy z wartościami. Gdy dla obiektu podstawowego zostanie wywołana metoda lub wyszukiwanie właściwości, JavaScript umieszcza element „za kulisami” i wywołuje metodę lub uruchamia wyszukiwanie właściwości obiektu otoki.

Na przykład literał łańcuchowy nie ma własnych metod, ale można wywołać funkcję Metoda .toUpperCase() dzięki odpowiedniemu obiektowi String kod:

"this is a string literal".toUpperCase();
> THIS IS A STRING LITERAL

Jest to tzw. dziedziczenie prototypowe, czyli właściwości i metody dziedziczenia. z odpowiedniego konstruktora wartości.

Number.prototype
> Number { 0 }
>  constructor: function Number()
>  toExponential: function toExponential()
>  toFixed: function toFixed()
>  toLocaleString: function toLocaleString()
>  toPrecision: function toPrecision()
>  toString: function toString()
>  valueOf: function valueOf()
>  <prototype>: Object { … }

Za pomocą tych konstruktorów możesz tworzyć elementy podstawowe, zamiast definiować tylko ze względu na ich wartość. Na przykład użycie konstruktora String powoduje utworzenie obiekt typu string, a nie literał ciągu: obiekt, który zawiera nie tylko nasz ciąg ale wszystkie właściwości odziedziczone i metody konstruktora.

const myString = new String( "I'm a string." );

myString;
> String { "I'm a string." }

typeof myString;
> "object"

myString.valueOf();
> "I'm a string."

W większości przypadków wynikowe obiekty zachowują się tak samo jak wartości, których użyliśmy ich zdefiniować. Na przykład mimo zdefiniowania wartości liczbowej za pomocą funkcji W wyniku konstruktora new Number powstaje obiekt zawierający wszystkie metody i właściwości prototypu Number, możesz używać operatorów matematycznych na linijce te obiekty tak samo jak w przypadku literałów liczbowych:

const numberOne = new Number(1);
const numberTwo = new Number(2);

numberOne;
> Number { 1 }

typeof numberOne;
> "object"

numberTwo;
> Number { 2 }

typeof numberTwo;
> "object"

numberOne + numberTwo;
> 3

Te konstruktory są bardzo rzadko używane, ponieważ wbudowany moduł JavaScript prototypowe dziedziczenie oznacza, że nie dają żadnych korzyści praktycznych. Tworzę w przypadku elementów podstawowych korzystających z konstruktorów również może prowadzić do nieoczekiwanych rezultatów, Wynik jest obiektem, a nie prostym literałem:

let stringLiteral = "String literal."

typeof stringLiteral;
> "string"

let stringObject = new String( "String object." );

stringObject
> "object"

Może to komplikować stosowanie rygorystycznych operatorów porównania:

const myStringLiteral = "My string";
const myStringObject = new String( "My string" );

myStringLiteral === "My string";
> true

myStringObject === "My string";
> false

Automatyczne wstawianie średnika (ASI)

Podczas analizy skryptu interpretery JavaScript mogą używać funkcji o nazwie automatycznego wstawiania średnika (ASI) w celu korygowania pominiętych średniki. Jeśli parser JavaScriptu napotka niedozwolony token, próbuje dodać średnik przed tokenem, aby naprawić potencjalny błąd składni, o ile spełniony jest co najmniej jeden z poniższych warunków:

  • Token ten jest oddzielony od poprzedniego tokena podziałem wiersza.
  • Token to }.
  • Poprzedni token to ), a wstawiony średnik będzie jego zakończeniem średnik instrukcji do...while.

Więcej informacji znajdziesz w regułach ASI.

Na przykład pominięcie średników po poniższych instrukcjach nie spowoduje błąd składni z powodu ASI:

const myVariable = 2
myVariable + 3
> 5

ASI nie może jednak uwzględniać wielu wyciągów w tym samym wierszu. Jeśli napisz kilka instrukcji w tym samym wierszu, oddziel je znakiem średniki:

const myVariable = 2 myVariable + 3
> Uncaught SyntaxError: unexpected token: identifier

const myVariable = 2; myVariable + 3;
> 5

ASI to próba poprawiania błędów, a nie stworzona z myślą o elastyczności składniowej w JavaScripcie. Użyj średników tam, gdzie ma to zastosowanie, aby nie polegać w celu wygenerowania prawidłowego kodu.

Tryb ścisły

Standardy, które regulują sposób pisania JavaScriptu, ewoluowały daleko co uwzględniono na etapie projektowania języka. Każda nowa zmiana w Prawidłowe działanie JavaScriptu nie może powodować błędów w starszych witrynach.

ES5 rozwiązuje pewne długotrwałe problemy z semantyką JavaScriptu bez złamanie istniejących implementacji przez wprowadzenie „trybu ścisłego”, sposób na rezygnację do bardziej restrykcyjnego zestawu reguł językowych dotyczących całego skryptu dla jednej funkcji. Aby włączyć tryb ścisły, użyj literału ciągu znaków "use strict", a po nim średnik w pierwszym wierszu skryptu lub funkcja:

"use strict";
function myFunction() {
  "use strict";
}

Tryb rygorystyczny zapobiega występowaniu określonych „niebezpiecznych” działania lub wycofane funkcje, rzuty jawne błędy zamiast typowych błędów „ciszy” oraz zabrania używania składni, które mogą kolidować z przyszłymi funkcjami językowymi. Na przykład wcześnie decyzje projektowe obejmujące zmienny zakres. tym większe prawdopodobieństwo, że deweloperzy omyłkowo „zanieczyszczają” zakresu globalnego, gdy deklarując zmienną, niezależnie od jej kontekstu, przez pominięcie parametru Słowo kluczowe var:

(function() {
  mySloppyGlobal = true;
}());

mySloppyGlobal;
> true

Współczesne środowiska wykonawcze JavaScript nie mogą naprawić tego zachowania bez ryzyka, celowe lub omyłkowe uszkadzanie witryn, które są z nim związane; Współczesny JavaScript zapobiega temu, bo umożliwia programistom nowych zadań i domyślnie włączać tryb ścisły tylko w kontekście nowych funkcji językowych, które nie będą zakłócać działania starszych implementacji:

(function() {
    "use strict";
    mySloppyGlobal = true;
}());
> Uncaught ReferenceError: assignment to undeclared variable mySloppyGlobal

Musisz napisać „"use strict"” jako literał ciągu. literał szablonu, (use strict) nie będzie działać. Parametr "use strict" musisz też dodać przed i wykonywalne w odpowiednim kontekście. W przeciwnym razie tłumacz języka go zignoruje.

(function() {
    "use strict";
    let myVariable = "String.";
    console.log( myVariable );
    sloppyGlobal = true;
}());
> "String."
> Uncaught ReferenceError: assignment to undeclared variable sloppyGlobal

(function() {
    let myVariable = "String.";
    "use strict";
    console.log( myVariable );
    sloppyGlobal = true;
}());
> "String." // Because there was code prior to "use strict", this variable still pollutes the global scope

Według odwołania, według wartości

Każda zmienna, w tym właściwości obiektu, parametrów funkcji i elementów parametru array, set lub mapa, może zawierać obiekt podstawowy lub wartość referencyjna.

Gdy przypisujesz wartość podstawową z jednej zmiennej do drugiej, kod JavaScript wyszukiwarka utworzy kopię tej wartości i przypisze ją do zmiennej.

Kiedy przypiszesz obiekt (instancje klasy, tablice i funkcje) do zamiast tworzyć nową kopię tego obiektu, zmienna będzie zawierać element odwołanie do zapisanej pozycji obiektu w pamięci. Z tego powodu, obiekt, do którego odwołuje się zmienna, zmienia obiekt, do którego się odwołuje, wartości zawartej w tej zmiennej. Jeśli na przykład zainicjujesz nową ze zmienną zawierającą odwołanie do obiektu, a następnie użyj nowego parametru w celu dodania właściwości do tego obiektu, zostaje dodana właściwość wraz z wartością do oryginalnego obiektu:

const myObject = {};
const myObjectReference = myObject;

myObjectReference.myProperty = true;

myObject;
> Object { myProperty: true }

Jest to ważne nie tylko w przypadku modyfikowania obiektów, ale także w przypadku ponieważ ścisła równość obiektów wymaga, aby obie zmienne odwoływać się do tego samego obiektu, aby obliczyć wartość true. Nie mogą się odwoływać różnymi obiektami, nawet jeśli są one strukturalne identyczne:

const myObject = {};
const myReferencedObject = myObject;
const myNewObject = {};

myObject === myNewObject;
> false

myObject === myReferencedObject;
> true

Przydział pamięci

JavaScript korzysta z automatycznego zarządzania pamięcią, co oznacza, że pamięć nie musi być przydzielane lub przydzielane w trakcie opracowywania; Choć szczegóły silników JavaScriptu podejść do zarządzania pamięcią są zakres tego modułu. Wiedząc, jak jest przydzielana pamięć, w kontekście pracy z wartościami referencyjnymi.

Istnieją 2 „obszary” w pamięci: „stos” i „sterty”. Sklepy wielobranżowe danych statycznych (wartości podstawowych i odwołań do obiektów), ponieważ stałą ilość miejsca potrzebnego do przechowywania tych danych można przydzielić przed po wykonaniu skryptu. Na stercie przechowywane są obiekty, które potrzebują dynamicznie przydzielanej przestrzeni bo ich rozmiar może się zmieniać podczas wykonywania. Pamięć jest zwalniana przez proces czyli „odśmiecanie”. usuwa obiekty bez odniesień z pamięci.

Wątek główny

JavaScript jest zasadniczo jednowątkowym językiem o „synchronicznym” modelu wykonywania, co oznacza, że może on wykonywać tylko jedno zadanie. za jednym razem. Kontekst sekwencyjnego wykonywania jest nazywany wątkiem głównym.

Wątek główny jest udostępniany przez inne zadania przeglądarki, takie jak analiza HTML renderowanie i ponowne renderowanie części strony, uruchamianie animacji CSS do obsługi interakcji z użytkownikiem, od prostych (np. wyróżniania tekstu) po złożony (np. podczas interakcji z elementami formularza). Dostawcy przeglądarek znaleźli sposobów optymalizacji zadań wykonywanych w wątku głównym, ale bardziej złożonych skrypty mogą nadal wykorzystywać zbyt wiele zasobów wątku głównego i mieć ogólny wpływ wydajność strony.

Niektóre zadania można wykonywać w wątki w tle o nazwie Web Workers, z pewnymi ograniczeniami:

  • Wątki instancji roboczych mogą działać tylko w przypadku samodzielnych plików JavaScript.
  • Mają znacznie ograniczony dostęp do okna przeglądarki i interfejsu użytkownika lub nie mają go wcale.
  • Są ograniczone pod względem możliwości komunikacji z wątkiem głównym.

Dzięki tym ograniczeniom są one idealnym rozwiązaniem w przypadku zadań wymagających dużych ilości zasobów w przeciwnym razie zająć główny wątek.

Stos wywołań

Struktura danych używana do zarządzania „kontekstami wykonania” – czyli kodem aktywnie wykonywane – lista nazywana stosem wywołań (często po prostu „stos”). Przy pierwszym wykonaniu skryptu interpreter JavaScriptu tworzy „globalny kontekst wykonywania”, i przekazuje ją do stosu wywołań, a następnie instrukcje w kontekście globalnym wykonywane pojedynczo, od góry do w dół. Gdy interpreter napotka wywołanie funkcji podczas wykonywania w kontekście globalnym, przekazuje „kontekst wykonywania funkcji” dla tego połączenia na stos, wstrzymuje globalny kontekst wykonywania i wykonuje funkcję w kontekście działania funkcji.

Przy każdym wywołaniu funkcji kontekst wykonania tej funkcji jest została przeniesiona na górę stosu, tuż nad bieżącym kontekstem wykonywania. Stos wywołań działa w modelu „pierwsze wejście, pierwsze wyjście”, co oznacza, że najbardziej ostatnie wywołanie funkcji, które jest najwyższe w stosie, jest wykonywane i jest kontynuowane aż problem nie zostanie rozwiązany. Po zakończeniu tej funkcji tłumacz usuwa ją. ze stosu wywołań oraz kontekstu wykonania zawierającego to wywołanie funkcji ponownie stanie się najwyższym elementem w stosie i wznawia wykonanie kodu.

Te konteksty wykonywania przechwytują wszystkie wartości niezbędne do ich wykonania. Ta również ustalić zmienne i funkcje dostępne w ramach na podstawie jej kontekstu nadrzędnego oraz określają i ustawiają wartość this słowo kluczowe w kontekście funkcji.

pętla zdarzeń i kolejka wywołań zwrotnych.

To sekwencyjne wykonywanie oznacza, że zadania asynchroniczne zawierające wywołanie zwrotne takich jak pobieranie danych z serwera, reagowanie na interakcje użytkownika lub oczekiwanie na minutniki ustawione na setTimeout lub setInterval spowodowałoby zablokowanie w wątku głównym do momentu ukończenia zadania lub nieoczekiwanego przerwania bieżący kontekst wykonania w momencie kontekstu wykonywania funkcji wywołania zwrotnego zostanie dodany do stosu. Aby rozwiązać ten problem, JavaScript zarządza zadaniami asynchronicznymi „model równoczesności” oparty na zdarzeniach, składa się z „pętli zdarzeń” oraz „kolejka oddzwaniania” (czasem nazywany „kolejką wiadomości”).

Gdy w wątku głównym wykonywane jest zadanie asynchroniczne, wywołanie zwrotne kontekst wykonania funkcji jest umieszczany w kolejce wywołania zwrotnego, a nie nad stosu wywołań. Zapętla zdarzeń to wzorzec nazywany czasem reactor, który stale przeprowadza sondowanie stanu stosu wywołań i kolejki wywołań zwrotnych. Jeśli znajdują się w niej zadania kolejka wywołań zwrotnych i pętla zdarzeń określają, że stos wywołań jest pusty, zadania z kolejki wywołań zwrotnych są przekazywane na stos pojedynczo, .