
[0]
, és az első [hossza - 1]. - Máté 20:16Kihagyom a malthusi katasztrófát, és eljutok hozzá: a tömbök az egyik legegyszerűbb és legfontosabb adatstruktúra. Míg a terminál elemekhez (az első és az utolsó) gyakran hozzáférnek, a Javascript nem biztosít kényelmes tulajdonságot vagy módszert erre, és az indexek használata felesleges lehet, és hajlamos a mellékhatásokra és az egyesével kapcsolatos hibákra.
Egy kevésbé ismert, nemrégiben kiadott JavaScript TC39 javaslat két „új” tulajdonság formájában nyújt vigaszt: Array.lastItem
& Array.lastIndex
.

Javascript tömbök
Sok programozási nyelvben, beleértve a Javascript-et is, a tömbök nulla indexelésűek. Az első és az utolsó terminálelemekhez a, [0]
illetve az [length — 1]
indexeken keresztül lehet hozzáférni . Ezt az örömöt egy C által létrehozott precedensnek köszönhetjük, ahol egy index egy tömb fejétől számított eltolást képviseli. Ez lehetővé teszi a nulla az első index, mert ez a tömb fejét. Dijkstra szintén „a nullát a legtermészetesebb számnak” hirdette. Tehát legyen megírva. Tehát legyen kész.
Azt gyanítom, hogy ha átlagosan indexenként szeretné elérni, akkor a terminálokra hivatkoznak a leggyakrabban. Végül is a tömböket általában egy válogatott gyűjtemény tárolására használják, és így felsőbb szintű elemeket (legmagasabb, legalacsonyabb, legrégebbi, legújabb stb.) Helyeznek el a végén.
Más script nyelvektől (mondjuk PHP vagy Elixir) eltérően a Javascript nem biztosít kényelmes hozzáférést a terminál tömb elemeihez. Vegyünk egy triviális példát az utolsó elemek két tömbben történő felcserélésére:
let faces = ["?", "?", "?", "?", "?"];let animals = ["?", "?", "?", "?", "?"];
let lastAnimal = animals[animals.length - 1];animals[animals.length - 1] = faces[faces.length - 1];faces[faces.length - 1] = lastAnimal;
A felcserélési logikához 2 tömbre van szükség, amelyekre 8 sorban 3 sorban hivatkozunk! A valós kódokban ez gyorsan ismétlődhet és nehezen értelmezhető az ember számára (bár egy gép számára tökéletesen olvasható).
Ráadásul kizárólag indexek segítségével nem definiálhat tömböt, és nem kaphatja meg ugyanabban a kifejezésben az utolsó elemet. Lehet, hogy ez nem tűnik fontosnak, de vegyünk egy másik példát, ahol a függvény, getLogins()
aszinkron API-hívást indít és rendezett tömböt ad vissza. Feltételezve, hogy a tömb végén szeretnénk a legfrissebb bejelentkezési eseményt:
let lastLogin = async () => { let logins = await getLogins(); return logins[logins.length - 1];};
Kivéve, ha a hossza fix és előre ismert, azt kell rendelni a tömböt egy helyi változót hozzáférni az utolsó elem. Ennek egyik olyan módja, hogy ezt olyan nyelveken kezeljük, mint a Python és a Ruby, a negatív indexek használata. Ezután [length - 1]
lerövidíthető, így [-1]
nincs szükség helyi referenciára.
-1
Csak kissé olvashatóbbnak találom, mint length — 1
, és bár a Javascript negatív tömbindexeit hozzá lehet közelíteni az ES6 Proxy-hoz, vagy Array.slice(-1)[0]
mindkettő jelentős teljesítmény-következményekkel jár arra nézve, ami egyébként egyszerű véletlenszerű hozzáférést jelent.

