Prototípus a JavaScript-ben: furcsa, de a következőképpen működik

A következő négy sor elegendő a legtöbb JavaScript-fejlesztő megzavarásához:

Object instanceof Function//true
Object instanceof Object//true
Function instanceof Object//true
Function instanceof Function//true

A JavaScript prototípusa az egyik leggondolkodtatóbb fogalom, de nem kerülheti el. Nem számít, mennyire figyelmen kívül hagyja, a prototípus puzzle-val a JavaScript élete során találkozhat.

Szóval nézzünk szembe azzal.

Az alapoktól kezdve a következő adattípusok vannak a JavaScript-ben:

  1. meghatározatlan
  2. nulla
  3. szám
  4. húr
  5. logikai érték
  6. tárgy

Az első öt primitív adattípus. Ezek tárolnak egy típusú értéket, például logikai értéket, és lehetnek igazak vagy hamisak .

Az utolsó „objektum” egy referencia típus, amelyet kulcs-érték párok gyűjteményeként írhatunk le (de sokkal több).

A JavaScript-ben új objektumok készülnek az Object constructor függvény (vagy objektum literál {}) használatával, amely olyan általános módszereket biztosít, mint a toString()és valueOf().

A JavaScript funkciói olyan speciális objektumok, amelyek „ meghívhatók” . Ezeket a Function constructor függvény (vagy a literal függvény) használatával készítjük el. Az a tény, hogy ezek a konstruktorok objektumok, valamint funkciók, mindig megzavart engem, ugyanúgy, ahogy a csirke-tojás rejtvény is összezavar mindenkit.

Mielőtt a prototípusokkal kezdem, szeretném tisztázni, hogy a JavaScript-ben két prototípus létezik:

  1. prototípus : Ez egy speciális objektum, amelyet a JavaScript bármely funkciójának tulajdonságaként rendelünk hozzá. Tisztázzuk itt, hogy ez már létezik minden ön által készített funkciónál, de nem kötelező a JavaScript által biztosított belső funkciókhoz (és a függvények által visszaadott bind). Ez prototypeugyanaz az objektum, amelyre a[[Prototype]](lásd alább) az adott funkcióból újonnan létrehozott objektumot ( newkulcsszó használatával ).
  2. [[Prototípus]]: Ez egy valahogy elrejtett tulajdonság minden objektumon, amelyhez a futó kontextus hozzáfér, ha valamilyen tulajdonság, amely az objektumon olvasható, nem érhető el. Ez a tulajdonság egyszerűen aprototypeannak a függvénynek, amelyből az objektum készült. Ez szkriptben érhető el speciális getter-setter (egy másik nap témája) néven __proto__. Vannak más új módszerek is a prototípus elérésére, de a rövidség kedvéért utaltam rá[[Prototype]]felhasználásával __proto__.
var obj = {}var obj1 = new Object()

A fenti két állítás egyenlő állítás, ha új objektum létrehozására használják, de sok minden történik, ha végrehajtjuk ezen állítások bármelyikét.

Amikor új tárgyat készítek, az üres. Valójában nem üres, mert aObjectkonstruktor, és eredendően kap referenciát prototypenak,-nek Object,amelyre a __proto__az újonnan létrehozott objektum.

Ha megnézzük a prototypeA Objectkonstruktor függvényt, úgy néz ki, ugyanaz, mint a __proto__A obj. Sőt, ők két pointert hivatkozva ugyanazt a tárgyat.

obj.__proto__ === Object.prototype//true

Minden prototypefüggvényvan egy benne rejlő tulajdonsága, constructoramely maga a függvény mutatója. Abban az esetben, Objectfunkció , a prototypemárconstructoramely vissza mutat Object.

Object.prototype.constructor === Object//true

A fenti képen a bal oldal a Objectkivitelező kibővített nézete . Biztosan kíváncsi arra, hogy mi ez a többi funkció rajta. Nos, a függvények objektumok , tehát tulajdonságaik lehetnek felettük, mint más objektumok.

