Javascript endrer dynamisk objekter. JavaScript-objekter etter eksempel. La oss iterere over egenskapene våre

Oppgaven :

1. Det er tre objekter (tre biler): første_bil, andre_bil og tredje_bil.

2. Hvert av objektene (biler) har et sett med egenskaper og deres tilsvarende verdier (kjøretøyets egenskaper).

3. Tenk på ett av objektene:

var first_Car = (
make: "VAZ",
/* produsent */
modell: 2106,
/ * modell * /
år: 1980,
/* utstedelsesår */
farge: "beige",
/* Farge */
passasjerer: 5,
/ * antall passasjerer * /
cabriolet: falsk,
/ * cabriolet * /
kjørelengde: 80 000
/* kilometerstand */
}

Egenskaper gjøre og farge har strengverdier;

Egenskaper modell, år, passasjerer og kjørelengde- numeriske verdier;

Eiendom cabriolet tar en boolsk verdi.

Du må gjøre følgende:

Skriv en funksjon som sjekker bilen med to parametere (produksjonsår og kjørelengde) og returnerer en boolsk verdi ekte eller falsk.

Detaljer:

1. Funksjonen har én parameter bil, i egenskap av at den mottar en av de 3 objektene. For eksempel bilen omtalt ovenfor første_bil.

2. Funksjonen skal fungere med et hvilket som helst lignende objekt.

Funksjon for å sjekke et objekt - sant eller usant

Kommentarer til løsningen:

  • Så vi har tre objekter (tre biler), som hver kan analyseres ved hjelp av funksjonen bra_bil.
  • Funksjon bra_bil har én parameter bil, som kan være hvilken som helst av objektene (biler): første_bil, andre_bil eller tredje_bil: funksjon bra_Bil (bil) .
  • I kroppsfunksjoner bra_bil det er utarbeidet et vilkår om at:

    Dersom eiendomsverdien år gjenstand bil mindre enn 2000 (med andre ord: hvis produksjonsåret for bilen er mindre enn 2000) så kommer funksjonen tilbake falsk;

    Ellers hvis eiendomsverdien kjørelengde gjenstand bil mer enn 50 000 (hvis kjørelengden til bilen er mer enn 50 000) så kommer funksjonen tilbake falsk;

    Ellers returnerer funksjonen ekte.

  • Deretter kaller vi funksjonen og spesifiserer objektet som en parameter tredje_bil(tredje bil) som består testen. Resultatet av funksjonen lagres i en variabel resultat:
    var resultat = god_bil (tredje_bil); .
  • Variabel resultat vises på skjermen;
  • To andre objekter (bil) vil ikke oppfylle kravene i betingelsen.

Optimalisering av koden din

La oss fortsette arbeid med objekter i javascript.

Så funksjonen ovenfor når du sjekker objekter (biler) gir som et resultat ekte eller falsk (sant eller usant).

Det er mulig å forbedre kvaliteten på oppfatningen av løsningen av det vurderte problemet litt, det vil si i stedet for ekte eller falsk vise hvilken som helst tekst. For å gjøre dette vil vi lage en betingelse for å analysere resultatet.

Betinget løsning for resultat - Resultat ...

Betingelsen for å analysere resultatet er satt sammen som følger.

  • Uttrykk hvis (resultat) er en forkortet uttrykksform
    hvis (resultat == sant) .
  • Hvis resultatet av funksjonen bra_bil er sant ekte, så viser vi uttrykket: «Du har en god bil: 2012 produksjonsår, med kjørelengde 15000 km.", hvor

    2012 og 15000 er eiendomsverdier år og kjørelengde gjenstand tredje_bil.

  • Hvis betingelsen for å sjekke resultatet vil returnere en falsk verdi falsk, så vil vi se: "Vi vil ikke snakke om bilen din ....". Det vil si den aktuelle gjenstanden (bil) mislykket verifisering.

Kodeoptimalisering - Gå videre - Legge til en funksjon

Men det er ikke alt. Ta en nærmere titt på kodebiten for å kalle funksjonen og analysere resultatet:

/ * Kalle opp funksjonen og analysere resultatet * /
var resultat = god_bil ( tredje_bil );

hvis (resultat) (
document.write ("Du har en fin bil:" + tredje_Bil .år + "produksjonsår, med kjørelengde" + tredje_Bil .mileage + "km.");
}
annet (
document.write ("La oss ikke snakke om bilen din ....");
}

Her gjenstanden tredje_bil (tredje bil) er angitt tre ganger:

  • Første gang du ringer en funksjon bra_bil den er spesifisert som parameteren: god_bil (tredje_bil) .
  • Og så vises det to ganger til når vi refererer til det for å indikere dets egenskaper: tredje_Bil.år og third_Car.mileage .

Jeg likte ikke dette, fordi når jeg analyserte et annet objekt (bil) vi får navnet hans også angi tre ganger!!!

For å oppnå en engangsindikasjon av det analyserte objektet trenger du også resultatet av funksjonen bra_bil og analyse av dette resultatet (det vil si helheten) legge til en annen funksjon.

Løsning med en funksjon til - Resultat ...

Du har en god bil: 2012, med 15 000 km kjørelengde.

Et besøk på en nettressurs er en spesifikk URI i adressefeltet til nettleseren. Den besøkende angir adressen til siden, og den analyseres av nettleseren til elementer i DOM-treet - Document Object Model. Enhver kobling på den siden forteller nettleseren å analysere en annen side og bygge et nytt tre med objekter.

Nettleseren lar den besøkende gå tilbake eller gå fremover gjennom en kjede av sider som allerede har blitt vist i den gjeldende økten.

Faktisk beveger brukerhandlinger seg mellom systemer med objekter som dannes i prosessen med å besøke sider. Hver side er sitt eget DOM-tre, og i tillegg er JavaScript-objekter objekter av syntaksen til selve språket og tilpassede beskrivelser.

DOM: lasting, oppdatering og endring

Det er tre hovedalternativer som utgjør objektene til nettressurssiden, både på DOM-nivå og selve JavaScript-språket, som utførte konstruksjonene for å lage variabler, og basert på beskrivelsene laget av utvikleren:

  • lasting - den besøkende kom til sidesiden;
  • oppdatering - besøkende (nettleserknapp eller Ctrl-F5);
  • endre et sideelement, for eksempel (AJAX, script, event, ...).

Alle tre prosessene er fundamentalt forskjellige, men det er spesielt viktig å skille trekk ved de to første. Det er vanskelig å hindre en besøkende i å oppdatere siden – dette er en uutryddelig besøksavhengighet som en utvikler bør huske på.

Navigering rundt på siden og utover bør utelukkende ligge i funksjonaliteten til selve siden, og ikke i historien til nettleserbesøk og funksjonene til knappene. Mange nettsteder erklærer dette viktige kravet, men besøkende bryter det tradisjonelt.

Å endre siden uten å laste på nytt på nivået til det individuelle elementet (for eksempel AJAX) er en vanlig løsning for dynamiske sider. Som regel brukes dette til å navigere gjennom elementene på siden, endre objektene, kontrollere dialogen med den besøkende.

Grunnleggende JavaScript-objekter

JavaScript er objektbasert. Nesten alle språkvariabler er objekter. Utvikleren kan formulere sine egne beskrivelser av objekter ved hjelp av en rekke syntakser.

Alt som ikke er en "streng", "tall", sant, usant, null eller udefinert, er et objekt. Innenfor rammen av språkets syntaks kan dette ignoreres, forståelse av objekter kun DOM-elementer og JavaScript Objects egne beskrivelser Den grunnleggende strukturen til språket har i de fleste tilfeller for utvikleren ingen vesentlig praktisk verdi.

For eksempel er matematiske funksjoner representert av Math-objektet. Dette er praktisk innenfor rammen av konseptet med språket, men for utvikleren er det bare en praktisk syntaks for å bruke det nødvendige arsenalet av matematiske operasjoner.

Det er viktig å jobbe riktig med DOM og beskrive dine egne objekter korrekt. Syntaksen til JavaScript-objektfunksjoner og uttrykk for å bruke dem er en form for å skrive logikken til den nødvendige algoritmen.

Strenger, matriser og objekter

Alle JavaScript-objekter er basert på regelen "property" = "value" og konseptet til en assosiativ matrise. På sitt enkleste er objekt-JavaScript en samling av egenskap = verdi-par. I dette tilfellet kan "verdien" ikke alltid være et tall, og eiendommen er ikke alltid skrevet uten anførselstegn.

Eiendomsnavn bør ikke brukes for mye. Ideelt sett, når egenskapsnavn bare inneholder latinske tegn, tilfredsstiller kravene til navngivingsvariabler og ikke er nøkkelord (inkludert reserverte) i språket.