Aláhúzás és Lodash
A szoftverfejlesztés egyik legismertebb alapelve a Ne ismételje meg magát (DRY). Mivel a terminálelemekhez való hozzáférés olyan gyakori, miért nem írunk hozzá segítő funkciót? Szerencsére sok olyan könyvtár, mint az Aláhúzás és a Lodash, már rendelkezik segédprogramokkal a _.first
& számára _.last
.
Ez nagy előrelépést kínál a lastLogin()
fenti példában:
let lastLogin = async () => _.last(await getLogins());
De ami az utolsó elemek cseréjét illeti, a fejlődés kevésbé jelentős:
let faces = ["?", "?", "?", "?", "?"];let animals = ["?", "?", "?", "?", "?"];
let lastAnimal = _.last(animals);animals[animals.length - 1] = _.last(faces);faces[faces.length - 1] = lastAnimal;
Ezek a segédfunkciók eltávolították a 8 referencia közül kettőt, csak most vezettünk be egy külső függőséget, amely furcsa módon nem tartalmaz funkciót a terminál elemek beállításához .
Valószínűleg egy ilyen funkciót szándékosan kizárnak, mert az API zavaros és nehezen olvasható. A Lodash korai verziói olyan módszert szolgáltattak, _.last(array, n)
ahol n az elemek száma a végétől, de végül a javára került _.take(array, n)
.
Ha feltételezzük, hogy nums
egy tömb szám, akkor mi lenne a várható viselkedés _.last(nums, n)
? Visszaadhatja az utolsó két elemet, mint például _.take
, vagy beállíthatja az utolsó elem értékét n-nek .
Ha egy tömb utolsó elemének beállításához írnánk függvényt, csak néhány megközelítést kell figyelembe venni a tiszta függvények, a módszerláncolás vagy a prototípus használatával:
let nums = ['d', 'e', 'v', 'e', 'l']; // set first = last
_.first(faces, _.last(faces)); // Lodash style
$(faces).first($(faces).last()); // jQuery style
faces.first(faces.last()); // prototype
Ezen megközelítések közül egyiket sem tartom nagy javulásnak. Valójában itt elveszik valami fontos. Mindegyik elvégez egy hozzárendelést, de egyik sem használja a hozzárendelés operátort ( =
). Ez nyilvánvalóbbá válhat az olyan elnevezési konvenciókkal, mint a getLast
és setFirst
, de ez gyorsan túlságosan bőbeszédűvé válik. Nem is beszélve a pokol ötödik köréről, amely tele van olyan programozókkal, akik kénytelenek navigálni az „öndokumentáló” örökölt kódban, ahol az adatok elérésére vagy módosítására csak a getterek és a beállítók szolgálnak.
Valahogy úgy tűnik, hogy ragaszkodunk a [0]
& [length — 1]
…
Vagy mi vagyunk? ?
A javaslatot
Mint említettük, az ECMAScript műszaki jelölt (TC39) javaslata megkísérli megoldani ezt a problémát két új tulajdonság definiálásával az Array
objektumon: lastItem
& lastIndex
. Ezt a javaslatot a core-js 3 már támogatja, és ma már használható a Babel 7 és TypeScript fájlokban. Még akkor is, ha nem használ transzpilert, ez a javaslat tartalmaz egy polifillet.
Személy szerint nem találok sok értéket a lastIndex
Ruby rövidebb elnevezésének , és jobban szeretem , first
és last
bár ezt kizárták a lehetséges web-kompatibilitási problémák miatt. Az is meglep, hogy ez a javaslat nem javasolja firstItem
a következetesség és a szimmetria tulajdonságait.
Időközben függetlenség nélküli, Ruby-jellegű megközelítést kínálok az ES6-ban:
Első Utolsó
Most két új Array tulajdonságunk van first
- last
és egy megoldás, amely:
✓ A hozzárendelés operátort használja
✓ Nem klónozza a tömböt
✓ Meg tud definiálni egy tömböt, és kap egy terminál elemet egy kifejezésbe
✓ Emberileg olvasható
✓ Egy felületet biztosít a megszerzéshez és beállításhoz
Újra átírhatjuk lastLogin()
egyetlen sorba:
let lastLogin = async () => (await getLogins()).last;
De az igazi győzelem akkor következik be, amikor az utolsó elemeket két tömbben cseréljük felére, a hivatkozások számának felével:
let faces = ["?", "?", "?", "?", "?"];let animals = ["?", "?", "?", "?", "?"];
let lastAnimal = animals.last;animals.last = faces.last;faces.last = lastAnimal;
Minden tökéletes, és megoldottuk a CS egyik legnehezebb problémáját. Ebben a megközelítésben nem rejtőznek gonosz szövetségek ...
Paranoia prototípus
Biztosan nincs a földön senki [programozó], aki olyan igazat tenne, hogy valaha vétkezés nélkül jót tenne. - Adagolt 7:20Sokan úgy gondolják, hogy a natív Object prototípusának kibővítése antiminta és bűncselekmény, amelyet 100 év Java-programozással büntetnek. A enumerable
tulajdonság bevezetése előtt a kiterjesztés Object.prototype
megváltoztathatja a for in
hurkok viselkedését . Konfliktushoz vezethet a különféle könyvtárak, keretrendszerek és harmadik féltől származó függőségek között is.
Talán a leg alattomosabb kérdés, hogy fordítási idejű eszközök nélkül egy egyszerű helyesírási hiba akaratlanul asszociatív tömböt hozhat létre.
let faces = ["?", "?", "?", "?", "?"];let ln = faces.length
faces.lst = "?"; // (5) ["?", "?", "?", "?", "?", lst: "?"]
faces.lst("?"); // Uncaught TypeError: faces.lst is not a function
faces[ln] = "?"; // (6) ["?", "?", "?", "?", "?", "?"]
Ez az aggodalom nem csak a mi megközelítésünkre vonatkozik, hanem minden natív Object prototípusra (beleértve a tömböket is). Ez mégis más formában kínálja a biztonságot. A Javascript tömbök hossza nem rögzített, következésképpen nincsenek is IndexOutOfBoundsExceptions
. A használat Array.last
biztosítja, hogy véletlenül ne próbáljunk meg belépni [length]
és akaratlanul belépni a undefined
területre.
Nem számít, melyik megközelítést választja, vannak buktatók. A szoftver ismét a kompromisszumok művészetének bizonyul.
Folytatva az idegen bibliai utalást, feltételezve, hogy nem hisszük, hogy Array.prototype
a kiterjesztés örök bűn, vagy hajlandóak vagyunk beleharapni a tiltott gyümölcsbe, használhatjuk ezt a tömör és olvasható szintaxist ma is!
Utolsó szavak
Programokat kell írni az emberek számára az olvasáshoz, és csak mellékesen a gépek végrehajtásához. - Harold AbelsonAz olyan szkriptnyelvekben, mint a Javascript, a funkcionális, tömör és olvasható kódot részesítem előnyben. A terminál tömb elemeinek elérése kapcsán az Array.last
ingatlant találom a legelegánsabbnak. Egy éles front-end alkalmazásban előnyben részesíthetem a Lodash-ot, hogy minimalizálhassam a konfliktusokat és a böngészőkön keresztüli aggályokat. De a Node háttérszolgáltatásokban, ahol én irányítom a környezetet, ezeket az egyéni tulajdonságokat részesítem előnyben.
Természetesen nem én vagyok az első, és nem is az utolsó, aki értékelem az olyan tulajdonságok értékét (vagy óvatosságot a következményekkel kapcsolatban) Array.lastItem
, amely remélhetőleg hamarosan megjelenik az Ön közelében lévő ECMAScript verzióval.

Kövessen a LinkedIn · GitHub · Közepes oldalon