Pytanie Jakie jest "nowe" słowo kluczowe w JavaScript?


The new słowo kluczowe w JavaScript może być dość mylące, gdy zostanie napotkane po raz pierwszy, ponieważ ludzie mają tendencję do myślenia, że ​​JavaScript nie jest obiektowym językiem programowania.

  • Co to jest?
  • Jakie problemy rozwiązuje?
  • Kiedy jest to właściwe, a kiedy nie?

1559
2017-10-29 21:32


pochodzenie


Również powiązany wątek - stackoverflow.com/questions/383402/... - Chetan Sastry


Odpowiedzi:


Robi 5 rzeczy:

  1. Tworzy nowy obiekt. Typ tego obiektu jest po prostu obiekt.
  2. Ustawia wewnętrzny, niedostępny, nowy obiekt [[prototyp]] (to znaczy. __proto__) właściwość, która ma być funkcją zewnętrzną, dostępną, prototyp obiekt (każdy obiekt funkcji automatycznie ma prototyp własność).
  3. To sprawia, że this zmienna wskazuje na nowo utworzony obiekt.
  4. Wykonuje funkcję konstruktora, używając nowo utworzonego obiektu kiedykolwiek this jest wspomniany.
  5. Zwraca nowo utworzony obiekt, chyba że funkcja konstruktora zwraca wartośćnull odniesienie do obiektu. W takim przypadku odwołanie do tego obiektu zostanie zwrócone.

Uwaga: funkcja konstruktora odnosi się do funkcji po new słowo kluczowe, jak w

new ConstructorFunction(arg1, arg2)

Gdy to zrobisz, jeśli zostanie zażądana niezdefiniowana właściwość nowego obiektu, skrypt sprawdzi obiekt [[prototyp]] zamiast tego obiekt dla właściwości. W ten sposób można uzyskać coś podobnego do tradycyjnego dziedziczenia klasy w JavaScript.

Najtrudniejszą częścią jest punkt numer 2. Każdy obiekt (łącznie z funkcjami) ma tę wewnętrzną właściwość nazywaną [[prototyp]]. To może tylko być ustawione na czas tworzenia obiektu, albo przy pomocy Nowy, z Object.createlub w oparciu o literał (funkcje domyślne to Function.prototype, numbers to Number.prototype itd.). Można go odczytać tylko za pomocą Object.getPrototypeOf (someObject). Jest Nie inny sposób na ustawienie lub odczytanie tej wartości.

Funkcje, oprócz ukrytego [[prototyp]] własność, mają również właściwość o nazwie prototypi to jest to, że można uzyskać dostęp i modyfikować, aby zapewnić odziedziczone właściwości i metody dla tworzonych obiektów.


Oto przykład:

ObjMaker = function() {this.a = 'first';};
// ObjMaker is just a function, there's nothing special about it that makes 
// it a constructor.

ObjMaker.prototype.b = 'second';
// like all functions, ObjMaker has an accessible prototype property that 
// we can alter. I just added a property called 'b' to it. Like 
// all objects, ObjMaker also has an inaccessible [[prototype]] property
// that we can't do anything with

obj1 = new ObjMaker();
// 3 things just happened.
// A new, empty object was created called obj1.  At first obj1 was the same
// as {}. The [[prototype]] property of obj1 was then set to the current
// object value of the ObjMaker.prototype (if ObjMaker.prototype is later
// assigned a new object value, obj1's [[prototype]] will not change, but you
// can alter the properties of ObjMaker.prototype to add to both the
// prototype and [[prototype]]). The ObjMaker function was executed, with
// obj1 in place of this... so obj1.a was set to 'first'.

obj1.a;
// returns 'first'
obj1.b;
// obj1 doesn't have a property called 'b', so JavaScript checks 
// its [[prototype]]. Its [[prototype]] is the same as ObjMaker.prototype
// ObjMaker.prototype has a property called 'b' with value 'second'
// returns 'second'

To tak jak dziedziczenie klas, bo teraz wszystkie obiekty, których używasz new ObjMaker() również odziedziczył własność "b".

Jeśli chcesz coś podobnego do podklasy, wykonaj następujące czynności:

SubObjMaker = function () {};
SubObjMaker.prototype = new ObjMaker(); // note: this pattern is deprecated!
// Because we used 'new', the [[prototype]] property of SubObjMaker.prototype
// is now set to the object value of ObjMaker.prototype.
// The modern way to do this is with Object.create(), which was added in ECMAScript 5:
// SubObjMaker.prototype = Object.create(ObjMaker.prototype);

SubObjMaker.prototype.c = 'third';  
obj2 = new SubObjMaker();
// [[prototype]] property of obj2 is now set to SubObjMaker.prototype
// Remember that the [[prototype]] property of SubObjMaker.prototype
// is ObjMaker.prototype. So now obj2 has a prototype chain!
// obj2 ---> SubObjMaker.prototype ---> ObjMaker.prototype

obj2.c;
// returns 'third', from SubObjMaker.prototype

obj2.b;
// returns 'second', from ObjMaker.prototype