Ingen egenskapsbestilling forventes, men når du oppretter eller initialiserer en assosiativ matrise, er det helt akseptabelt å vite hvordan elementene er ordnet. Det anbefales ikke å bruke denne omstendigheten, men det er mulig å huske på.

Å initialisere en rekke egenskaper betyr samtidig:

  • lage en matrise;
  • objektskaping.

I en spesifikk applikasjonskontekst kan du vurdere et JavaScript-objekt - som en assosiativ matrise, og andre steder i algoritmen - som et objekt, tilordne de nødvendige metodene til det, endre verdiene til elementene.

Siden egenskapsnavn og verdier må spesifiseres i strengformat når de opprettes eller endres, anbefales det at du bruker små bokstaver og anførselstegn.

Få tilgang til objektegenskaper

Du kan hente og endre verdiene til objektegenskaper med Object.keys-konstruksjonen: JavaScript danner en rekke av alle objektegenskaper. Når objekter opprettes dynamisk, er denne konstruksjonen veldig praktisk, fordi den automatisk genererer en liste over alle egenskapene i objektet.

I dette eksemplet er beskrivelsen av de to matrisene gjort på en annen måte. I bruk er begge matrisene likeverdige, siden de inneholder egenskaper med samme navn og deres verdier. Sløyfen itererer over alle egenskapene til den andre matrisen og danner en streng med alle verdier.

En lignende effekt kan oppnås med punktnotasjon eller parentesnotasjon:

  • x1_Obj .NameLast;
  • x1_Obj ["NameFirst"].

Begge konstruksjonene er gyldige og gir ønsket resultat. I det gitte eksemplet, når du spesifiserer en matrise gjennom krøllete klammeparenteser "()", kan det gjøres en feil i form av symbolet "," på slutten av oppregningen (merket i eksemplet med en rød sirkel). Nettlesere ignorerer vanligvis det ekstra tegnet i oppregningen, men det er best å la være.

Fjerner objektegenskaper

Siden et objekt er en assosiativ matrise, vil operasjonen JavaScript-sletteobjekt utføres på nivået til det gjeldende objektet (med arv - det betyr noe) og vises på samlingen av egenskapene til dette objektet.

I sammenheng med det gitte eksemplet kan du bruke følgende konstruksjoner:

  • slett x1_Obj .NameLast;
  • slett x2_Obj ["NameFirst"];

Den første konstruksjonen fjerner det andre elementet i det første objektet, den andre konstruksjonen fjerner det første elementet i det andre objektet. Slette-operatoren fungerer ikke på prototypeegenskaper og returnerer false hvis egenskapen ikke kan slettes.

Objektegenskaper og metoder

Syntaksen til JavaScript-objektegenskaper og -funksjoner (metoder) ligner på de generelle kanonene for syntaks og semantikk for språket. Faktisk er det motsatte sant.

Objektegenskaper og metoder er en variant av å beskrive informasjon og handlinger som er tillatt med den gjennom det objektorienterte JavaScript-paradigmet.

Dette eksemplet beskriver x3_Obj-objektet, som bare har to egenskaper: element og pos. Deretter ble hello ()-metoden lagt til som en funksjon. Som et resultat vil tolkningen av denne beskrivelsen i sammenheng med egenskapsverdier, JavaScript-objektverdier gjøre som vist i resultatvinduet, det vil si at den plasserer funksjonens kropp (1) som en verdi.

Når Hello ()-egenskapen kalles direkte, tolkes den som en metode (funksjon) og resultatet (2) vil være kjøringen av koden til denne metoden.

Dette nøkkelordet på et objekt

For å orientere seg i egenskapsrommet til et objekt, kan en utvikler bruke dette nøkkelordet og henvise gjennom det til egenskapene han beskriver for å få eller endre verdiene deres.

Dette er bare begynnelsen på å beskrive et objekt med bare en konstruktørkropp. Dette eksemplet beskriver et informasjonskapselobjekt. Objektet initialiseres på det tidspunktet siden lastes med konstruksjonen:

  • var oCookie = nye scCookies (coOwnerCode);
  • oCookie .Init ();

I dette eksemplet er cownerCode en unik besøks-ID. Hvis ikke, vil ny kode bli generert i konstruktøren til oCookie-objektet. Det spiller ingen rolle hva utvikleren av dette objektet mener med autorisasjon av den besøkende, det er viktig hvordan dette nøkkelordet brukes her for å beskrive metodene til objektet og kalle dem fra andre metoder for objektet:

  • denne .GetCookie = funksjon (cName) (...);
  • denne .SetCookie = funksjon (cName, cValue) (...).

Slik beskrives objektets metoder for å lese en informasjonskapsel ved navn og skrive verdien av en informasjonskapsel med et spesifikt navn.

  • denne .GetCookie ("medeier");
  • denne .SetCookie ("coOwner", cowner);

Så de brukes, hvis verdien ikke vil bli presentert som et resultat av den første konstruksjonen, setter den andre konstruksjonen den.

Eksempel på et informasjonskapselobjekt

Man kan diskutere objektets og det objektorienterte paradigmet til et språk som kjører i et nettlesermiljø. Dette er interessant, men virkeligheten er praksis, ikke teori. Å betjene DOM-en til en side, tilby et verktøysett for å manipulere objekter og navigere i objektsystemer er en sterk poeng. JavaScript.

I objektorientert praksis er noe annet viktig. Å jobbe med informasjonskapsler på nesten alle nettressurser er i rekkefølgen. Å implementere dette i et objektformat er en god idé. I denne sammenhengen skjer initialiseringen av objektet i det øyeblikket siden åpnes: siden er lastet inn = informasjonskapselobjektet eksisterer og har lest alt, og det som ikke ble - opprettet.

I prosessen med å jobbe med siden, utfører den besøkende visse handlinger og nettleseren må endre eller lage informasjonskapsler. Det er to objektmetoder (skissert ovenfor) som gjør dette.

Faktisk oppstår informasjonskapselobjektet umiddelbart etter at nettleseren bygger DOM og legger til ny funksjonalitet til JavaScript-objektsystemet: les og lag (endre) informasjonskapselen.

I dette enkle eksemplet betraktes det som en prosedyre for å lage virkelige objekter som utelukkende har sine egne egenskaper og funksjonalitet (metoder). Hvert objekt gjør jobben sin og deltar ikke i den generelle algoritmen, endrer ikke dataene til andre objekter eller det generelle navneområdet.

Med denne tilnærmingen sikrer utvikleren opprettelsen av et system med unike objekter som er tilstrekkelig til å beskrive og vedlikeholde problemet som løses.

Side- og objekthendelser

Et viktig element i funksjonen til DOM og JavaScript: objekthendelse "s - lar deg få informasjon om en hendelse i sin behandler. Nesten hvert element på siden kan tildeles sin egen behandler for en eller flere hendelser.

Faktisk lager en JavaScript-utvikler ikke en stor "bit" kode, men mange beskrivelser av funksjoner, objekter, datastrukturer og tildeler hendelsesbehandlere til spesifikke sideelementer.

Objekthendelse er informasjon om hendelsen som forårsaket behandleren og dennes evne til å utføre en adekvat respons på denne hendelsen. Hver hendelse er forskjellig ikke bare i navn og sted for forekomsten, men også i mange andre parametere.

Spesielt er tastaturhendelser ett sett med parametere, musehendelser er et helt annet dataområde, og serverresponsen via AJAX er fullstendig planlagt av utvikleren selv.

I hvert enkelt tilfelle blir bildet av hendelser som kan oppstå på siden forvandlet til en rekke inkluderte behandlere; utenom de planlagte alternativene for å håndtere et spesifikt sett med hendelser, foretar ikke siden noen handling.

Objektskaping og drift

Nettleseren "forvandler" URI, adressen til nettressursen spesifisert av den besøkende, til et DOM-tre - systemet med sideobjekter til denne nettressursen. Når den besøkende beveger seg gjennom koblingene på siden, navigerer nettleseren til de tilsvarende trærne på andre sider.

Denne omstendigheten tillater utvikleren å bygge sitt eget system av objekter som grunnlaget for en nettressurs som reagerer adekvat på oppførselen til den besøkende. Hvis vi trekker frem den generelle funksjonaliteten, for eksempel:

  • arbeid med informasjonskapsler;
  • mottak / overføring av data (AJAX);
  • popup-tips;
  • interne meldinger (nettstedchat);
  • andre oppgaver;

når de er opprettet, kan objektsystemer brukes til å utvikle andre nettsteder. Dette er en betydelig fordel med objekttilnærmingen fremfor vanlig bruk av JavaScript som nettleserspråket som sørger for funksjonen til siden og reaksjonen på hendelser.