Ha alaposan megnézed, maga a Object(bal oldalon) rendelkezik a__proto__ami azt jelenti Objectvalamilyen más konstruktorról kellett készülnie, amelynek prototype. As-ja vanObjectfüggvényobjektum, használatával kell elkészíteni Functionkonstruktőr.

__proto__nak,-nek Objectugyanúgy néz ki, mint prototypea Function. Amikor ellenőrzem mindkettő egyenlőségét, kiderül, hogy ugyanazok a tárgyak.

Object.__proto__ === Function.prototype//true

Ha alaposan megnézi, látni fogja a Functionönmagában van egy __proto__ami azt jelenti Functionkonstruktor funkcióvalamilyen konstruktor függvényből kellett készülnie, amelynek a prototype. MintFunctionmaga egy függvény , felhasználásával kell elkészíteniFunctionkivitelező, vagyis maga. Tudom, hogy ez furcsán hangzik, de ha megnézed, kiderül, hogy igaz.

A __proto__a Functionésprototypenak,-nek Functionvannakvalójában két mutató utal ugyanarra az objektumra.

Function.prototype === Function.__proto__\\true

Mint korábban említettük, a constructorbármelyikprototypemutatnia kell annak a funkciónak, amely ezt birtokolja prototype.A constructornak,-nek prototypenak,-nek Functionmutat vissza Functionönmagára.

Function.prototype.constructor === Function\\true

Ismét a prototypenak,-nek Functionvan egy __proto__. Nos, ez nem meglepő ... prototypeegy tárgy, lehet. De vegye észre azt is, hogy aprototypeof Object.

Function.prototype.__proto__ == Object.prototype\\true

Tehát itt van egy főtérképünk:

instanceof Operatora instanceof b

Ainstanceofoperátor megkeresi az objektumot b- mutatott rábármelyik constructor(ek) a szénláncú__proto__tovább a. Olvassa el újra! Ha talál ilyen hivatkozást, visszatértruemás false.

Most visszatérünk az első négyünkhöz instanceofnyilatkozatok. Megfelelő nyilatkozatokat írtaminstanceofVisszatérés truea következőnek:

Object instanceof FunctionObject.__proto__.constructor === Function
Object instanceof ObjectObject.__proto__.__proto__.constructor === Object
Function instanceof FunctionFunction.__proto__.constructor === Function
Function instanceof ObjectFunction.__proto__.__proto__.constructor === Object

Phew !! Még a spagetti is kevésbé kusza, de remélem, hogy most már egyértelműbbek a dolgok.

Itt van valami, amit nem korábban jelezte, hogy prototypeaObjectnincs a __proto__.

Valójában van egy __proto__de ez egyenlő null. A láncnak valahol véget kellett vetnie, és itt ér véget.

Object.prototype.__proto__\\null

A Object, Function,Object.prototype ésFunction.prototypetulajdonságokkal is rendelkeznek, amelyek funkciók, mint például Object.assign,Object.prototype.hasOwnProperty ésFunction.prototype.call. Ezek olyan belső függvények, amelyek nem rendelkeznek, prototypeés azok Functiona__proto__ami mutató Function.prototype.

Object.create.__proto__ === Function.prototype\\true

Megvizsgálhatja a konstruktor egyéb funkcióit, például a ArrayésDate, vagy vegye el tárgyaikat és keresse meg a prototypeés__proto__. Biztos vagyok benne, hogy meg tudja tudni, hogyan kapcsolódik minden.

Extra lekérdezések:

Van még egy kérdés, hogy a poloska nekem egy darabig: Miért van az, hogy prototypeaz Objecta tárgy , és prototypeaz Functionis függvény objektum ?

Ittjó magyarázat rá, ha ugyanúgy gondoltál.

Egy másik kérdés, amely eddig rejtélyt jelenthet számodra: Hogyan kapják meg a primitív adattípusok a hasonló funkciókat toString(),substr() és toFixed()?Ez jól magyarázza itt .

Használatával prototypeaz öröklést működtethetjük egyedi objektumainkkal JavaScript-ben. De ez egy másik nap témája.

Köszönöm, hogy elolvasta!