Po pierwsze, pamiętaj, że JavaScript to przede wszystkim język prototypowy , a nie język oparty na klasach 1 . Foo
nie jest klasą, to funkcja, która jest przedmiotem. Możesz utworzyć obiekt z tej funkcji za pomocą new
słowa kluczowego, które pozwoli ci stworzyć coś podobnego do klasy w standardowym języku OOP.
Sugeruję zignorowanie przez __proto__
większość czasu, ponieważ ma słabą obsługę wielu przeglądarek, a zamiast tego skup się na nauczeniu się, jak prototype
działa.
Jeśli masz instancję obiektu utworzoną z funkcji 2 i uzyskujesz dostęp do jednego z jego elementów (metod, atrybutów, właściwości, stałych itp.), Dostęp będzie spływał w dół hierarchii prototypów, dopóki (a) nie znajdzie członek lub (b) nie znajduje innego prototypu.
Hierarchia rozpoczyna się od wywołanego obiektu, a następnie wyszukuje obiekt prototypowy. Jeśli prototypowy obiekt ma prototyp, powtarza się, jeśli prototyp nie istnieje, undefined
jest zwracany.
Na przykład:
foo = {bar: 'baz'};
console.log(foo.bar); // logs "baz"
foo = {};
console.log(foo.bar); // logs undefined
function Foo(){}
Foo.prototype = {bar: 'baz'};
f = new Foo();
console.log(f.bar);
// logs "baz" because the object f doesn't have an attribute "bar"
// so it checks the prototype
f.bar = 'buzz';
console.log( f.bar ); // logs "buzz" because f has an attribute "bar" set
Wydaje mi się, że przynajmniej trochę zrozumiałeś już te „podstawowe” części, ale muszę je wyrazić, żeby się upewnić.
W JavaScript wszystko jest przedmiotem 3 .
wszystko jest przedmiotem.
function Foo(){}
nie tylko definiuje nową funkcję, ale definiuje nowy obiekt funkcji, do którego można uzyskać dostęp za pomocą Foo
.
Dlatego możesz uzyskać dostęp do Foo
prototypu za pomocą Foo.prototype
.
Możesz także ustawić więcej funkcji na Foo
:
Foo.talk = function () {
alert('hello world!');
};
Dostęp do tej nowej funkcji można uzyskać za pomocą:
Foo.talk();
Mam nadzieję, że już teraz zauważasz podobieństwo między funkcjami na obiekcie funkcji a metodą statyczną.
Pomyśl o f = new Foo();
tworzeniu instancji klasy, Foo.prototype.bar = function(){...}
o definiowaniu wspólnej metody dla klasy oraz Foo.baz = function(){...}
o definiowaniu publicznej metody statycznej dla klasy.
ECMAScript 2015 wprowadził szereg cukrów składniowych do tego rodzaju deklaracji, aby ułatwić ich wdrożenie, a jednocześnie ułatwić czytanie. Poprzedni przykład można zatem zapisać jako:
class Foo {
bar() {...}
static baz() {...}
}
co pozwala bar
nazywać się jako:
const f = new Foo()
f.bar()
i baz
być nazywany:
Foo.baz()
1: class
było „przyszłym zastrzeżonym słowem” w specyfikacji ECMAScript 5 , ale ES6 wprowadza możliwość definiowania klas za pomocą class
słowa kluczowego.
2: zasadniczo instancja klasy utworzona przez konstruktora, ale istnieje wiele niuansowych różnic, których nie chcę was wprowadzać w błąd
3: prymitywne wartości - które obejmują undefined
, null
logiczne, liczby i łańcuchy - nie są technicznie obiektami, ponieważ są implementacjami języka niskiego poziomu. Wartości logiczne, liczby i łańcuchy nadal oddziałują z łańcuchem prototypowym, jakby były obiektami, dlatego dla celów tej odpowiedzi łatwiej jest uznać je za „obiekty”, nawet jeśli nie są całkiem.
Foo.talk = function ...