Cargo-cult programmeren is wat een programmeur doet wanneer hij of zij een bepaalde taal of paradigma niet goed genoeg kent, en zo uiteindelijk overbodige en mogelijk schadelijke code schrijft. Het steekt zijn kop vrij vaak in het land van JavaScript. In dit artikel onderzoek ik het concept van ladingcultusprogrammering en plaatsen om op te letten in JavaScript.
Dogmatische regels oppervlak en verspreiden, totdat ze worden beschouwd als de norm.
Cargo-culting wordt soms omschreven als "de extreme naleving van de vorm in plaats van de inhoud." De vorm, in programmeren, is de syntaxis, paradigma's, stijlen en patronen die we gebruiken. De inhoud is het abstracte ding dat je wilt weergeven door je code - de essentie van je programma. Iemand met een gebrek aan begrip in een gebied zal waarschijnlijk de vorm van anderen kopiëren zonder echt begrip, en dus kan hun inhoud - hun programma - lijden.
Cargo-culting is merkwaardig gebruikelijk in JavaScript, waarschijnlijk vanwege de algemene lage toetredingsbarrière in de front-end ontwikkelingswereld. U kunt binnen enkele seconden een HTML-pagina maken met een beetje JavaScript. Dientengevolge zijn er veel mensen die voldoende bekwaam zijn in deze technologieën om zich op hun gemak te voelen bij het creëren en opleggen van regels aan zichzelf en anderen. Uiteindelijk kopiëren andere nieuwkomers deze regels. Dogmatische regels oppervlak en verspreiden, totdat ze worden beschouwd als de norm:
Een regel blijft zich verspreiden totdat een programmeur alleen een bepaalde techniek gebruikt vanwege zijn populariteit, in plaats van elke specifieke use-case onafhankelijk te beschouwen.
Als je in de loop van de jaren getuige bent geweest van de geestige plagerij en retoriek van de softwareontwikkelaar, heb je de neiging gezien om ogenschijnlijk kleine dingen uitvoerig te bespreken. Dingen als de puntkomma, de komma, witte ruimte of de gekrulde steun.
Syntaxis zoals puntkomma's of witruimten kunnen puur elementen van vorm lijken, niet van inhoud. Maar veel van deze subtiele syntaxisregels kunnen aanzienlijke gevolgen hebben in JavaScript. Als je de 'vorm' niet begrijpt, kun je de 'inhoud' niet beginnen te begrijpen.
Dus in dit artikel zullen we vaststellen welke vormgebieden in JavaScript vaak worden afgepakt met vracht - dat wil zeggen, gekopieerd zonder begrip.
Hoe JavaScript kan lijken ... een afbeelding van de presentatie "The Politics Of JavaScript" van Angus CrollAngus Croll, in een recente presentatie, getiteld "The Politics of JavaScript", benadrukte een van de meest voorkomende stukken JS-dogma waar mensen de ladingcultuur van afhalen:
if (typeof myObject.foo === 'undefined') ...
Meestal doe ik zo'n langdradige cheque onbepaald
is zinloos. De techniek werd gebruikelijk omdat mensen andere mensen kopieerden, niet vanwege de werkelijke waarde ervan.
Natuurlijk zijn er tijden wanneer:
typeof x === 'undefined'
... heeft de voorkeur boven:
x === niet gedefinieerd
Maar er zijn ook momenten waarop de laatste de voorkeur heeft. Een snel overzicht van de opties:
// Bepaal of 'x' undefined is: x === undefined typeof x == 'undefined' typeof x === 'undefined' x === void 0 // Bepaal of 'x' ongedefinieerd is OF null: x = = null x == undefined
Mensen begonnen het te gebruiken soort van
aanpak omdat ze zichzelf beschermden tegen:
onbepaald
naar zoiets waar
. Je moet jezelf afvragen: "Is het waarschijnlijk dat iemand ongedefinieerd overschrijft, en zou mijn script moeten toegeven aan dergelijke dwaasheden?"Maar meestal beschermen ze zichzelf tegen zorgen. Het is een catch-all vermijding van het moeten weten van de details. Het kennen van de details kan je echter helpen. Elk karakter van uw code moet bestaan met een doel in gedachten.
De enige keer dat u een a moet gebruiken soort van
controleren op onbepaald
is wanneer u zoekt naar een variabele die mogelijk niet is gedeclareerd, bijvoorbeeld controleren op jQuery in de globale scope:
if (typeof jQuery! = 'undefined') // ... Gebruik jQuery
Het ding is, als jQuery doet bestaan, dan kunnen we er zeker van zijn dat het een object is - een "waarheids" ding. Dus dit zou voldoende zijn:
// of: if (window.jQuery)
Laten we iets heel algemeens nemen en over het algemeen als goed advies beschouwen, uitsluitend met strikte gelijkheid:
a === b
Strikte gelijkheid wordt als goed beschouwd omdat het dubbelzinnigheid vermijdt. Het controleert zowel de waarde als het type, wat betekent dat we ons geen zorgen hoeven te maken over impliciete dwang. Met niet-strikte gelijkheid moeten we ons echter zorgen maken over:
1 == 1 // waar - oké, dat is goed 1 == "1" // waar - hmm 1 == [1] // waar - wat!?
Dus het lijkt verstandig advies om niet-strikte gelijkheid volledig te vermijden, toch? Eigenlijk niet. Er zijn veel situaties waarin strikte gelijkheid grote hoeveelheden overtolligheid creëert, en niet-strikte gelijkheid verdient de voorkeur.
Wanneer je met 100% zekerheid weet dat de typen van beide operands hetzelfde zijn, kun je de noodzaak voor strikte gelijkheid vermijden. Ik weet bijvoorbeeld altijd dat het soort van
operator retourneert een tekenreeks en mijn rechterhandopdracht is ook een tekenreeks (bijv. "aantal"
):
// Met strict-equals typeof x === 'number' // Met niet-strict-equals: typeof x == 'number'
Ze zijn beide effectief identiek. Ik suggereer niet noodzakelijk dat we in dit geval afstand doen van strikte gelijken - ik stel voor dat we ons bewust blijven van wat we doen, zodat we de beste keuzes kunnen maken, gegeven elke situatie.
Een ander heel handig voorbeeld is wanneer u wilt weten of een waarde dat ook is nul
of onbepaald
. Met strikte gelijkheid, zou u dit kunnen doen:
if (value === undefined || value === null) // ...
Met niet-strikte gelijkheid is het veel eenvoudiger:
if (value == null) // ...
Er is hier geen sprake van - het doet precies wat we willen, alleen maar aantoonbaar minder zichtbaar. Maar, als we de taal kennen, wat is dan het probleem? Het staat precies in de specificatie:
De vergelijking x == y
, waar X
en Y
zijn waarden, produceert waar
of vals
. Een dergelijke vergelijking wordt als volgt uitgevoerd:
Als je JavaScript aan het schrijven bent met de bedoeling dat het wordt gelezen, of helemaal niet, door mensen die JavaScript kennen, dan zou ik zeggen dat je je niet slecht zou hoeven te voelen als je misbruik maakt van impliciete taalregels, zoals deze.
hasOwnProperty
De hasOwnProperty
methode wordt gebruikt om te bepalen of een eigenschap direct eigendom is van een object. Wordt het vaak gevonden in voor in
loops om ervoor te zorgen dat je alleen knoeit met directe eigenschappen en niet met geërfde eigenschappen.
for (var i in object) if (object.hasOwnProperty (i)) // We kunnen dingen doen met 'object [i]'
Het is belangrijk op te merken dat de voor in
statement loopt alleen door enumarabele eigenschappen. Native geërfde methoden zijn bijvoorbeeld niet opsombaar en u hoeft zich er hoe dan ook geen zorgen over te maken.
De hasOwnProperty
controleren voorkomt specifiek dat u eigenschappen aanraakt die u of een script van een derde partij heeft gedefinieerd, bijvoorbeeld wanneer het prototype van uw object opsombare eigenschappen heeft.
Als je weet dat het prototype van je object (of het prototype van het prototype enz.) heeft dan geen opsombare eigenschappen je hoeft je geen zorgen te maken over het gebruik hasOwnProperty
in uw voor in
loops. En, als uw object is geïnitialiseerd, via ES5's Object.create (null)
, dan kun je niet eens bellen hasOwnProperty
direct op het object (geen prototype betekent geen overgeërfde native methoden). Dit betekent dat gebruik hasOwnProperty
standaard in al uw voor in
loops kunnen soms breken.
Een mogelijke oplossing voor objecten met nul
prototypen is om een opgeslagen verwijzing naar te gebruiken hasOwnProperty
, zoals zo:
var hasOwnProperty = Object.prototype.hasOwnProperty; // Later in uw code: for (var i in someObject) if (hasOwnProperty.call (someObject, i)) // ...
Dat zal werken, zelfs als het object geen prototype heeft (in het geval van Object.create (null)
). Maar natuurlijk moeten we dit alleen doen als we weten dat we het nodig hebben. Als je een script van een derde partij schrijft voor een "vijandige" omgeving, ja, controleer dan zeker voor opsomming van overerfbare eigenschappen. Anders is het misschien niet altijd nodig.
Notitie: IE9 en Safari 2.0 compliceren de zaak verder wanneer u probeert om opsommingseigenschappen te identificeren die al zijn gedefinieerd als niet-opsombaar. Het is de moeite waard om een echt cross-browser forOwn loop-implementatie uit te proberen.
Tot slot: uw gebruik van hasOwnProperty
moet afhangen van het object dat wordt doorgelust. Het hangt af van welke aannames u veilig kunt maken. Jezelf blind beschermen met behulp van de hasOwnProperty
zal niet in alle gevallen volstaan. Wees ook op uw hoede voor verschillen tussen browsers.
Een andere veelvoorkomende redundantie die in de JS-code kruipt, is de haakjes. Binnen expressies wordt het gebruikt om specifieke groepering van subuitdrukkingen te forceren. Zonder hen bent u overgeleverd aan voorgangers en associaties van de operator. Bijvoorbeeld:
A && B || C A && (B || C) (A && B) || C
Een daarvan is niet zoals de ander. De haakjes dwingen een specifieke groepering af en veel mensen geven de voorkeur aan de extra duidelijkheid. In dit geval heeft de logische AND-operator een hogere prioriteit dan de logische OR-operator, wat betekent dat het de eerste en laatste regels zijn die gelijk zijn. De tweede regel is een geheel andere logische bewerking.
Hogere prioriteit betekent dat het vóór andere bewerkingen in een reeks bewerkingen zal plaatsvinden.
Om deze complexiteit te vermijden, kiezen ontwikkelaars vaak voor een 'beleid voor haakjes' - waarbij u steeds haakjes blijft toevoegen totdat het overduidelijk is welke bewerkingen plaatsvinden, zowel voor u als voor potentiële lezers van de code. Men kan stellen dat deze breedsprakigheid uiteindelijk de dingen minder duidelijk maakt.
Soms is het lastig voor een lezer. Er moet rekening worden gehouden met het feit dat een gegeven haakje mogelijk is toegevoegd omdat:
Neem dit voorbeeld:
A && B? doFoo (): doBaz ()
Zonder kennis van de regels voor operator-voorrang, kunnen we hier twee mogelijke bewerkingen zien:
(A && B)? doFoo (): doBaz () A && (B? doFoo (): doBaz ())
In dit geval is het de logische AND die de hogere prioriteit heeft, wat betekent dat de equivalente haakjes-expressie:
(A && B)? doFoo (): doBaz ()
We zouden echter geen verplichting voelen om deze haakjes in onze code toe te voegen. Het gebeurt impliciet. Zodra we herkennen dat het impliciet gebeurt, zijn we vrij om het te negeren en ons te concentreren op het programma zelf.
Er zijn natuurlijk geldige argumenten om de haakjes te behouden waar impliciete groepering onduidelijk is. Dit komt echt op u neer en waar u zich comfortabel bij voelt. Ik zou je echter willen vragen om de precedenten te leren en dan kun je volledig bevoegd worden om de beste route te nemen, afhankelijk van de specifieke code waarmee je te maken hebt.
Het is niet zeldzaam om overtollige aanhalingstekens in object-letterwoorden te zien:
var data = 'date': '2011-01-01', 'id': 3243, 'action': 'UPDATE', 'related': '1253': 2, '3411': 3;
In aanvulling op tekenreeksen, kunt u met JavaScript de namen en nummers van geldige id's gebruiken als lettertekens voor objecten, zodat het bovenstaande kan worden herschreven naar:
var data = date: '2011-01-01', id: 3243, action: 'UPDATE', related: 1253: 2, 3411: 3;
Soms geeft u misschien de voorkeur aan de toegevoegde consistentie van het kunnen gebruiken van aanhalingstekens, vooral als een veldnaam een gereserveerd woord is in JavaScript (zoals 'class' of 'instanceof'). En dat is prima.
Het gebruik van citaten is geen slechte zaak. Maar het is overbodig. Wetende dat je ze niet hoeft te gebruiken, wordt de helft van de gewonnen strijd. Het is nu jouw keuze om te doen wat je wilt.
Er is een enorme hoeveelheid subjectieve voorkeur als het gaat om plaatsing van interpunctie in de programmering. Meest recent is de JavaScript-wereld gonst van retoriek en ontevredenheid over de komma.
Initialiseren van een object in traditioneel idiomatische JavaScript ziet er als volgt uit:
var obj = a: 1, b: 2, c: 3;
Er is een alternatieve aanpak, die echter in een stroomversnelling is geraakt:
var obj = a: 1, b: 2, c: 3;
Het veronderstelde voordeel van het plaatsen van de komma's vóór elk sleutel / waarde-paar (behalve de eerste) is dat het betekent dat u slechts één regel hoeft aan te raken om een eigenschap te verwijderen. Gebruikend de traditionele benadering, zou u "moeten verwijderenc: 3
"en dan de achterliggende komma op de regel hierboven. Maar met de komma-eerst benadering kun je gewoon verwijderen", c: 3
Voorstanders beweren dat dit minder komma's maakt en ruimt ook broncontroleforums op.
Tegenstanders zeggen echter dat deze benadering alleen maar leidt tot het wegwerken van het "comma" -probleem door een nieuw probleem met de leidende komma te introduceren. Probeer de eerste regel te verwijderen en u krijgt een leidende komma op de volgende regel. Dit wordt eigenlijk als een goede zaak beschouwd door voorstanders van komma's, omdat een leidende komma onmiddellijk een SyntaxError zou gooien. Een achterliggende komma werpt echter niets, behalve in IE6 en 7. Dus als de ontwikkelaar zijn JS niet in die versies van IE test, kunnen de achterlopende komma's vaak de productiecode binnendringen, wat nooit goed is. Een leidende komma-worp in alle omgevingen, dus minder kans om gemist te worden.
Natuurlijk zou je kunnen betogen dat dit hele ding onbeschoft is. We zouden waarschijnlijk linters zoals JSLint of de vriendelijkere JSHint moeten gebruiken. Dan zijn we vrij om de interpunctie en witruimte plaatsing te gebruiken die het meest logisch is voor ons en onze collega's.
Laten we niet eens beginnen met de komma-eerste stijl in variabele declaraties ...
var a = 1, b = 2, c = 3;
We moeten ons best doen om de talen die we gebruiken tot een goed niveau te leren kennen, zodat we in staat zijn om cargo-culting en overbeveiligde catch-all coderingstechnieken te vermijden. En we moeten erop vertrouwen dat onze collega's en andere ontwikkelaars hetzelfde doen.
We hebben ook gesproken over het opgeven van cruft om te profiteren van de eigenaardigheden en impliciete regels van een taal. Voor sommigen schept dit onderhoudsproblemen, vooral als iemand die junior is in het verwerven van een bepaalde taal de code benadert. Bijvoorbeeld, wat als ze niet weten over de zwakke vs. strikte gelijkheid van JavaScript?
Op het gebied van onderhoudbaarheid worden we herinnerd aan dit beroemde citaat:
Altijd coderen alsof de persoon die uw code onderhoudt, een gewelddadige psychopaat is die weet waar u woont.
Ik weet niet of dat echt een goed advies is. Zelfs metaforisch genomen, suggereert dit een wantrouwen ten aanzien van de competentie van de fictieve onderhouder - en de noodzaak om zich zorgen te maken over hun begrip boven al het andere. Ik zou liever code schrijven in de wetenschap dat er voor gezorgd zal worden door mensen die hun dingen weten. Dus als een mogelijke tegenspraak of zelfs een addendum bij dat citaat, bied ik aan:
Altijd coderen alsof de persoon die uiteindelijk uw code onderhoudt kennis heeft van de taal en de constructies en probeert het probleemdomein te begrijpen door uw code te lezen.
Hoewel dit misschien niet altijd waar is, moeten we ernaar streven dat het zo is. We moeten proberen ervoor te zorgen dat mensen die werken aan een specifieke technologie voldoende begrip hebben om dit te doen. De geleerde cargo-culter zegt:
Als ik voor eeuwig me beperk op een lager niveau van begrip in mijn code - zacht betreden - strikt vasthouden aan conventies en stijlgidsen en dingen die ik zie dat de "experts" doen, dan kan ik nooit mijn eigen inzicht bevorderen, noch profiteren van een taal in al zijn raarheid en schoonheid. Ik ben gelukkig en zalig gezonken in deze wereld van regels en absoluutheden, maar om verder te gaan, moet ik deze wereld verlaten en hoger begrip omhelzen.