Niedawno natknąłem się na tę Object.create()
metodę w JavaScript i staram się wydedukować, jak różni się ona od tworzenia nowej instancji obiektu new SomeFunction()
i kiedy chciałbyś użyć jednej nad drugą.
Rozważ następujący przykład:
var test = {
val: 1,
func: function() {
return this.val;
}
};
var testA = Object.create(test);
testA.val = 2;
console.log(test.func()); // 1
console.log(testA.func()); // 2
console.log('other test');
var otherTest = function() {
this.val = 1;
this.func = function() {
return this.val;
};
};
var otherTestA = new otherTest();
var otherTestB = new otherTest();
otherTestB.val = 2;
console.log(otherTestA.val); // 1
console.log(otherTestB.val); // 2
console.log(otherTestA.func()); // 1
console.log(otherTestB.func()); // 2
Zauważ, że w obu przypadkach obserwuje się to samo zachowanie. Wydaje mi się, że podstawowe różnice między tymi dwoma scenariuszami to:
- Obiekt użyty w
Object.create()
rzeczywistości tworzy prototyp nowego obiektu, podczas gdynew Function()
z zadeklarowanych właściwości / funkcji nie tworzy prototypu. - Nie można tworzyć zamknięć za pomocą
Object.create()
składni, tak jak w przypadku składni funkcjonalnej. Jest to logiczne, biorąc pod uwagę zakres typu leksykalnego (vs blokowy) JavaScript.
Czy powyższe stwierdzenia są prawidłowe? Czy coś mi brakuje? Kiedy używałbyś jednego nad drugim?
EDYCJA: link do wersji jsfiddle powyższego przykładu kodu: http://jsfiddle.net/rZfYL/
Odpowiedzi:
Tak,
Object.create
buduje obiekt, który dziedziczy bezpośrednio z tego przekazanego jako pierwszy argument.W przypadku funkcji konstruktora nowo utworzony obiekt dziedziczy po prototypie konstruktora, np .:
W powyższym przykładzie
o
dziedziczy bezpośrednio zSomeConstructor.prototype
.Różnica polega na tym,
Object.create
że możesz stworzyć obiekt, który niczego nie odziedziczyObject.create(null);
, z drugiej strony, jeśli ustawisz,SomeConstructor.prototype = null;
że nowo utworzony obiekt odziedziczyObject.prototype
.Możesz tworzyć zamknięcia, np. Używając argumentu deskryptorów właściwości:
Zauważ, że mówię o
Object.create
metodzie ECMAScript 5. edycji , a nie podkładce Crockforda.Metoda zaczyna być natywnie wdrażana w najnowszych przeglądarkach, sprawdź tę tabelę zgodności .
źródło
foo;
jest rozwiązywany w obecnym środowisku leksykalnym . 2) Aby zapewnić łatwy sposób implementacji dziedziczenia, jest to naprawdę potężna konstrukcja. IMO Chciałbym go użyć, ponieważ jest naprawdę prosty i lekki, ale w przypadku kodu produkcyjnego nadal musimy poczekać, aż ES5 będzie szeroko obsługiwany. O brakujących cechach brakowało faktu utworzenia „nieskazitelnego” obiektu,Object.create(null);
naprawdę przydatne jest zaimplementowanie niezawodnych obiektów podobnych do tablicy haszowej ...Object.create(null)
oznacza, że nie musisz używaćhasOwnProperty()
bzdur podczas iteracji, ponieważ nie dziedziczy ona żadnych ??? Podoba mi się - dzięki. Oczywiście, wszyscy nadal będą to robić,hasOwnProperty
ponieważ nie wszyscy będą z tego korzystać,Object.create(null)
więc nie jestem pewien, czy to prawdziwa korzyść ... Do tej pory znalazłem inne „zalety”Object.create()
całkowicie nieprzekonujące.Mówiąc najprościej,
new X
polega naObject.create(X.prototype)
dodatkowym uruchomieniuconstructor
funkcji. (I dajeconstructor
szansęreturn
rzeczywistemu obiektowi, który powinien być wynikiem wyrażenia zamiastthis
.)Otóż to. :)
Reszta odpowiedzi jest po prostu myląca, ponieważ najwyraźniej nikt inny nie czyta definicji
new
żadnego z nich. ;)źródło
Oto kroki, które mają miejsce wewnętrznie dla obu połączeń:
(Wskazówka: jedyną różnicą jest krok 3)
new Test()
:new Object()
objobj.__proto__
naTest.prototype
return Test.call(obj) || obj; // normally obj is returned but constructors in JS can return a value
Object.create( Test.prototype )
new Object()
objobj.__proto__
naTest.prototype
return obj;
W zasadzie
Object.create
nie uruchamia konstruktora.źródło
new
zasadzie wszystkie funkcje są zduplikowane, aObject.create
nie.Pozwól, że wyjaśnię (więcej na blogu ):
Car
konstruktorvar Car = function(){}
, dzieje się to wewnętrznie: mamy jeden{prototype}
ukryty link, doFunction.prototype
którego nie jest dostępny i jedenprototype
link, doCar.prototype
którego jest dostępny i który jest faktycznieconstructor
dostępnyCar
. Zarówno Function.prototype, jak i Car.prototype mają ukryte linki doObject.prototype
.Kiedy chcemy stworzyć dwa równoważne obiekty za pomocą
new
operatora icreate
metody, musimy to zrobić w następujący sposób:Honda = new Car();
iMaruti = Object.create(Car.prototype)
. Co się dzieje?Honda = new Car();
- Podczas tworzenia takiego obiektu{prototype}
wskazywana jest właściwość ukrytaCar.prototype
. Tak więc tutaj{prototype}
obiekt Hondy zawsze będzieCar.prototype
- nie mamy żadnej możliwości zmiany{prototype}
właściwości obiektu. Co jeśli chcę zmienić prototyp naszego nowo utworzonego obiektu?Maruti = Object.create(Car.prototype)
- Podczas tworzenia takiego obiektu masz dodatkową opcję wyboru{prototype}
właściwości obiektu. Jeśli chcesz Car.prototype jako, a{prototype}
następnie przekaż go jako parametr w funkcji. Jeśli nie chcesz, każdy{prototype}
dla obiektu potem można przekazaćnull
tak:Maruti = Object.create(null)
.Wniosek - korzystając z metody
Object.create
masz swobodę wyboru{prototype}
właściwości obiektu . Wnew Car();
, nie ma tej swobody.Preferowany sposób w OO JavaScript:
Załóżmy, że mamy dwa przedmioty
a
ib
.Załóżmy teraz, że
a
ma kilka metod, któreb
również chcą uzyskać dostęp. W tym celu wymagamy dziedziczenia obiektów (a
powinien to być prototypb
tylko wtedy, gdy chcemy uzyskać dostęp do tych metod). Jeśli sprawdzimy prototypy,a
ab
następnie dowiemy się, że mają one wspólny prototypObject.prototype
.Problem - chcemy obiekt
a
jako prototypb
, ale tutaj stworzyliśmy obiektb
z prototypemObject.prototype
. Rozwiązanie - wprowadzono ECMAScript 5Object.create()
, aby łatwo osiągnąć takie dziedzictwo. Jeśli tworzymyb
taki obiekt :następnie,
Tak więc, jeśli wykonujesz skrypty obiektowe,
Object.create()
jest to bardzo przydatne do dziedziczenia.źródło
a.isPrototypeOf(b);
powróci,false
co jest słuszne, ponieważ oba Obiekty są różne i wskazują na inną pamięć. Prawidłowy sposób zrobienia tego znew
operatorem znajduje się tutaj. - jsfiddle.net/167onunp .To:
i
są dość podobne. Jedną ważną różnicą jest to, że
new Foo
faktycznie uruchamia kod konstruktora, podczas gdyObject.create
nie wykonuje kodu takiego jakZauważ, że jeśli używasz dwuparametrowej wersji
Object.create()
, możesz robić znacznie potężniejsze rzeczy.źródło
Object.create
w najprostszej formie, takiej jak ta, pozwala pominąć funkcje konstruktora w kodzie, korzystając z dziedziczenia prototypów.Różnica polega na tak zwanym „dziedziczeniu pseudoklasycznym a prototypowym”. Sugeruje się użycie tylko jednego typu w kodzie, a nie mieszanie dwóch.
W dziedziczeniu pseudoklasycznym (z operatorem „new”) wyobraź sobie, że najpierw definiujesz pseudoklasę, a następnie tworzysz obiekty z tej klasy. Na przykład zdefiniuj pseudoklasę „Osoba”, a następnie utwórz „Alice” i „Bob” z „Osoby”.
W dziedziczeniu prototypowym (przy użyciu Object.create) bezpośrednio tworzysz określoną osobę „Alice”, a następnie tworzysz inną osobę „Bob”, używając „Alice” jako prototypu. Nie ma tu „klasy”; wszystkie są przedmiotami.
Wewnętrznie JavaScript używa „dziedziczenia prototypowego”; „pseudoklasyczny” sposób to tylko trochę cukru.
Zobacz ten link, aby porównać dwa sposoby.
źródło
Podsumowanie:
1) ze
new
słowem kluczowym należy zwrócić uwagę na dwie rzeczy;a) funkcja jest używana jako konstruktor
b)
function.prototype
obiekt jest przekazywany do__proto__
właściwości ... lub gdzie__proto__
nie jest obsługiwany, jest to drugie miejsce, w którym nowy obiekt szuka właściwości2) wraz z
Object.create(obj.prototype)
tobą konstruujesz obiekt (obj.prototype
) i przekazujesz go do zamierzonego obiektu. Z tą różnicą, że teraz nowy obiekt__proto__
wskazuje również na obj.prototype (w tym celu proszę odesłać xj9)źródło
Warianty tworzenia obiektów.
Wariant 1 : „ new Object () ” -> Konstruktor obiektów bez argumentów.
Wariant 2 : „ nowy obiekt (osoba) ” -> Konstruktor obiektów z argumentem.
Wariant 3.1 : „ Object.create (person) ”. Użyj Object.create z prostym obiektem „person”. „Object.create (osoba)” utworzy (i zwróci) nowy pusty obiekt i doda właściwość „__proto__” do tego samego nowego pustego obiektu. Ta właściwość „__proto__” będzie wskazywać na obiekt „osoba”.
Wariant 3.2 : „ Object.create (Object.prototype) ”. Użyj Object.create z wbudowanym obiektem -> 'Object.prototype'. „Object.create (Object.prototype)” utworzy (i zwróci) nowy pusty obiekt i doda właściwość „__proto__” do tego samego nowego pustego obiektu. Ta właściwość „__proto__” będzie wskazywać na obiekt „Object.prototype”.
Wariant 4 : „ new SomeFunction () ”
źródło
Wewnętrznie
Object.create
robi to:Składnia po prostu usuwa złudzenie, że JavaScript używa klasycznego dziedziczenia.
źródło
Object.create
robi o wiele więcej, możesz zdefiniować właściwości za pomocą deskryptorów właściwości i możesz stworzyć obiekt, który niczego nie odziedziczy (Object.create(null);
), tego typu podkładek należy unikać, ponieważ tak naprawdę nie można tego naśladować zachowanie na ES3. Więcej informacjiObject.create
.Zgodnie z tą odpowiedzią i tym
new
słowem kluczowym wideo wykonuje następujące czynności:Tworzy nowy obiekt.
Łączy nowy obiekt z funkcją konstruktora (
prototype
).Sprawia, że
this
zmienna wskazuje nowy obiekt.Wykonuje funkcję konstruktora przy użyciu nowego obiektu i niejawnie wykonuje
return this
;Przypisuje nazwę funkcji konstruktora do właściwości nowego obiektu
constructor
.Object.create
wykonuje tylko1st
i2nd
kroki !!!źródło