Pidev segadus: miks ma ikkagi JavaScripti funktsioonide avaldusi kasutan

Veel 90ndate lõpus - kui ma õppisin JavaScripti - õpetati meid funktsiooni "Hello World" kirjutama funktsiooni avalduse abil . Nagu nii…

function helloWorld() { return ‘Hello World!’; }

Tänapäeval näib, et kõik lahedad lapsed kirjutavad funktsiooni “Tere maailm” niimoodi ...

const helloWorld = () => 'Hello World!';

See on ES2015 JavaScripti funktsiooniväljend ja see on pagana seksikas. Seda on ilus vaadata. See kõik on üks rida. Nii napisõnaline. Nii armas.

See kasutab noolefunktsiooni, mis on üks ES2015 kõige populaarsemaid funktsioone.

Kui ma seda esimest korda nägin, olin selline:

Niisiis, pärast peaaegu 20 aastat JavaScripti ja pärast ES2015 kasutamist paljudes projektides, kirjutaksin täna funktsiooni “Tere maailm” järgmiselt:

function helloWorld() { return ‘Hello World!’; }

Nüüd, kui olen teile uut viisi näidanud, olen kindel, et suudate vaevalt seista, et vaadata ülaltoodud vana kooli koodi.

Kolm tervet rida lihtsalt lihtsa funktsiooni jaoks! Kõik need lisategelased!

Ma tean, mida sa mõtled ...

Ma armastan noole funktsioone, ma tõesti. Kuid kui pean oma koodis deklareerima tipptasemel funktsiooni, kasutan siiski head vanamoodsat funktsiooni.

See onu Bobi Martini tsitaat selgitab, miks:

„... lugemiseks kulutatud aja suhe kirjutamisse on tublisti üle 10: 1. Uue koodi kirjutamise osana loeme pidevalt vana koodi.

Kuna see suhe on nii kõrge, tahame, et koodi lugemine oleks lihtne, isegi kui see kirjutamist raskendab. "

- Robert C. Martin

Puhas kood: vilgas tarkvara meisterdamise käsiraamat

Funktsioonilausetel on funktsiooni avaldiste ees kaks selget eelist:

Eelis nr 1: kavatsuste selgus

Tuhandete koodiridade kaudu päevas skaneerides on kasulik osata võimalikult kiiresti ja hõlpsalt aru saada programmeerija kavatsustest.

Vaadake seda:

const maxNumberOfItemsInCart = ...;

Lugesite kõiki neid märke ja te ei tea ikkagi, kas ellips tähistab funktsiooni või mõnda muud väärtust. See võib olla:

const maxNumberOfItemsInCart = 100;

... või võib sama lihtsalt olla:

const maxNumberOfItemsInCart = (statusPoints) => statusPoints * 10;

Kui kasutate funktsiooni lauset, pole sellist ebaselgust.

Vaata:

const maxNumberOfItemsInCart = 100;

… Versus:

function maxNumberOfItemsInCart(statusPoints) { return statusPoints * 10; }

Kavatsus on kristallselge juba rea ​​algusest peale.

Kuid võib-olla kasutate koodiredaktorit, millel on mõned värvikodeerimise vihjed. Võib-olla olete kiirlugeja. Võib-olla sa lihtsalt ei usu, et see nii suur asi on.

Ma kuulen sind. Jäme näib endiselt üsna seksikas.

Tegelikult, kui see oleks minu ainus põhjus, oleksin võinud leida viisi enda veenmiseks, et see on väärt kompromiss.

Kuid see pole minu ainus põhjus ...

Eelis nr 2: deklaratsiooni järjekord == täitmise järjekord

Ideaalis tahaksin deklareerida oma koodi enam-vähem selles järjekorras, mis eeldab, et see täidetakse.

See on minu jaoks showstopper: kõik väärtused, mis on deklareeritud kasutades const märksõna, pole ligipääsetavad, kuni täitmine selleni jõuab.