Objekter er komplette komponenter som kan styles som separate filer og brukes senere. Et karakteristisk trekk ved denne tilnærmingen er muligheten for tilbakemelding når et oppdatert, forbedret objekt kan brukes i en tidligere utvikling, og automatisk oppdaterer funksjonaliteten uten å endre nettstedet.

I denne artikkelen ønsker jeg å snakke så fullstendig og konsekvent som mulig om hva et objekt er i JavaScript, hva dets evner er, hvilke relasjoner som kan bygges mellom objekter og hvilke metoder for "native" arv som følger av dette, hvordan det hele påvirker ytelse og hva gjør det hele :)

Artikkelen vil IKKE si et ord om: emulering av det tradisjonelle klasseobjekt-paradigmet, syntaktisk sukker, innpakninger og rammer.

Kompleksiteten til materialet vil øke fra begynnelsen til slutten av artikkelen, så for proffene kan de første delene virke kjedelige og trivielle, men videre vil det være mye mer interessant :)

Objekter i JavaScript

Mange artikler inneholder uttrykket "I JavaScript er alt et objekt." Teknisk sett er dette ikke helt sant, men det gjør det riktige inntrykket på nybegynnere :)

Faktisk er mye i et språk et objekt, og selv det som ikke er et objekt kan ha noen av sine evner.

Det er viktig å forstå at ordet "objekt" brukes her ikke i betydningen "et objekt av en viss klasse." Et objekt i JavaScript er først og fremst bare en samling egenskaper (hvis det er lettere for noen, kan du kalle det en assosiativ matrise eller en liste), bestående av nøkkelverdi-par. Dessuten kan nøkkelen bare være en streng (selv for matriseelementer), men verdien kan være en hvilken som helst datatype som er oppført nedenfor.

Så det er 6 i JavaScript grunnleggende typer data er Udefinert (angir ingen verdi), Null, boolsk (boolsk), streng (streng), tall (tall) og objekt (objekt).
Dessuten er de 5 første primitiv datatyper, men Object er det ikke. I tillegg kan man konvensjonelt anta at objekttypen har "undertyper": en array (Array), en funksjon (Function), et regulært uttrykk (RegExp) og andre.
Dette er en noe forenklet beskrivelse, men i praksis er det som regel tilstrekkelig.

I tillegg er de primitive typene String, Number og Boolean på en eller annen måte assosiert med de ikke-primitive "undertypene" av Object: henholdsvis String, Number og Boolean.
Dette betyr at strengen "Hello, world", for eksempel, kan lages både som en primitiv verdi og som et objekt av typen String.
Kort fortalt er dette gjort slik at programmereren kan bruke metoder og egenskaper når han arbeider med primitive verdier som om de var objekter. Du kan lese mer om dette i den tilsvarende delen av denne artikkelen.

Arbeid etter referanse

En lenke er en måte å få tilgang til et objekt under forskjellige navn. Arbeid med eventuelle gjenstander utføres utelukkende ved referanse.
La oss demonstrere dette med et eksempel:
test = funksjon () (varsel ("Hei!")) // Lag en funksjon (varsel ("Hallo!")) (Og funksjonen, som vi husker, er et fullverdig objekt) og gjør testvariabelen til en referanse til den
test_link = test; // test_link refererer nå også til funksjonen vår
test (); // Hallo!
test_link (); // Hallo!


Som vi kan se, gir både den første lenken og den andre samme resultat.
Det er nødvendig å innse at vi ikke har noen funksjon som heter test, og at testvariabelen ikke er en slags "main" eller "main" link, og "test_link" er en mindre.

Vår funksjon, som alle andre objekter, er bare et område i minnet, og alle referanser til dette området er helt likeverdige. Dessuten kan det hende at et objekt ikke har noen referanser i det hele tatt - i dette tilfellet kalles det anonymt, og kan bare brukes umiddelbart etter opprettelse (for eksempel sendt til en funksjon), ellers vil det være umulig å få tilgang til det og snart vil bli ødelagt av søppelsamleren (søppelhenting), som er det som sletter objekter uten referanser.

La oss se hvorfor det er så viktig å forstå dette:

test = (prop: "noe tekst") // Lag et objekt med en prop-egenskap
test_link = test; // Lag en annen lenke til dette objektet

Alert (test.prop); // litt tekst

// Endre egenskapen til objektet
test_link.prop = "ny tekst";

Alert (test.prop); // ny tekst
varsel (test_link.prop); // ny tekst
/ * Man kan si at eiendommen har endret seg her og der – men det er det ikke.
Objektet er ett. Så egenskapen har endret seg én gang i den, og lenkene fortsetter å peke dit de peker. * /

// Legg til en ny egenskap og fjern den gamle
test.new_prop = "hei";
slett test.prop;

Alert (test_link.prop); // undefined - denne egenskapen eksisterer ikke lenger
varsel (test_link.new_prop);

// Fjern lenken
slette test;
varsel (test.ny_prop);
/ * På dette tidspunktet vil skriptet gi en feil, fordi testen ikke lenger eksisterer, og test.new_prop eksisterer ikke desto mer * /
varsel (test_link.new_prop); // Hallo
/ * men her er alt i orden, fordi vi ikke slettet selve objektet, men bare en lenke til det. Nå blir objektet vårt pekt på med en enkelt lenke test_link * /

// Lag et nytt objekt
test = test_link; // Først oppretter du testlenken på nytt
test_link = (prop: "noen tekst") // Og her er det nye objektet

Alert (test_link.prop); // litt tekst
varsling (test.prop); // udefinert
/ * Oppretting av et nytt objekt bryter koblingen, og nå peker test og test_link til forskjellige objekter.
Faktisk er dette ensbetydende med å fjerne test_linken og lage den på nytt, men allerede peker til et annet objekt * /
varsel (test.ny_prop); // hei - nå inneholder testen en lenke til vårt aller første objekt


* Denne kildekoden ble uthevet med Source Code Highlighter.

Denne oppførselen til objekter reiser ofte mange spørsmål for nybegynnere, så jeg håper denne teksten vil bringe litt klarhet. Hvis vi ønsker å lage en virkelig ny, uavhengig kopi av objektet, og ikke en lenke, er den eneste måten å gjøre dette på å lage et nytt objekt og kopiere de nødvendige egenskapene dit.

Det er også verdt å merke seg at arbeid med objekter ved referanse, i tillegg til de ovennevnte morsomme effektene, også gir betydelige minnebesparelser, noe som er viktig når ett objekt er mye brukt på ulike steder i programmet.

Primitive verdier

Som jeg nevnte ovenfor, kan datatypene streng og tall være både objekter og primitive verdier.
obj = ny streng ("hei"); // Lag streng som objekt
enkel = "hei"; // Lag en primitiv verdi

Varsel (obj); // Hallo
varsling (enkel); // hei - så langt er alt forutsigbart

Alert (obj.length); // 6 - et objekt av typen String har en length-egenskap som lagrer lengden på strengen
varsel (enkel.lengde); // 6
/ * Selv om simple ikke er et objekt, kan vi få tilgang til det samme settet med egenskaper som et String-objekt. Dette er ganske praktisk * /

Obj.prop = "tekst";
simple.prop = "tekst";

Alert (obj.prop); // tekst - siden obj er et vanlig objekt, kan vi enkelt gi det en egenskap til
varsling (enkel.prop); // udefinert - men enkel er ikke et objekt, og dette tallet vil ikke fungere for oss

* Denne kildekoden ble uthevet med Source Code Highlighter.


Det samme gjelder både Number og Boolean (vel, foruten det faktum at de ikke har en lengdeegenskap, men det finnes en rekke andre fantastiske egenskaper).
Å bruke strenger og tall som objekter har ingen praktisk nytte. primitive verdier er mer praktiske å jobbe med, men beholder samtidig all nødvendig funksjonalitet. For fullstendighetens skyld er det imidlertid nødvendig å forstå denne mekanismen.

Ikke forveksle bruken av primitive verdier med bruken av bokstaver - for eksempel, uavhengig av om vi oppretter en matrise som "test = new Array ()" eller som "test =", vil resultatet fortsatt være det samme objektet . Vi vil ikke få noen primitive verdier.

Opprette og bruke objekter

Så, i motsetning til språk der klasse-objekt-paradigmet er implementert, trenger vi ikke å lage en klasse først, deretter lage et objekt av klassen. Vi kan umiddelbart lage et objekt, noe vi vil gjøre i følgende eksempel:
test = (
simple_property: "Hei",
objektegenskap: (
user_1: "Petya",
user_2: «Vasya»
},
function_property: funksjon (bruker) (
varsel (denne .simple_property + "," + denne .object_property);
}
}

Test.function_property ("bruker_1"); // Hei, Petya.

* Denne kildekoden ble uthevet med Source Code Highlighter.


