JavaScript nie ma klasycznego modelu obiektowego klasy . Używa potężniejszego prototypowego dziedziczenia, które może naśladować klasy, ale nie nadaje się do tego dobrze. Wszystko jest przedmiotem, a przedmioty mogą dziedziczyć z innych obiektów.
Konstruktor jest po prostu funkcją, która przypisuje właściwości do nowo utworzonych obiektów. Obiekt (utworzony przez wywołanie z new
keyword) można odwoływać się przez this
keyword (który jest lokalny dla funkcji).
Metoda jest również tylko funkcją o nazwie na obiekt - ponownie z this
wskazując na obiekt. Przynajmniej wtedy, gdy ta funkcja jest wywoływana jako właściwość obiektu, przy użyciu kropki, nawiasów. Powoduje to wiele zamieszania u początkujących, ponieważ jeśli przekażesz tę funkcję (np. Do detektora zdarzeń), zostanie ona "odłączona" od obiektu, na którym był dostępny.
Teraz, gdzie jest dziedziczenie? Instancje "klasy" dziedziczą z tego samego obiektu prototypowego. Metody są zdefiniowane jako właściwości funkcji dla tego obiektu (zamiast jednej funkcji dla każdej instancji), instancja, w której się je nazywa, dziedziczy tylko tę właściwość.
Przykład:
function Foo() {
this.bar = "foo"; // creating a property on the instance
}
Foo.prototype.foo = 0; // of course you also can define other values to inherit
Foo.prototype.getBar = function() {
// quite useless
return this.bar;
}
var foo = new Foo; // creates an object which inherits from Foo.prototype,
// applies the Foo constructor on it and assigns it to the var
foo.getBar(); // "foo" - the inherited function is applied on the object and
// returns its "bar" property
foo.bar; // "foo" - we could have done this easier.
foo[foo.bar]; // 0 - access the "foo" property, which is inherited
foo.foo = 1; // and now overwrite it by creating an own property of foo
foo[foo.getBar()]; // 1 - gets the overwritten property value. Notice that
(new Foo).foo; // is still 0
Tak, my używaliśmy tylko właściwości tego obiektu i są z niego zadowoleni. Ale wszystkie z nich są "publiczne" i można je zastąpić/zmienić/usunąć! Jeśli to nie ma znaczenia, masz szczęście. Możesz wskazać "prywatyzację" właściwości, dodając przedrostki ich nazw podkreśleniami, ale to tylko wskazówka dla innych programistów i może nie być przestrzegana (szczególnie w błędzie).
Więc, sprytni umysły znaleźli rozwiązanie, które wykorzystuje funkcję konstruktora jako zamknięcie, pozwalając na tworzenie prywatnych "atrybutów". Każde wykonanie funkcji javascript tworzy nowe środowisko zmienne dla zmiennych lokalnych, które mogą zbierać śmieci po zakończeniu wykonywania. Każda funkcja zadeklarowana w tym zakresie ma również dostęp do tych zmiennych i dopóki te funkcje mogą być wywoływane (np. Przez detektor zdarzeń), środowisko musi się utrzymywać. Tak więc, przez eksportowanie funkcji zdefiniowanych lokalnie ze swojego konstruktora, zachowujesz to zmienne środowisko za pomocą zmiennych lokalnych, do których dostęp mają tylko te funkcje.
Zobaczmy, jak to działa:
function Foo() {
var bar = "foo"; // a local variable
this.getBar = function getter() {
return bar; // accesses the local variable
}; // the assignment to a property makes it available to outside
}
var foo = new Foo; // an object with one method, inheriting from a [currently] empty prototype
foo.getBar(); // "foo" - receives us the value of the "bar" variable in the constructor
Ta funkcja getter, która jest zdefiniowana wewnątrz konstruktora, jest teraz nazywany „uprzywilejowany sposób”, jak to ma dostęp do „private” (lokalny) "atrybuty" (zmienne). Wartość bar
nigdy się nie zmieni. Można również zadeklarować funkcję ustawiającą dla niego oczywiście, i że można dodać pewne sprawdzanie poprawności itp.
Należy zauważyć, że metody obiektu prototypowego nie mają dostępu do zmiennych lokalnych konstruktora, ale mogą one użyj metod uprzywilejowanych. Dodajmy:
Foo.prototype.getFooBar = function() {
return this.getBar() + "bar"; // access the "getBar" function on "this" instance
}
// the inheritance is dynamic, so we can use it on our existing foo object
foo.getFooBar(); // "foobar" - concatenated the "bar" value with a custom suffix
Można więc połączyć oba podejścia. Zauważ, że uprzywilejowane metody wymagają więcej pamięci, ponieważ tworzysz różne obiekty funkcji z różnymi łańcuchami zasięgu (ale ten sam kod). Jeśli zamierzasz tworzyć niezwykle duże ilości instancji, powinieneś zdefiniować metody tylko na prototypie.
To staje się jeszcze bardziej skomplikowane, gdy konfigurujesz dziedziczenie z jednej "klasy" na drugą - w zasadzie musisz uczynić obiekt prototypowy dziecka dziedziczącym po obiekcie macierzystym i zastosować konstruktor macierzysty w instancjach potomnych w celu utworzenia "prywatne atrybuty". Przyjrzeć się Correct javascript inheritance, Private variables in inherited prototypes, Define Private field Members and Inheritance in JAVASCRIPT module pattern i How to implement inheritance in JS Revealing prototype pattern?
dostęp '.bar' jest własności przedmiotów nie zmienna. Więc tak, aby uzyskać właściwość z obiektu, musisz to zrobić poprzez odwołanie do tego obiektu. Jeśli 'this' odwołuje się do twojego obiektu, to' this.bar' da ci tę właściwość. –
'this.bar' nie jest tym samym, co' bar'. Możesz jednak użyć 'var bar = this.bar', który spowoduje, że' bar' odwoła się do 'this.bar'a – Loktar
@Loktar, ale tylko wtedy, gdy' this.bar' jest obiektem lub tablicą ... – Alnitak