Функція «Клас проти заводу»: вивчення подальшого шляху

Відкрийте функціональний JavaScript було визнано однією з найкращих нових книг про функціональне програмування від BookAuthority !

ECMAScript 2015 (він же ES6) постачається із classсинтаксисом, тому тепер у нас є дві конкуруючі моделі для створення об’єктів. Для їх порівняння я створив те саме визначення об'єкта (TodoModel), що і клас,а потім як заводська функція.

TodoModel як клас

class TodoModel { constructor(){ this.todos = []; this.lastChange = null; } addToPrivateList(){ console.log("addToPrivateList"); } add() { console.log("add"); } reload(){} }

TodoModel як фабрична функція

function TodoModel(){ var todos = []; var lastChange = null; function addToPrivateList(){ console.log("addToPrivateList"); } function add() { console.log("add"); } function reload(){} return Object.freeze({ add, reload }); }

Капсуляція

Перше, що ми помічаємо, це те, що всі члени, поля та методи об’єкта класу є загальнодоступними.

var todoModel = new TodoModel(); console.log(todoModel.todos); //[] console.log(todoModel.lastChange) //null todoModel.addToPrivateList(); //addToPrivateList

Відсутність інкапсуляції може створити проблеми з безпекою. Візьмемо приклад глобального об’єкта, який можна змінити безпосередньо з консолі розробника.

При використанні заводських функцій лише відкриті нами методи є загальнодоступними, а все інше інкапсульовано.

var todoModel = TodoModel(); console.log(todoModel.todos); //undefined console.log(todoModel.lastChange) //undefined todoModel.addToPrivateList(); //taskModel.addToPrivateList is not a function

це

thisпроблеми з втратою контексту все ще існують при використанні класу. Наприклад, thisвтрачає контекст у вкладених функціях. Це не тільки дратує під час кодування, але й постійне джерело помилок.

class TodoModel { constructor(){ this.todos = []; } reload(){ setTimeout(function log() { console.log(this.todos); //undefined }, 0); } } todoModel.reload(); //undefined

або thisвтрачає контекст, коли метод використовується як зворотний виклик, як у випадку DOM.

$("#btn").click(todoModel.reload); //undefined

При використанні заводської функції таких проблем не виникає, оскільки вона взагалі не використовується this.

function TodoModel(){ var todos = []; function reload(){ setTimeout(function log() { console.log(todos); //[] }, 0); } } todoModel.reload(); //[] $("#btn").click(todoModel.reload); //[]

це і функція стрілки

Функція стрілки частково вирішує проблеми thisвтрати контексту в класах, але в той же час створює нову проблему:

  • this більше не втрачає контекст у вкладених функціях
  • this втрачає контекст, коли метод використовується як зворотний виклик
  • Функція стрілки сприяє використанню анонімних функцій

Я переробив за TodoModelдопомогою функції стрілки. Важливо зазначити, що в процесі рефакторингу функції стрілки ми можемо втратити щось дуже важливе для читабельності ім’я функції. Подивіться наприклад:

//using function name to express intent setTimeout(function renderTodosForReview() { /* code */ }, 0); //versus using an anonymous function setTimeout(() => { /* code */ }, 0);

Discover Functional JavaScript був названий одним ізнайкращі нові книги про функціональне програмування від BookAuthority !

Докладніше про застосування методів функціонального програмування в React погляньте на Functional React .

Вивчіть функціональний React на основі проекту за допомогою функціональної архітектури з React та Redux .

Підпишіться на Twitter