Foran oss er testobjektet, som har 3 egenskaper, hvis navn, håper jeg, taler for seg selv. Det som interesserer oss mest med det, er funksjonen egenskapen egenskapen, som inneholder funksjonen. En slik funksjon kan kalles en metode for et objekt.

Vår funksjon bruker dette nøkkelordet to ganger, som er en peker (dvs. en referanse) til objektet som funksjonen kalles fra. Dermed, this.simple_property = test.simple_property = "Hei", og this.object_property = test.object_property = "Peter".

Det skal forstås tydelig at dette alltid refererer til objektet som funksjonen kalles fra, og ikke til objektet den tilhører. Selv om disse er det samme objektet i dette eksemplet, er dette ikke alltid tilfelle.

test.function_property ("bruker_1"); // Hei, Petya.

Test2 = nytt objekt (); // En annen form for å lage et nytt objekt, lik test2 = ()

Test.function_property.call (test2, "bruker_1"); //feil
/ * Anropsmetoden lar deg kalle en funksjon på vegne av et annet objekt. I dette tilfellet kaller vi function_property-metoden til testobjektet, og denne peker ikke lenger til testobjektet, men til test2-objektet. Og siden den har ikke egenskapen object_property, så når du prøver å få this.object_property, vil skriptet gi en feilmelding * /

// prøv å fikse situasjonen
test2.simple_property = "God dag";
test2.objekt_egenskap = test.objekt_eienskap; // I dette tilfellet vil vi bruke å spesifisere objektet ved referanse for ikke å duplisere koden

Test.function_property.call (test2, "bruker_1"); // God dag, Petya.


* Denne kildekoden ble uthevet med Source Code Highlighter.

Det bør også fremgå av eksemplet at det ikke er noen klare trinn for å lage og bruke et objekt. Objektet kan endres på hvilken som helst måte når som helst - før, etter og til og med under bruk. Dette er også en viktig forskjell fra «tradisjonell» OOP.

Konstruktør

I eksemplet ovenfor har vi laget 2 objekter som har noen likheter. Både simple_property og object_property egenskaper var til stede. Åpenbart, når du skriver ekte kode, oppstår ofte oppgaven med å lage identiske eller bare lignende objekter. Og selvfølgelig trenger vi ikke å lage alle slike objekter manuelt.

En konstruktør vil hjelpe oss. En konstruktør i JavaScript er ikke en del av en klasse (fordi det ikke er noen klasser), men bare en funksjon i seg selv. Den vanligste funksjonen.

make_me = funksjon (_navn) (
varsel ("Jeg ble lansert");
dette .navn = _navn;

}


/ * La oss se hva som skjer her. Tolken ser den nye operatøren og sjekker hva som står til høyre for den. Fordi make_me er en funksjon, og den kan brukes som en konstruktør, så opprettes et nytt objekt i minnet og make_me-funksjonen utføres, og dette peker til dette nye objektet. Deretter legges dette objektet til egenskapen name, som tildeles verdien fra _name-argumentet, og vis_navn-metoden. Dessuten (jeg vet ikke i hvilket øyeblikk, men det spiller ingen rolle) barnevariabelen begynner å peke på vårt nye, nettopp-fødte objekt * /

Alert (barn.navn); //Vasya
child.show_name (); //Vasya


barn2.vis_navn (); //Peter

Child2.show_name = funksjon () (varsel ( "Jeg vil ikke si navnet mitt");} // Ikke glem at vi kan endre objektene våre når som helst
barn2.vis_navn (); // Jeg vil ikke si navnet mitt

Child.show_name (); // Vasya - barn påvirker ikke hverandre på noen måte


* Denne kildekoden ble uthevet med Source Code Highlighter.

Du kan også sammenligne konstruktøren med en far - han føder et barn, og gir ham visse egenskaper, men umiddelbart etter opprettelsen blir barnet helt uavhengig av forelderen og kan bli veldig forskjellig fra brødrene sine.
Hvis vi husker beskrivelsen av datatyper i begynnelsen av artikkelen, blir det klart at Objekt og dets undertyper (Function, Array og andre) faktisk er konstruktører som gir det opprettede objektet egenskapene til en funksjon, en matrise, etc.

Så dette er mye bedre. Vi har nå muligheten til å lage objekter etter et bestemt mønster. Imidlertid er ikke alt bra. For det første tar hvert objekt vi lager og alle dets egenskaper og metoder en egen plass i minnet, selv om de på mange måter gjentas. For det andre, hva om vi ønsker å bevare forbindelsen mellom forelder og barn, og kunne endre alle barneobjekter på en gang. En prototype vil komme oss til unnsetning.

Prototype

Akkurat som hvert barn har en far og en mor (i det minste biologisk), så har alle objekter i JavaScript. Og hvis faren, som vi bestemte, jobber som designer, så er moren bare en prototype. La oss se hvordan dette skjer:
make_me = funksjon (_navn) (
varsel ("Jeg ble lansert");
dette .navn = _navn;
denne .vis_navn = funksjon () (varsel (dette .navn);)
}
/*
Når tolken ser funksjonsnøkkelet, sjekker koden til høyre for det, og siden alt er ok - det skaper et nytt objekt i minnet, som også er vår funksjon. Deretter opprettes automatisk (uten deltakelse fra programmereren) en prototype-egenskap for denne funksjonen, som refererer til et tomt objekt. Hvis vi gjorde det manuelt, ville det se ut som make_me.prototype = new Object ();

Deretter blir det gitte objektet (pekt på av prototype-egenskapen) også automatisk lagt til med en konstruktør-egenskap som peker tilbake til funksjonen. Det viser seg at dette er en sirkulær lenke.

Nå er dette objektet, som kan beskrives som (konstruktør: ... her er en referanse til funksjonen ...) - funksjonsprototypen.
*/

// Objekt er egentlig et objekt
varsel (type av make_me.prototype.constructor); // Funksjon er vår funksjon
varsel (make_me.prototype.constructor === make_me); // sant

// Legg til en ny metode til prototypen av make_me-funksjonen

Child = new make_me ("Vasya"); // de lanserte meg
/ * Nå, i tillegg til alt beskrevet i forrige eksempel, opprettes en ekstra skjult egenskap [] i underordnet objekt, som peker til det samme objektet som make_me.prototype. Fordi eiendommen er skjult, vi kan verken se dens verdi eller endre den - den spiller imidlertid en viktig rolle i det videre arbeidet * /

Alert (barn.navn); //Vasya
child.show_name (); //Vasya

Child.set_name ("Kolya");
/ * Først ser tolkeren etter set_name-metoden på underordnet objekt. Siden den ikke er der, fortsetter den å søke etter barnet [] Eiendom, finner den der og kjører den. * /
child.show_name (); // Kolya - nå heter Vasya Kolya :)