Õiglane hoiatus: ma lähen teile kõik, "professor JavaScript". Ainuke asi, mida peate kogu allpool toodud žargoonis mõistma, on see, et enne, kui olete selle deklareerinud, ei saa konstanti kasutada .

Järgmine kood loob vea:

sayHelloTo(‘Bill’); const sayHelloTo = (name) => `Hello ${name}`;

Seda seetõttu, kui JavaScript mootori loeb koodi, siis seovad "sayHelloTo", kuid see ei initsialiseerida ta.

Kõik JavaScripti deklaratsioonid on varakult seotud, kuid initsialiseeritakse erinevalt.

Teisisõnu, JavaScript seob deklaratsiooni „sayHelloTo” - loeb selle kõigepealt ette ja loob mällu ruumi selle väärtuse hoidmiseks - kuid see ei määra „sayHelloTo” millekski enne, kui see selle täitmise ajal jõuab .

Ajavahemikku „sayHelloTo” sidumise ja „sayHelloTo” initsialiseerimise vahel nimetatakse ajaliseks surnud tsooniks (TDZ).

Kui kasutate ES2015 otse brauseris (erinevalt ES5-le ülekandmisest midagi sellist, nagu Babel), viskab tõrke ka järgmine kood:

if(thing) { console.log(thing); } const thing = 'awesome thing';

The code above, written using “var” instead of “const”, would not throw an error because vars get initialized as undefined when they are bound, whereas consts are not initialized at all at bind time. But I digress…

Function statements do not suffer from this TDZ problem. The following is perfectly valid:

sayHelloTo(‘Bill’); function sayHelloTo(name) { return `Hello ${name}`; }

This is because function statements get initialized as soon as they are bound — before any code is executed.

So, no matter when you declare the function, it will be available to its lexical scope as soon as the code starts executing.

What I’ve just described above forces us to write code that looks upside down. We have to start with the lowest level function and work our way up.

My brain doesn’t work that way. I want the context before the details.

Most code is written by humans. So it makes sense that most people’s order of understanding roughly follows most code’s order of execution.

In fact, wouldn’t it be nice if we could provide a little summary of our API at the top of our code? With function statements, we totally can.

Check out this (somewhat contrived) shopping cart module…

export { createCart, addItemToCart, removeItemFromCart, cartSubTotal, cartTotal, saveCart, clearCart, } function createCart(customerId) {...} function isValidCustomer(customerId) {...} function addItemToCart(item, cart) {...} function isValidCart(cart) {...} function isValidItem(item) {...} ...

With function expressions it would look something like…

... const _isValidCustomer = (customerId) => ... const _isValidCart = (cart) => ... const _isValidItem = (item) => ... const createCart = (customerId) => ... const addItemToCart = (item, cart) => ... ... export { createCart, addItemToCart, removeItemFromCart, cartSubTotal, cartTotal, saveCart, clearCart, }

Imagine this as a larger module with many small internal functions. Which would you prefer?

There are those who will argue that using something before you’ve declared it is unnatural, and can have unintended consequences. There are even extremely smart people who have said such things.

It is definitely an opinion — not a fact — that one way is better than the other.

But if you ask me: Code is communication. Good code tells a story.

I’ll let the compilers and the transpilers, the minifiers and the uglyfiers, deal with optimizing code for the machines.

I want to optimize my code for human understanding.

What about those arrow functions, though?

Yes. Still sexy and still awesome.

I typically use arrow functions to pass a small function as a value to a higher order function. I use arrow functions with promises, with map, with filter, with reduce. They are the bees knees, my friends!

Some examples:

const goodSingers = singers.filter((singer) => singer.name !== 'Justin Bieber'); function tonyMontana() { return getTheMoney() .then((money) => money.getThePower()) .then((power) => power.getTheWomen()); }

I used a few other new JavaScript features in this article. If you want to learn more about the latest JavaScript standard (ES2015) and all the cool features it has to offer, you should get my quick start guide for free.

Minu eesmärk on alati aidata võimalikult paljusid arendajaid. Kui leiate, et see artikkel on kasulik, vajutage nuppu ❤ (soovita), et teised seda näeksid. Aitäh!