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 instrukcjido
...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, .