Make_me.prototype.show_name2 = funksjon () (varsel ("Hei," + dette .navn;) //T.k. prototypen er et vanlig objekt, vi kan også endre det med en gang

Child2 = new make_me ("Petya");
barn2.vis_navn2 (); // Hei, Petya
child.show_name2 (); // Hei Kolya - endringer i prototypen påvirker ikke bare nyopprettede objekter, men også alle gamle

Barn2.vis_navn2 = funksjon () (varsel ( "Jeg vil ikke si navnet mitt");} // Vi kan fortsatt endre selve objektet, mens den nye metoden show_name2 i dette objektet (og bare i det) så å si vil "overskrive" den gamle metoden fra prototypen
barn2.vis_navn2 (); // Jeg vil ikke si navnet mitt - fordi vi har nå vår egen show_name2-metode, så kalles den, og ingen søk i prototypen forekommer

Child.show_name2 (); // Hei, Kolya - alt er fortsatt her

Make_me.prototype = (rekvisitt: "hei") // La oss prøve å gjenskape prototypen igjen

Alert (barn.prop); // udefinert
child.show_name2 (); //Hei Kolya
/ * Hvis du husker hva arbeid ved referanse er, så er alt klart. Gjenoppretting av prototypen bryter forbindelsen, og nå peker []-egenskapen til child- og child2-objektene til ett objekt (som var prototypen til make_me-funksjonen), og make_me.prototype-egenskapen til et annet objekt, som er det nye. prototype av make_me-funksjonen * /

Child3 = new make_me ("Oleg");
varsling (barn3.prop); // hei - som forventet


* Denne kildekoden ble uthevet med Source Code Highlighter.

Som man kan se fra eksemplet, mens faren forblir trofast mot moren (dvs. mens prototypen av funksjonen forblir den samme), er alle barn avhengige av moren og er følsomme for alle endringer i henne. Men så snart foreldrene blir skilt (designeren endrer prototypen til en annen), sprer barna umiddelbart hvem hvor og det er ikke lenger noen forbindelse med dem.

Litt om terminologi
Inntil den primære forbindelsen mellom konstruktøren og prototypen er brutt, kan vi observere følgende bilde:

make_me = funksjon (_navn) (
varsel ("Jeg ble lansert");
dette .navn = _navn;
denne .vis_navn = funksjon () (varsel (dette .navn);)
}

Make_me.prototype.set_name = funksjon (_navn) (dette .navn = _navn;)
barn = ny make_me ("Vasya");

Alert (type av make_me.prototype); // objekt - funksjonen har en prototype-egenskap
varsel (type av barn. prototype); // undefined - det opprettede objektet har INGEN prototype-egenskap
varsel (child.constructor.prototype === make_me.prototype); // true - men objektet har en konstruktør-egenskap, som peker på make_me-konstruktørfunksjonen, som igjen har en prototype-egenskap


* Denne kildekoden ble uthevet med Source Code Highlighter.

Som jeg la merke til etter å ha lest en rekke fora om dette emnet, er hovedproblemene folk får når de forveksler prototypeegenskapen til en funksjon og den skjulte [] egenskapen til et objekt opprettet med den funksjonen.
Begge disse egenskapene er referanser til det samme objektet (så lenge den primære koblingen mellom prototypen og konstruktøren ikke er brutt), men de er likevel forskjellige egenskaper, med forskjellige navn, en av dem er tilgjengelig for programmereren, og andre er ikke.

Det er alltid nødvendig å tydelig forstå at hvis vi snakker om prototypen til en konstruktør, så er dette alltid prototypeegenskapen, og hvis om prototypen til det opprettede objektet, så er dette en skjult egenskap [].

Arv

Vi vet nå at hvert objekt har en skjult prototypereferanse, og hver prototype er et vanlig objekt.
De mest oppmerksomme leserne har allerede fanget lukten av rekursjon :)
Faktisk siden en prototype er et vanlig objekt, så har den på sin side en kobling til prototypen sin, og så videre. Slik implementeres prototypehierarkiet.
fugl = funksjon () () // Dette er birdie-konstruktøren
bird.prototype.cry = funksjon () (varsling ("Cree!");) // Fuglen kan skrike
bird.prototype.fly = funksjon () (varsling ("Jeg flyr!");) // og fly

And = funksjon () ()
duck.prototype = ny fugl ();
duck.prototype.cry = funksjon () (varsel ("Quack quack!");) // Anda skriker annerledes
duck.prototype.constructor = and; // Tving egenskapen prototype.constructor til å settes til duck, fordi ellers vil det referere til fugl

Billy = ny and (); // Billy er anda vår
billy.fly (); //Jeg flyr! – Billy kan fly fordi han er en fugl
billy.cry (); //Kvakk KVAKK! – Billy skriker kvakksalver fordi han er en and


* Denne kildekoden ble uthevet med Source Code Highlighter.

På denne måten kan du implementere et hierarki av ethvert hekkenivå.

Asterisk problem

Nå, siden vi vet så mye om alt dette, la oss prøve å finne ut hvor mye som skjer på disse tre linjene.
make_me = funksjon () ()
barn = ny make_me ();
varsel (child.toString ()); // utganger

* Denne kildekoden ble uthevet med Source Code Highlighter.

På den første linjen lager vi en ny funksjon og en make_me-variabel som peker til denne funksjonen. Dette lager en prototype for funksjonen, make_me.prototype, som inneholder en konstruktør-egenskap som peker til make_me.
Men det er ikke alt :)
Fordi make_me-funksjonen er også et objekt, da har den på sin side en pappa og en mamma, dvs. konstruktør og prototype. Konstruktøren er en innebygd funksjon av funksjonsspråket () og prototypen er et objekt som inneholder metoder for kall, applikasjon, etc.. – det er takket være denne prototypen at vi kan bruke disse metodene i enhver funksjon. Dette gir make_me-funksjonen en []-egenskap som peker til Function.prototype.

I sin tur er prototypen til funksjonskonstruktøren også et objekt, hvis konstruktør er (overraskelse!) Objekt (dvs. Funksjon.prototype. []. Konstruktør === Objekt), og prototypen er et objekt som inneholder standardegenskapene og metoder for objektet, slik som toString, hasOwnProperty og andre (med andre ord - Function.prototype. [] ["hasOwnProperty"] - dette er nøyaktig samme metode som vi kan bruke i alle avledede objekter - og dette er nøyaktig egen metode for dette objektet, og ikke arvet ). Slik finner vi ut på en interessant måte at alle slags objekter er avledet fra Objekt.

Kan vi fortsette videre? Det viser seg ikke. Object.prototype inneholder de grunnleggende egenskapene til et objekt nettopp fordi det ikke har sin egen prototype. Object.prototype [] = Null; På dette tidspunktet stopper reisen gjennom prototypekjeden for å finne en eiendom eller metode.

Et annet interessant faktum er at konstruktøren av objektet er funksjon. De. Objekt []. Konstruktør === Funksjon.
Det er en annen sirkulær referanse - konstruktøren for Object er Function, og konstruktøren for Function.prototype er Object.

La oss gå tilbake til vårt eksempel. Vi har allerede forstått hvordan funksjonen er opprettet, la oss nå gå videre til den andre linjen. Der lager vi et barneobjekt hvis konstruktør er make_me-funksjonen og prototypen er make_me.prototype.

Vel, i tredje linje ser vi hvordan tolken går opp i kjeden, fra barn til barn [] (Aka make_me.prototype), deretter til barn []. [] (Aka Object.prototype), og allerede der finner toString-metoden, som lanseres for kjøring.

Urenheter

Det kan virke som om arv via prototyper er den eneste måten JavaScript er mulig på. Dette er ikke sant.
Vi har å gjøre med et veldig fleksibelt språk som ikke gir så mye regler som muligheter.

For eksempel, hvis vi vil, kan vi ikke bruke prototyper i det hele tatt, men programmere ved å bruke konseptet mixins. Til dette vil våre gode gamle venner - konstruktører være nyttige for oss.

// Dette er en menneskelig konstruktør
mann = funksjon () (
denne .live = funksjon () (varsel ("Jeg lever");) // En person vet hvordan han skal leve
denne .walk = funksjon () (varsel ("Jeg går");) // En person kan gå
}

// Dette er dikterens konstruktør
poet = funksjon () (
denne .kill = funksjon () (varsel ( "Poeten drepte en mann");} // En poet kan drepe en person
denne .live = funksjon () (varsel ("Jeg er død");) // Dette vil føre til at personen dør
}

Vladimir = ny mann (); // Vladimir er en mann
vladimir.live (); // Jeg lever - han er i live
vladimir.walk (); // Jeg går - han går

Poet.call (vladimir); // Utfør dikterkonstruktøren for vladimir-objektet
vladimir.kill (); // Poeten drepte mannen
vladimir.live (); //Jeg er død

// Og nå fokus
man.call (vladimir);
vladimir.live (); //Jeg lever


* Denne kildekoden ble uthevet med Source Code Highlighter.

Hva ser vi i dette eksemplet? For det første er det muligheten til å arve fra flere objekter som ikke er i samme hierarki. I eksemplet er det 2 av dem, men det kan være så mange du vil.
For det andre er dette fraværet av noe hierarki i det hele tatt. Overordnede egenskaper og metoder bestemmes utelukkende av rekkefølgen konstruktørene kalles.
For det tredje er dette muligheten til å endre et objekt enda mer dynamisk, og det er et eget objekt, og ikke alle etterkommere, som når man endrer prototypen.

Oppdatering: Nedleggelser og private eiendommer

For ikke å blåse opp denne allerede ganske store artikkelen, gir jeg en lenke til innlegget Closures in JavaScript, hvor det er skrevet litt detaljert om det.

Hva skal man gjøre med alt dette nå

Som jeg sa ovenfor, vilkårlig modifikasjon av individuelle objekter, og bruk av konstruktører, og mixins, og fleksibiliteten til prototyper er bare verktøy, muligheter som lar en programmerer lage kode som er både forferdelig og vakker på alle måter. Det er bare viktig å forstå hvilke oppgaver vi løser, med hvilke midler, hvilke mål vi oppnår og hvilken pris vi betaler for det.

Dessuten er spørsmålet om prisen ganske ikke-trivielt, spesielt hvis vi snakker om utvikling for Internet Explorer 6 og 7-versjoner.
1. Minne - alt er enkelt her. I alle nettlesere tar arv på prototyper flere ganger mindre minne enn når man lager metoder gjennom konstruktører. Dessuten, jo flere metoder og egenskaper vi har, jo større er forskjellen. Det er imidlertid verdt å huske at hvis vi ikke har tusen identiske objekter, men bare én, så vil minneforbruket uansett være lite, fordi det er andre faktorer å vurdere her.
2. Prosessortid - her er de viktigste finessene knyttet til nettlesere fra Microsoft.
På den ene siden kan objekter der metoder og egenskaper skapes gjennom en konstruktør lages mange ganger (i noen tilfeller titalls eller hundrevis av ganger) langsommere enn gjennom en prototype. Jo flere metoder, jo tregere. Så hvis IE fryser i noen sekunder under initialiseringen av skriptet - det er en grunn til å grave i denne retningen.

