Функция Class vs Factory: исследование пути вперед

funkcziya class vs factory issledovanie puti vpered

Откройте для себя функциональный 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);

Откройте для себя функциональный JavaScript был назван одним из лучшие новые книги по функциональному программированию от BookAuthority!

Чтобы узнать больше о методах функционального программирования в React, просмотрите Функциональный React.

учиться функциональный Reactпроектно, с Функциональная архитектура с React и Redux.

Подписывайтесь на Twitter

Добавить комментарий

Ваш адрес email не будет опубликован.