Wiem, że to zadziała:
function Foo() {};
Foo.prototype.talk = function () {
alert('hello~\n');
};
var a = new Foo;
a.talk(); // 'hello~\n'
Ale jeśli chcę zadzwonić
Foo.talk() // this will not work
Foo.prototype.talk() // this works correctly
Znajduję metody na Foo.talk
pracę,
Foo.__proto__ = Foo.prototype
Foo.talk = Foo.prototype.talk
Czy są na to inne sposoby? Nie wiem, czy jest to właściwe. Czy używasz metod klasowych lub statycznych w kodzie JavaScript?
javascript
oop
lostyzd
źródło
źródło
Foo.talk = function ...
Foo.walk = function() {}
Nie wpłynie na jego wystąpienia, ponieważ nie ma go w łańcuchu prototypów. Czy istnieje przeglądarka internetowa, która pozwala[[prototype]]
wskazać funkcję na jej funkcjęprototype
?this
wskaźnikiem.Odpowiedzi:
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ę, jakprototype
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:
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
:Dostęp do tej nowej funkcji można uzyskać za pomocą:
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 orazFoo.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:
co pozwala
bar
nazywać się jako:i
baz
być nazywany: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.źródło
Foo.talk()
. Możesz to przypisać w konstruktorze, jeśli chcesz:this.talk = Foo.talk
- lub, jak zauważysz, przypisującFoo.prototype.talk = Foo.talk
. Ale nie jestem pewien, czy to dobry pomysł - z zasady metody instancji powinny być specyficzne dla instancji.Foo.talk()
po prostu wywołuje funkcję z przestrzenią nazw. Używałbyś go w sytuacjach podobnych do wywoływania metod statycznych w językach OOP, takich jak Java / C #. Dobrym przykładem przypadku użycia może być funkcja taka jakArray.isArray()
.Foo.talk = function ()...
nie będą dostępne dla podklas dla własnej nazwy klasy. Można to obejść poprzez „rozszerzanie” podklas, ale wciąż szukam bardziej eleganckiego sposobu.Możesz to osiągnąć jak poniżej:
Możesz teraz wywołać funkcję „mów”, jak poniżej:
Możesz to zrobić, ponieważ w JavaScript funkcje są również obiektami.
źródło
Wywołaj metodę statyczną z instancji:
Prosty projekt klasy Javascript: https://github.com/reduardo7/sjsClass
źródło
Clazz.staticMethod
ale pokazuje on, jak połączyć się z tymi metodami statycznymi z obiektu utworzonego. Jest to szczególnie przydatne w środowiskach takich jak Node.js, w których użycie wymaga, możesz nie mieć bezpośredniego dostępu do oryginalnego konstruktora. Jedyne, co chciałbym dodać tothis.constructor.staticMethod.apply(this, arguments);
constructor: (a) -> @constructor.add @
(i takOto dobry przykład pokazujący, jak JavaScript działa ze zmiennymi i metodami static / instance.
źródło
this
.this
słowa kluczowegoDodatkowo można teraz korzystać z
class
istatic
da
źródło
a.talk()
nie działa. Przyjęta odpowiedź mówi, że łańcuch prototypów powinien ją znaleźć, prawda? Ale tak nie jestUżywam przestrzeni nazw:
I aby go użyć:
Lub
źródło
ES6 obsługuje teraz
class
istatic
słowa kluczowe takie jak urok:źródło
Jeśli musisz pisać metody statyczne w ES5, znalazłem świetny samouczek:
patrz @ https://abdulapopoola.com/2013/03/30/static-and-instance-methods-in-javascript/
źródło
Tylko dodatkowe uwagi. Używając klasy ES6, kiedy tworzymy metody statyczne .. silnik Javacsript ustawił atrybut deskryptora nieco inaczej niż w starej szkole „statycznej”
ustawia wewnętrzny atrybut (właściwość deskryptora) dla brand () na
w porównaniu do
który ustawia wewnętrzny atrybut dla brand () na
sprawdź, czy dla parametru enumerable ustawiono wartość false dla metody statycznej w ES6.
oznacza to, że nie można użyć pętli for-in, aby sprawdzić obiekt
Metoda statyczna w ES6 jest traktowana jak własność prywatna innej klasy (nazwa, długość, konstruktor), z wyjątkiem tego, że metoda statyczna jest nadal zapisywalna, więc zapisywalny deskryptor ma wartość true
{ writable: true }
. oznacza to również, że możemy to zmienićźródło
Podczas próby wywołania
Foo.talk
, JS próbuje szukać funkcjętalk
przez__proto__
i, oczywiście, nie można go znaleźć.Foo.__proto__
jestFunction.prototype
.źródło
Wywołania metod statycznych są wykonywane bezpośrednio w klasie i nie można ich wywoływać w instancjach klasy. Do tworzenia funkcji narzędziowej często stosuje się metody statyczne
Całkiem jasny opis
Wykonano bezpośrednio z mozilla.org
Foo musi być związany z twoją klasą. Następnie, kiedy tworzysz nową instancję, możesz wywołać myNewInstance.foo () Jeśli importujesz klasę, możesz wywołać metodę statyczną
źródło
Kiedy spotkałem się z taką sytuacją, zrobiłem coś takiego:
więc teraz mogę wywołać metodę info jako
Logger.info("my Msg", "Tag");
źródło
W twoim przypadku, jeśli chcesz
Foo.talk()
:Ale jest to nieefektywny sposób wdrożenia, użycie
prototype
jest lepsze.Innym sposobem, Mój sposób jest zdefiniowany jako klasa statyczna:
Powyższa klasa statyczna nie musi być używana,
prototype
ponieważ zostanie zbudowana tylko raz jako użycie statyczne.źródło
JavaScript nie ma żadnych rzeczywistych klas, a raczej korzysta z systemu dziedziczenia prototypowego, w którym obiekty „dziedziczą” po innych obiektach poprzez łańcuch prototypów. Można to najlepiej wyjaśnić za pomocą samego kodu:
źródło