På den annen side kan et objekts egne metoder (opprettet via en konstruktør) utføres litt raskere enn prototype. Hvis du desperat trenger å fremskynde utførelsen av en metode i denne nettleseren, må du ta hensyn til dette. Husk at det er metodekallet (dvs. søket etter det i objektet) som akselereres, og ikke utførelsen. Så hvis selve metoden kjører et sekund, vil du ikke merke en spesiell ytelsesøkning.

I andre nettlesere observeres lignende problemer, hvor tiden for å lage objekter og kalle metodene deres er omtrent den samme for begge tilnærmingene.

P.S. Vanligvis, i artikler av denne typen, tilbyr forfatteren en slags innpakning, enten ved å prøve å implementere klasseobjektarv basert på prototype, eller bare syntaktisk sukker for prototypisk arv. Jeg gjør ikke dette med vilje, fordi Jeg tror at en person som forstår betydningen av denne artikkelen er i stand til å skrive hvilken som helst innpakning for seg selv, og mange flere interessante ting :)

Tags: Legg til tagger

Objekter er hjørnesteinen i JavaScript. Mange innebygde datatyper er representert som objekter. For å være en vellykket JavaScript-utvikler må du ha en klar forståelse av hvordan de fungerer. Byggesteinene til et objekt kalles dets felt eller JavaScript-objektegenskaper. De brukes til å beskrive ethvert aspekt av et objekt. Eiendommen kan beskrive lengden på listen, fargen på himmelen eller fødselsdatoen til en person. Objektskaping er en enkel prosess. Språket gir syntaks kjent som objektliterals, som er angitt med krøllete klammeparenteser.

Tilgang til eiendommer

Språket gir to oppføringer for tilgang til eiendommer. Den første og mest vanlige er kjent som punktnotasjon. Med punktnotasjon kan du få tilgang til en ressurs ved å spesifisere navnet på vertsobjektet, etterfulgt av punktum og navnet på egenskapen. For eksempel, når object.foo opprinnelig ble tildelt verdien en, vil verdien bli 2 etter at JavaScript-setningen til objektene er utført.

En alternativ syntaks for tilgang er kjent som parentesnotasjon. I notasjon er objektnavnet etterfulgt av et sett med firkantede parenteser. De spesifiserer egenskapsnavnet som en streng:

objekt ["foo"] = objekt ["foo"] + 1.

Den er mer uttrykksfull enn punktnotasjon fordi den lar en variabel spesifisere hele eller deler av et egenskapsnavn. Dette er mulig fordi JavaScript-objekttolkeren automatisk konverterer dette uttrykket til en streng og deretter henter den tilsvarende egenskapen. Egenskapsnavn opprettes umiddelbart ved å sette sammen innholdet i f-variabelen med strengen "oo":

objekt = "bar".

Brakettnotasjon lar egenskapsnavn inneholde tegn som ikke er tillatt i punktnotasjon. For eksempel er følgende uttalelse helt lovlig i parentes. Imidlertid, hvis brukeren prøver å lage det samme egenskapsnavnet i stiplet notasjon, vil han støte på en syntaksfeil:

objekt [" [e-postbeskyttet]# $% & * (). "] = sant.

Egenskapene til nestede JavaScript-objekter kan nås ved å koble til perioder og/eller parenteser. For eksempel inneholder følgende objekt et nestet objekt kalt baz som inneholder et annet objekt kalt foo som har en egenskap kalt bar som inneholder verdien fem:

var objekt = (baz: (foo: (takt: 5))).

Følgende uttrykk får tilgang til den nestede egenskapslinjen. Det første uttrykket bruker punktnotasjon, mens det andre uttrykket bruker kvadratnotasjon. Det tredje uttrykket kombinerer begge oppføringene for å oppnå samme resultat:

  • object.baz.foo.bar;
  • objekt ["baz"] ["foo"] ["bar"];
  • objekt ["baz"]. foo ["bar"].

Uttrykk som det som er vist i forrige eksempel kan redusere ytelsen hvis de brukes feil og gjøre JavaScript-objektet ubrukelig. Evaluering av hver prikk eller parentesuttrykk tar tid. Hvis den samme egenskapen brukes flere ganger, er det fornuftig å få tilgang til egenskapen én gang og deretter lagre verdien i en lokal variabel for alle fremtidige formål.

Fungerer som metode

Når en funksjon brukes som en egenskap for et objekt, kalles det en metode. I likhet med egenskaper spesifiseres de ved hjelp av objekt-literal notasjon. For eksempel:

var objekt = (sum: funksjon (foo, bar) (retur foo + bar;)).

JavaScript-objektmetoder kan kalles ved å bruke etiketter og parenteser. Følgende eksempel kaller sum ()-metoden fra forrige eksempel ved å bruke begge notasjonene:

  • objekt.sum (1, 2);
  • objekt ["sum"] (1, 2).

Objektlitteral notasjon er nyttig for å lage nye objekter, men den kan ikke legge til egenskaper eller metoder til eksisterende. Heldigvis er det like enkelt å legge til nye data som å lage en oppdragserklæring. Et tomt objekt opprettes. Deretter, ved hjelp av oppgavesetninger, legges to egenskaper til, foo og bar, samt baz-metoden:

  • var objekt = ();
  • objekt.foo = 1;
  • object.bar = null;
  • object.baz = funksjon () (retur "hei fra baz ()";).

Innkapslingsprogrammer

Den grunnleggende ideen bak objektorientert programmering er å dele opp programmer i mindre biter og gjøre hver enkelt ansvarlig for å administrere sin egen tilstand. Dermed kan noe kunnskap om hvordan en del av et program fungerer være lokalt for den delen. Noen som jobber med resten av programmet trenger ikke huske eller vite om det. Hver gang disse lokale dataene endres, er det bare koden som er umiddelbart rundt dem som må oppdateres.

De ulike delene av et slikt program samhandler med hverandre gjennom grensesnitt, begrensede sett med funksjoner eller bindinger, som gir nyttig funksjonalitet på et mer abstrakt nivå, og skjuler deres eksakte implementering. Slike deler av programmet er modellert ved hjelp av objekter. Deres grensesnitt består av et spesifikt sett med metoder og egenskaper. Egenskaper som er en del av et grensesnitt kalles offentlige egenskaper. Resten, som ikke skal berøre ekstern kode, kalles private.

Mange språk gir muligheten til å skille mellom offentlige og private eiendommer og tillater ikke ekstern kode for å få tilgang til private eiendommer. JavaScript, igjen med en minimalistisk tilnærming, har ennå ikke blitt oppnådd. Det pågår arbeid for å legge til dette språket. Derfor vil JavaScript-programmerere bruke denne ideen med hell. Som regel er tilgjengelig grensesnitt beskrevet i dokumentasjonen eller kommentarene. Det er også vanlig å sette et understrek (_) i begynnelsen av eiendomsnavn for å indikere at eiendommene er private. Å skille grensesnitt fra implementering er en god idé. Det blir ofte referert til som innkapsling.

Egenskaper

Et objekt med parenteser (...) kalles et objekt bokstavelig. Du kan umiddelbart sette noen egenskaper i slike parenteser (...). For eksempel parer "nøkkel: verdi og så videre":