obj2.a;
// returns 'first', from SubObjMaker.prototype, because SubObjMaker.prototype 
// was created with the ObjMaker function, which assigned a for us

Przeczytałem mnóstwo śmieci na ten temat, zanim w końcu znalazłem ta strona, gdzie jest to bardzo dobrze wyjaśnione przy pomocy ładnych diagramów.


1961
2017-10-29 22:22



Chciałem tylko dodać: Istnieje sposób na uzyskanie dostępu do wewnętrznego [[prototypu]] przez __proto__. Jest to jednak niestandardowe i obsługiwane tylko przez stosunkowo nowe przeglądarki (i nie wszystkie). Pojawia się znormalizowany sposób, a mianowicie Object.getPrototypeOf (obj), ale jest to Ecmascript3.1 i sam jest obsługiwany tylko w nowych przeglądarkach - ponownie. Generalnie zaleca się, aby nie używać tej właściwości, ale tam naprawdę szybko się komplikuje. - Blub
Pytanie: co dzieje się inaczej, jeśli ObjMaker jest zdefiniowany jako funkcja zwracająca wartość? - Jim Blackler
@LonelyPixel new istnieje abyś nie musiał Napisz metody fabryczne do konstruowania / kopiowania funkcji / obiektów. Oznacza to: "Skopiuj to, czyniąc to tak, jak jego rodzica" klasa ", rób to sprawnie i poprawnie oraz przechowuj informacje o dziedziczeniu, które są dostępne tylko dla mnie, JS, wewnętrznie". Aby to zrobić, modyfikuje inaczej niedostępne wewnętrzne prototypenowego obiektu, aby nieprzejrzysto enkapsulować odziedziczone elementy, naśladując klasyczne łańcuchy dziedziczenia OO (które nie są modyfikowalne w środowisku wykonawczym). Możesz symulować to bez new, ale dziedziczenie będzie modyfikowalne w czasie wykonywania. Dobry? Zły? Zależy od Ciebie. - Arcane Engineer
mały punkt do dodania: wywołanie konstruktora, poprzedzone nowym słowem kluczowym, automatycznie zwraca utworzony obiekt; nie ma potrzeby jawnego zwracania go z poziomu konstruktora. - charlie roberts
Jest jedna uwaga, która mówi Notice that this pattern is deprecated!. Jaki jest poprawny, aktualny wzorzec do ustawienia prototypu klasy? - Tom Pažourek


Załóżmy, że masz tę funkcję:

var Foo = function(){
  this.A = 1;
  this.B = 2;
};

Jeśli nazwiesz to jako samodzielną funkcję, taką jak:

Foo();

Wykonanie tej funkcji doda dwie właściwości do window obiekt (A i B). Dodaje go do window bo window jest obiektem, który wywołał funkcję, gdy wykonujesz ją w ten sposób, oraz this w funkcji jest obiektem, który wywołał funkcję. W JavaScript przynajmniej.

Teraz możesz to tak nazwać new:

var bar = new Foo();

Co się stanie, gdy dodasz new do wywołania funkcji jest to, że tworzony jest nowy obiekt (tylko var bar = new Object()) i że this w funkcji wskazuje na nowy Object właśnie stworzyłeś, zamiast do obiektu, który wywołał funkcję. Więc bar jest teraz obiektem o właściwościach A i B. Każda funkcja może być konstruktorem, po prostu nie zawsze ma sens.


359
2018-06-20 23:46



Zależy od kontekstu wykonania. W moim przypadku (skrypty Qt) jest to tylko obiekt globalny. - Maxym
Czy to spowoduje większe zużycie pamięci? - Jürgen Paul
ponieważ okno jest obiektem, który wywołał funkcję - musi być: ponieważ okno jest obiektem, który zawiera funkcja. - Dávid Horváth
@Taurus W przeglądarce internetowej funkcja bez metody będzie metodą window niejawnie. Nawet w zamknięciu, nawet jeśli jest anonimem. Jednak w tym przykładzie jest to proste wywołanie metody w oknie: Foo(); => [default context].Foo(); => window.Foo();. W tym wyrażeniu window jest kontekst (nie tylko gość, co nie ma znaczenia). - Dávid Horváth
@Taurus Zasadniczo tak. Jednak w ECMA 6 i 7 rzeczy są bardziej złożone (patrz lambdy, klasy itp.). - Dávid Horváth


Oprócz odpowiedzi Daniela Howarda, oto co new ma (lub przynajmniej wydaje się robić):

function New(func) {
    var res = {};
    if (func.prototype !== null) {
        res.__proto__ = func.prototype;
    }
    var ret = func.apply(res, Array.prototype.slice.call(arguments, 1));
    if ((typeof ret === "object" || typeof ret === "function") && ret !== null) {
        return ret;
    }
    return res;
}

Podczas

var obj = New(A, 1, 2);

jest równa

var obj = new A(1, 2);

146
2018-05-27 09:23



