Klasse vs fabriksfunktion: udforske vejen frem
Discover Functional JavaScript blev udnævnt til en af de bedste nye funktionelle programmeringsbøger af BookAuthority !
ECMAScript 2015 (aka ES6) kommer med class
syntaksen, så nu har vi to konkurrerende mønstre til at skabe objekter. For at sammenligne dem opretter jeg den samme objektdefinition (TodoModel) som en klasse,og derefter som en fabriksfunktion.
TodoModel som en klasse
class TodoModel { constructor(){ this.todos = []; this.lastChange = null; } addToPrivateList(){ console.log("addToPrivateList"); } add() { console.log("add"); } reload(){} }
TodoModel som en fabriksfunktion
function TodoModel(){ var todos = []; var lastChange = null; function addToPrivateList(){ console.log("addToPrivateList"); } function add() { console.log("add"); } function reload(){} return Object.freeze({ add, reload }); }
Indkapsling
Det første vi bemærker er, at alle medlemmer, felter og metoder til et klasseobjekt er offentlige.
var todoModel = new TodoModel(); console.log(todoModel.todos); //[] console.log(todoModel.lastChange) //null todoModel.addToPrivateList(); //addToPrivateList
Manglen på indkapsling kan skabe sikkerhedsproblemer. Tag eksemplet på et globalt objekt, der kan ændres direkte fra Developer Console.
Når du bruger fabriksfunktion, er kun de metoder, vi udsætter, offentlige, alt andet er indkapslet.
var todoModel = TodoModel(); console.log(todoModel.todos); //undefined console.log(todoModel.lastChange) //undefined todoModel.addToPrivateList(); //taskModel.addToPrivateList is not a function
dette
this
at miste kontekstproblemer er der stadig, når du bruger klasse. For eksempel this
er at miste sammenhæng i indlejrede funktioner. Det er ikke kun irriterende under kodning, men det er også en konstant kilde til fejl.
class TodoModel { constructor(){ this.todos = []; } reload(){ setTimeout(function log() { console.log(this.todos); //undefined }, 0); } } todoModel.reload(); //undefined
eller this
mister kontekst, når metoden bruges som tilbagekald, som ved en DOM-begivenhed.
$("#btn").click(todoModel.reload); //undefined
Der er ingen sådanne problemer, når du bruger en fabriksfunktion, da den slet ikke bruger this
.
function TodoModel(){ var todos = []; function reload(){ setTimeout(function log() { console.log(todos); //[] }, 0); } } todoModel.reload(); //[] $("#btn").click(todoModel.reload); //[]
dette og pil funktion
Pile-funktionen løser delvist de this
løsende kontekstproblemer i klasser, men skaber samtidig et nyt problem:
this
mister ikke længere sammenhæng i indlejrede funktionerthis
mister kontekst, når metoden bruges som tilbagekald- pilfunktion fremmer brugen af anonyme funktioner
Jeg refactored TodoModel
brug af pilen funktion. Det er vigtigt at bemærke, at vi i processen med refactoring til pilfunktionen kan miste noget meget vigtigt for læsbarheden, funktionsnavnet. Se for eksempel på:
//using function name to express intent setTimeout(function renderTodosForReview() { /* code */ }, 0); //versus using an anonymous function setTimeout(() => { /* code */ }, 0);
Discover Functional JavaScript blev udnævnt til et afbedste nye funktionelle programmeringsbøger fra BookAuthority !
For mere om anvendelse af funktionelle programmeringsteknikker i React, se på Functional React .
Lær funktionel reaktion på en projektbaseret måde med funktionel arkitektur med React og Redux .
Følg på Twitter