la bruker = (// et objektnavn: "John", // ved nøkkel "navn" lagre verdi "(! LANG: John" age: 30 // by key "age" store value 30 }.!}

Eiendommen har en nøkkel (også kjent som "navn" eller "identifikator") foran kolon ":" og en verdi til høyre for den. Brukerobjektet har to egenskaper. Det resulterende bruker-JavaScript-objektet med to signerte filer merket "navn" og "alder". Du kan legge til, slette og lese filer fra den når som helst. Eiendomsverdier er tilgjengelige ved bruk av punktnotasjon. Det kan være av hvilken som helst type. Boolsk kan legges til. For å slette en egenskap, bruk delete i feiltilfellet for et JavaScript-objekt.

Alle JavaScript-feilobjekter er etterkommere av Error-objektet eller et arvet objekt:

  1. Syntax Error-objektet arver fra Error-objektet.
  2. JSON Parse feil for en bestemt type Syntax Error-objekt.

For å dykke enda dypere inn i hvordan applikasjoner håndterer JavaScript-feil, ta en nærmere titt på Airbrake JavaScript, et feilsporingsverktøy for sanntidsvarsler og en umiddelbar forståelse av hva som gikk galt med JavaScript-kode.

Feilmeldinger som en bruker kan motta før sletting av et JavaScript-objekt:

  1. Dårlig kontrolltegn i streng bokstavelig.
  2. Dårlig karakter i en streng bokstavelig.
  3. Dårlig Unicode-utgang.
  4. Dårlig fluktkarakter.
  5. Uavsluttet streng.
  6. Uventet ikke-numerisk kode.
  7. Det er ingen sifre etter desimaltegn.
  8. Uavsluttet brøktall.
  9. Det er ingen tall etter gradsindikatoren.
  10. Det er ingen sifre etter eksponenttegnet.
  11. Den eksponentielle delen har ikke noe tall.
  12. Uventet slutt på data.
  13. Et uventet nøkkelord.
  14. Et uventet symbol.
  15. Slutt på data mens du leser innholdet i objektet.
  16. Det forventede egenskapsnavnet eller ")".

Beregningsegenskaper

Du kan bruke firkantede parenteser i en bokstavelig objekt. Dette kalles beregnede egenskaper. Et eksempel er vist nedenfor.

Den beregnede eiendomsverdien er enkel: det betyr at eiendomsnavnet skal hentes fra frukt. Så hvis en besøkende skriver inn "eple", blir pose (eple: 5). Du kan bruke mer komplekse uttrykk i hakeparenteser:

la frukt = "eple";

: 5 // bag.appleComputers = 5

Firkantede parenteser er mye kraftigere enn punktnotasjon. De aksepterer egenskapsnavn og variabler. Men de er også mer tungvint å skrive. Derfor brukes det meste av tiden, når eiendomsnavn er kjente og enkle, et punktum. Og hvis du trenger noe mer komplekst, så bytt til firkantede parenteser.

Ordreservasjon

En variabel kan ikke ha et navn som tilsvarer ett av de reserverte ordene som for, la, return, osv. Men det er ingen slik begrensning ved sortering av JavaScript-objekter.


I prinsippet er ethvert navn tillatt, men det er et spesielt: det "__proto__" får en spesiell behandling av historiske årsaker. Du kan for eksempel ikke sette den til en annen verdi enn objekt:

obj .__ proto__ = 5;

varsel (obj .__ proto__); //, fungerte ikke etter hensikten

Som du kan se fra koden, ignoreres tilordningen av primitiv 5. Dette kan bli en kilde til feil og til og med sårbarheter hvis operatøren har til hensikt å lagre vilkårlige nøkkelverdi-par i objektet og la den besøkende spesifisere nøklene. I dette tilfellet kan den besøkende velge "proto" som nøkkel og legge den til JavaScript-objektet. Det er en måte å gjøre objekter behandlet med __proto__ som en vanlig egenskap. Det er også et annet kart over datastrukturer som støtter vilkårlige nøkler.

Heltallsegenskaper

Begrepet "heltallsegenskap" betyr her en streng som kan konverteres fra et heltall uten endring. Så, for eksempel, "49" er et heltallsegenskapsnavn, fordi når det blir konvertert til et heltall og tilbake, er det fortsatt det samme. Men "+49" og "1.2" er det ikke. På den annen side, hvis nøklene ikke er heltall, er de oppført i rekkefølgen de ble opprettet. Se eksempel nedenfor.


For å fikse problemet med retningsnummer, kan du "jukse" ved å gjøre kodene ikke-heltall. Det er tilstrekkelig å legge til et "+" (plusstegn) foran hver kode. Nå vil det fungere etter hensikten.

Forskjellen mellom objekter og primitiver er at de lagres og kopieres "ved referanse". Primitive verdier blir tildelt og kopiert "som en heltallsverdi". En variabel lagrer en "adresse i minnet", ikke selve objektet eller en "referanse" til det. Du kan bruke hvilken som helst variabel for å få tilgang til og endre innholdet.


Eksemplet ovenfor viser at det bare er ett objekt og en admin for å logge på det. Deretter, hvis brukeren senere bruker en annen nøkkel (bruker), vil brukeren oppdage endringen.

Operatorene likhet == og streng likhet === fungerer på samme måte for objekter. To objekter er like bare hvis de er samme objekt. For sammenligninger som obj1> obj2, eller for sammenligninger med den primitive obj == 5, konverteres objekter til primitiver. For å være ærlig er slike sammenligninger svært sjelden nødvendige og er vanligvis et resultat av en kodefeil.

JavaScript-objektvalidering

Objekter har tilgang til enhver eiendom. Men hvis det ikke eksisterer i det hele tatt, vil det ikke være en feil. Bare tilgang til en ikke-eksisterende egenskap returnerer udefinert. Det gir en veldig vanlig måte å se etter en eiendom og sammenligne med en udefinert. Nedenfor er et eksempel.


Bruker "in" for egenskaper som lagrer udefinert. Vanligvis fungerer den strenge "=== undefined" sammenligningskontrollen fint. Det er et spesielt tilfelle hvor det feiler og "in" fungerer riktig. Dette er når en egenskap til et objekt eksisterer, men forblir udefinert.


I koden ovenfor eksisterer egenskapen obj.test teknisk sett. Derfor fungerer in-operatøren riktig. Situasjoner som dette er svært sjeldne fordi udefinert vanligvis ikke er tilordnet. For det meste brukes null "ukjent" eller "tom" verdier. Dermed er in-operatøren faktisk en gjest i koden.

Loop "for..in"

For å gå gjennom alle tastene fra objekt til objekt, er det en spesiell form for løkke: for..in. Dette er en helt annen ting enn for (;;)-konstruksjonen.

Nedenfor er et eksempel.


Det skal bemerkes at alle "for"-konstruktører lar deg deklarere looping-variabelen inne i loopen som en let-nøkkel. Alternativt kan du bruke en annen variabelnavnnøkkel i stedet.

For eksempel er for (la prop i obj) også mye brukt.

Det er en alternativ "firkantet bracket" som fungerer på hvilken som helst streng.


Når det er sagt, krever poenget at nøklene til JavaScript-objektet er en gyldig variabelidentifikator, det vil si at det ikke er mellomrom eller andre begrensninger. Du må være oppmerksom på at linjen inne i parentesene er korrekt sitert. Firkantede parenteser gir også en måte å få et egenskapsnavn fra ethvert uttrykk, i motsetning til en bokstavelig streng fra en variabel:

la nøkkel = "liker fugler";

// samme som bruker ["liker fugler"] = sant;

bruker = sant.

Her kan variabelnøkkelen beregnes ved kjøretid og avhenger av brukerinndata og deretter brukes til å få tilgang til egenskapen. Dette gir programmerere mye fleksibilitet. Punktnotasjon kan ikke brukes på en lignende måte, siden den vil iterere over JavaScript-objektet. Nedenfor er et eksempel.


Konst objekt

Det deklarerte const-objektet kan endres. Et eksempel er vist nedenfor.


Det kan virke som et JavaScript-objekt på nettet (*) vil gi en feil, men det gjør det ikke. Dette er fordi const fanger opp verdien til brukeren selv. Og her holder brukeren en referanse til det samme objektet hele tiden. Linjen (*) går inn i objektet, den blir ikke tildelt på nytt av brukeren. Const vil gi en feilmelding hvis du prøver å sette bruker og noe annet. Kloning og sammenslåing, Object.assign oppretter en annen referanse til det samme objektet i tilfelle det må dupliseres. Dette er også gjennomførbart, men litt mer komplisert fordi det ikke er noen innebygd metode i JavaScript. Faktisk er dette sjelden nødvendig. Kopiering ved referanse brukes i de fleste tilfeller. Men hvis du virkelig trenger det, må du lage et JavaScript-objekt og replikere strukturen til det eksisterende, kopiere egenskapene på et primitivt nivå. Nedenfor er et eksempel.


Og du kan også bruke Object.assign-metoden for dette. Argumentene dest og src1, ..., srcN er objekter. Den kopierer egenskapene til alle objektene src1, ..., srcNINTO dest. Med andre ord, egenskapene til alle argumenter som starter fra den andre, kopieres til den første. Deretter går den tilbake til dest. Du kan for eksempel bruke den til å kombinere flere objekter til ett.


Og det er også mulig å bruke Object.assign for å erstatte den enkle kloneløkken. Den kopierer alle brukeregenskapene til et tomt objekt og returnerer det, akkurat som en løkke, men kortere. Så langt har alle brukeregenskaper blitt antatt å være primitive. Men egenskaper kan være referanser til andre objekter.

For å fikse dette, må du bruke en kloneløkke som sjekker hver brukerverdi og, hvis det er et objekt, deretter replikerer strukturen. Dette kalles "dyp kloning".

Det er en standard dypkloningsalgoritme som håndterer saken ovenfor og mer komplekse tilfeller kalt den strukturerte kloningsalgoritmen. For å unngå å finne opp hjulet på nytt, kan du bruke en fungerende implementering fra lodash JavaScript-biblioteket kalt _.cloneDeep (obj).

Avanserte teknikker

Hvis en programmerer går over et objekt og søker å få alle egenskaper i samme rekkefølge som de ble lagt til, kan de stole på "spesiell rekkefølge" der heltallsegenskaper sorteres og andre dannes i den rekkefølgen som JavaScript-objektet ble opprettet i. .

Avanserte objektmetoder omhandler konsepter som sjelden brukes i JavaScript. Dette er fordi disse kraftige funksjonene ikke er nødvendige i normale scenarier. Noen av disse metodene fungerer kanskje ikke i eldre nettlesere, for eksempel tidlige utgivelser av Netscape 4.

Bruken av prototypen kan brukes til å lage JavaScript-objekter og alle mycircle-metoder, ikke bare nye. Dette gir en blandet ytelsesbelastning. De trenger ikke å ha separate kopier av metodene for hver forekomst av objektet, så de kan kreve mindre minne for å fungere, men nettleseren må se etter gjeldende og overordnet omfang for å finne dem. Dette kan føre til ekstrem ventetid. Vanligvis bør brukeren bruke det som er passende for koden i stedet for å basere den beslutningen på ytelse, med mindre de har å gjøre med et veldig spesifikt kontrollert miljø.


Returner sant

I noen tilfeller kan det være nødvendig at en egenskap til et objekt er bundet til selve objektet eller et sted i prototypekjeden. I JavaScript bruker alle objekter hasOwnProperty-metoden, som returnerer true hvis denne egenskapen er bundet til en enkelt objektforekomst. I dette tilfellet blir det mulig å sjekke om objektets konstruktør har samme egenskap med samme verdi som selve objektforekomsten. Dette kan gi feil resultat hvis det er separate JavaScript-objektegenskaper med samme verdi for både objektforekomsten og kjedeprototypen. HasOwnProperty-metoden tar en enkelt parameter, egenskapsnavnet som en streng.


Private metoder kan lages på samme måte. Det er bare en funksjon som er opprettet inne i en konstruktørfunksjon. Dette kan virke forvirrende for noen, men det er slik det fungerer. En privat funksjon kan bare kalles av konstruktøren selv eller av metoder som er definert i strengen. De kan brukes som offentlige metoder hvis de er tilordnet til en offentlig konstruktør og åpnes ved hjelp av offentlige metoder for Javascript-objekter.

funksjon myob () (funksjon cantBeSeen () (varsling (secretValue);

) var secretValue = "";

this.method1 = funksjon () (secretValue = "(! LANG: ingen overraskelser";!}

this.method2 = cantBeSeen;

) var oneOb = ny myob ();

oneOb.method1 ();

// varsler "ingen overraskelser" oneOb.method2 ();

// varsler "ingen overraskelser".

Kommandomal

Kommandoobjekter tillater løst koblede systemer, og skiller de som sender forespørselen fra objektene og faktisk behandler forespørselen. Disse forespørslene kalles hendelser, og koden som håndterer forespørslene kalles hendelsesbehandlere.

Anta at du bygger applikasjoner som støtter utklippstavlehandlingene Klipp ut, Kopier og Lim inn. Disse handlingene kan utløses på forskjellige måter i hele applikasjonen: av menysystemet, kontekstmenyer, for eksempel ved å høyreklikke på et tekstfelt, eller ved hjelp av hurtigtaster. Kommandoobjekter lar deg sentralisere behandlingen av disse handlingene, én for hver operasjon når du bare trenger én kommando for å behandle alle Klipp-forespørsler, én for alle kopieringsforespørsler og én for alle Lim-forespørsler.

Siden kommandoene sentraliserer all behandling, er de også ofte involvert i behandlingen av kanselleringsfunksjoner for hele applikasjonen. Betydelige forbedringer kan oppnås ved å bruke moderne JavaScript-teknikker, noe som resulterer i mer effektive, pålitelige og vedlikeholdbare applikasjoner.

JavaScript + jQuery-maler kan brukes for å se hvordan du gjør dette. Denne unike pakken inkluderer optimert JavaScript for alle GoF-maler som bruker mer avanserte funksjoner som navnerom, prototyper, moduler, funksjonsobjekter, nedleggelser, anonyme funksjoner og mer. Hvis brukere vil ha de nyeste verktøyene og teknikkene for JavaScript-maler, jQuery-maler og malarkitekturer, så er dette den beste brukssaken. Denne pakken inneholder verdifull, oppdatert informasjon for JavaScript-utviklere. Her er hva som er inkludert:

  1. JavaScript-optimaliserte GoF-maler.
  2. Moderne JavaScript-designmønstre.
  3. Model-View designmønstre.
  4. JQuery designmaler.
  5. Arkitektoniske mønstre JavaScript-idiomer.
  6. Eksempelapplikasjoner (MVC, SPA, etc.)

De foreslåtte grunnleggende om JavaScript-objektsyntaks er svært viktige for nybegynnere. Du må forstå objekter først, så vil det være kunnskap om objektorientert programmering. Det er viktig å ha en dyp forståelse av dette materialet, da det fungerer som grunnlaget for resten av JavaScript-språket.

Et objekt er en uordnet samling av egenskaper. En egenskap er en del av et objekt som simulerer en variabel. En egenskap består av et navn og en verdi.

Det er tre kategorier av objekter i JavaScript:

  • Base type objekter Er objekter definert i ECMAScript-spesifikasjonen. For eksempel er objekter av typen Array, Function, Date eller RegExp objekter av basistypen.
  • Kjøretidsobjekter Er objekter definert i kjøretiden (for eksempel en nettleser). For eksempel er objekter av typen HTMLElement kjøretidsobjekter.
  • Egendefinerte objekter Er ethvert objekt opprettet ved å kjøre JavaScript-kode.

Objektskaping

Et objekt kan opprettes ved hjelp av en objekt-literal eller den nye operatøren med en konstruktør.

En bokstavelig objekt er en kommadelt liste med null eller flere egenskaper (navn: verdipar), omsluttet av krøllete klammeparenteser. Egenskapsnavnet kan være en hvilken som helst gyldig identifikator, streng bokstavelig (du kan bruke en tom streng) eller et tall. Numeriske egenskapsnavn konverteres automatisk til strenger. Egenskapsverdien kan være en verdi av en hvilken som helst type eller et uttrykk (egenskapsverdien i dette tilfellet vil være resultatet av å evaluere uttrykket):

// Lag et tomt objekt var o = (); // Lag et objekt med tre egenskaper var user = (navn: "Homer", "age": 45, 1: true);

Opprette et objekt med den nye operatoren:

Var o = nytt objekt ();

Objektoperasjoner

Hovedoperasjonene som utføres med objekter er å legge til nye egenskaper, endre eksisterende egenskaper, slette egenskaper og få tilgang til egenskaper.

Du kan legge til en ny egenskap til et objekt ved å tilordne en verdi til egenskapen. For å tilordne en verdi til en egenskap, må den ha tilgang. En av tilgangsoperatørene brukes til å få tilgang til eiendommen:. (punktum) eller (firkantede parenteser):

Å få tilgang til en eiendom og endre en verdi gjøres på samme måte (ved å bruke tilgangsoperatører):

Var o = (x: 5); varsel (o.x); // Ringer eiendomsvarslet (o ["x"]); // Tilgang til egenskapen o.x = 10; // Endre verdien

Sletting av en egenskap gjøres med delete-operatoren:

Var o = (x: 5); varsel ("x" i o); // true delete o.x; varsel ("x" i o); // falsk

For å iterere over egenskapene til et objekt, brukes en for-in-løkke:

Var obj = (x: 5, y: 10, str: "Hei!"); for (var prop i obj) (varsling (prop);)

Objektmetoder

En egenskap hvis verdi er en funksjon kalles en metode. Et metodekall utføres på samme måte som et vanlig funksjonsanrop - ved å bruke operatøren () (anropsoperatør):

Var o = (siHi: funksjon () (varsel ("Hei!");)); o.siHei (); // "Hallo!"

Dette nøkkelordet brukes for å få tilgang til egenskapene til et objekt inne i en metode. Den inneholder en referanse til objektet som metoden ble kalt:

Var o = (navn: "Homer", siNavn: funksjon () (varsel (dette.navn);)); o.sayName (); // "Homer"

I stedet for dette nøkkelordet kan du bruke navnet på objektet direkte, men dette er ikke veldig praktisk, fordi hvis navnet på objektet endres, må du også endre navnet i metodene:

Var o = (navn: "Homer", siNavn: funksjon () (varsel (o.navn);)); o.sayName (); // "Homer"