Zauważyłem, że javascript jest łatwiejszy do zrozumienia niż angielski: v - damphat
Doskonała odpowiedź. Mam jedno małe pytanie: jak to możliwe func.prototype być null? Czy mógłbyś trochę o tym powiedzieć? - Tom Pažourek
@tomp można zastąpić właściwości prototype, po prostu pisząc A.prototype = null; W tym wypadku new A() spowoduje obiekt, ten wewnętrzny prototyp wskazuje na Object obiekt: jsfiddle.net/Mk42Z - basilikum
Sprawdzanie typu może być błędne, ponieważ obiekt hosta może wytworzyć coś innego niż "obiekt" lub "funkcja". Aby przetestować, czy coś jest przedmiotem, wolę Object(ret) === ret. - Oriol
@Oriol dziękuję za komentarz. To prawda, co mówisz, a każdy rzeczywisty test powinien być wykonany w bardziej solidny sposób. Jednak myślę o tej pojęciowej odpowiedzi, typeof test właśnie ułatwia zrozumienie, co dzieje się za kulisami. - basilikum


Dla początkujących lepiej to zrozumieć

wypróbuj poniższy kod w konsoli przeglądarki.

function Foo() { 
    return this; 
}

var a = Foo();       //returns window object
var b = new Foo();   //returns empty object of foo

a instanceof Window;  // true
a instanceof Foo;     // false

b instanceof Window;  // false
b instanceof Foo;     // true

Teraz możesz przeczytać odpowiedź społeczności wiki :)


85
2017-10-29 21:34



Dobra odpowiedź. Również - pomijając return this; daje taką samą wydajność. - Nelu
Byłoby miło wskazać, dlaczego tak się dzieje. - Florian Leitgeb


więc prawdopodobnie nie do tworzenia   wystąpienia obiektu

Jest używany dokładnie do tego. Definiujesz konstruktor funkcji w następujący sposób:

function Person(name) {
    this.name = name;
}

var john = new Person('John');

Jednak dodatkowa korzyść, którą posiada ECMAScript, można rozszerzyć dzięki .prototype własność, więc możemy zrobić coś takiego ...

Person.prototype.getName = function() { return this.name; }

Wszystkie obiekty utworzone z tego konstruktora będą teraz miały getName ze względu na prototypowy łańcuch, do którego mają dostęp.


33
2017-10-29 21:36



konstruktory funkcji są używane jak klasy, nie ma class słowo kluczowe, ale możesz zrobić to samo. - meder omuraliev
Istnieje kindof to słowo kluczowe class - klasa jest zarezerwowana do wykorzystania w przyszłości - Greg
Nawiasem mówiąc, dlatego używasz .className nie .class do ustawienia klasy CSS - Greg
Powinien być kapitalizowany Person by convention. - eomeroff


JavaScript jest obiektowy język programowania i jest używany dokładnie do tworzenia instancji. Jest oparty na prototypach, a nie na klasach, ale to nie znaczy, że nie jest obiektowy.


26
2017-10-29 21:37



Chciałbym powiedzieć, że JavaScript wydaje się być bardziej zorientowany na obiekt niż wszystkie języki klasowe. W JavaScript wszystko, co napiszesz, staje się natychmiast obiektem, ale w językach klasowych najpierw piszesz deklaracje, a dopiero później tworzysz określone instancje (obiekty) klas. Prototyp JavaScript wydaje się niejasno przypominać wszystkie rzeczy VTABLE dla języków klasowych. - JustAMartin


JavaScript jest dynamicznym językiem programowania, który obsługuje paradygmat programowania obiektowego i wykorzystuje go do tworzenia nowych instancji obiektu.

Klasy nie są konieczne dla obiektów - Javascript jest a oparty na prototypach język.


13
2018-05-16 07:21





czasami kod jest łatwiejszy niż słowa:

var func1 = function (x) { this.x = x; }                    // used with 'new' only
var func2 = function (x) { var z={}; z.x = x; return z; }   // used both ways
func1.prototype.y = 11;
func2.prototype.y = 12;

A1 = new func1(1);      // has A1.x  AND  A1.y
A2 =     func1(1);      // undefined ('this' refers to 'window')
B1 = new func2(2);      // has B1.x  ONLY
B2 =     func2(2);      // has B2.x  ONLY

dla mnie, o ile nie prototypuję, używam stylu func2, ponieważ daje mi to trochę więcej elastyczności wewnątrz i na zewnątrz funkcji.


3
2017-10-29 21:38



B1 = new func2(2);<- Dlaczego tego nie będzie B1.y  ? - sunny_dev
@sunny_dev Nie jestem ekspertem od JS, ale prawdopodobnie dlatego func2 zwraca bezpośrednio wartość (obiekt z), zamiast pracować / zwracać z wartościami wewnętrznymi (this) - Eagle


The new słowo kluczowe służy do tworzenia nowych instancji obiektów. I tak, javascript jest dynamicznym językiem programowania, który obsługuje paradygmat programowania obiektowego. Konwencja dotycząca nazewnictwa obiektu jest, zawsze używaj dużej litery dla obiektów, które mają być tworzone za pomocą nowego słowa kluczowego.

obj = new Element();

2
2017-10-05 02:28