Class vs Factory function: exploring the way forward - Lee-hyuna/33-js-concepts-kr GitHub Wiki

Class vs Factory function: ์•ž์œผ๋กœ์˜ ๊ธธ์„ ๋ชจ์ƒ‰ํ•˜๋‹ค.

ECMAScript 2015(์ผ๋ช… ES6)๋Š” ํด๋ž˜์Šค ๊ตฌ๋ฌธ๊ณผ ํ•จ๊ป˜ ์ œ๊ณต๋˜๋ฏ€๋กœ ์ด์ œ ์šฐ๋ฆฌ๋Š” ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ๋‘ ๊ฐ€์ง€ ๊ฒฝ์Ÿ ํŒจํ„ด์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ๋น„๊ตํ•˜๊ธฐ ์œ„ํ•ด ํด๋ž˜์Šค์™€ ๋™์ผํ•œ ๊ฐ์ฒด ์ •์˜(TodoModel)๋ฅผ ๋งŒ๋“  ๋‹ค์Œ Factory function๋กœ ๋งŒ๋“ค์–ด ๋ด…๋‹ˆ๋‹ค.

TodoModel as a Class

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

TodoModel as a Factory Function

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

Encapsulation (์บก์Šํ™”)

์šฐ๋ฆฌ๊ฐ€ ์•Œ์•„์ฐจ๋ฆด ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ ํด๋ž˜์Šค ๊ฐ์ฒด์˜ ๋ชจ๋“  ๊ตฌ์„ฑ์›, fields ๊ทธ๋ฆฌ๊ณ  methods๊ฐ€ public์ด๋ผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

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

์บก์Šํ™”์˜ ๋ถ€์กฑ์€ ๋ณด์•ˆ ๋ฌธ์ œ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค. Developer Console์—์„œ ์ง์ ‘ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋Š” ์ „์—ญ ๊ฐ์ฒด์˜ ์˜ˆ๋ฅผ ๋“ค์–ด ๋ณด์‹ญ์‹œ์˜ค. Factory function๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์šฐ๋ฆฌ๊ฐ€ ๊ณต๊ฐœํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋งŒ public์ด ๋˜๊ณ , ๋‚˜๋จธ์ง€๋Š” ์บก์Šํ™”๋ฉ๋‹ˆ๋‹ค.

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

this

this๊ฐ€ context ์žƒ๋Š” ๋ฌธ์ œ๋Š” ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ• ๋•Œ ์—ฌ์ „ํžˆ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด this๋Š” ์ค‘์ฒฉ๋œ ํ•จ์ˆ˜์—์„œ context๋ฅผ ์žƒ์–ด ๋ฒ„๋ฆฌ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์ฝ”๋”ฉ ๊ณผ์ •์—์„œ ์งœ์ฆ๋‚˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ ๋ฒ„๊ทธ์˜ ์ง€์†์ ์ธ ์›์ฒœ์ด๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.

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

๋˜๋Š” this๋Š” ๋ฉ”์†Œ๋“œ๊ฐ€ DOM ์ด๋ฒคํŠธ์™€ ๊ฐ™์ด ์ฝœ๋ฐฑ์œผ๋กœ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ context๋ฅผ ์žƒ์–ด ๋ฒ„๋ฆฌ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

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

Factory function๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์ด์™€ ๊ฐ™์€ ๋ฌธ์ œ๋Š” ์ „ํ˜€ ์—†์Šต๋‹ˆ๋‹ค.

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

this ๊ทธ๋ฆฌ๊ณ  arrow function

Arrow function๋Š” ๋ถ€๋ถ„์ ์œผ๋กœ ํด๋ž˜์Šค์˜ context ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์ง€๋งŒ ๋™์‹œ์— ์ƒˆ๋กœ์šด ๋ฌธ์ œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

  • this๋Š” ๋” ์ด์ƒ ์ค‘์ฒฉ ๋œ ํ•จ์ˆ˜์—์„œ context๋ฅผ ์žƒ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ๋ฉ”์„œ๋“œ๊ฐ€ ์ฝœ๋ฐฑ์œผ๋กœ ์‚ฌ์šฉ๋  ๋•Œ this๋Š” context๋ฅผ ์žƒ์–ด ๋ฒ„๋ฆฝ๋‹ˆ๋‹ค.
  • Arrow function๋Š” ์ต๋ช… ํ•จ์ˆ˜์˜ ์‚ฌ์šฉ์„ ์ด‰์ง„ํ•ฉ๋‹ˆ๋‹ค.

Arrow function์„ ์‚ฌ์šฉํ•˜์—ฌ TodoModel์„ ๋ฆฌํŒฉํ† ๋งํ–ˆ์Šต๋‹ˆ๋‹ค. Arrow function์œผ๋กœ ๋ฆฌํŒฉํ† ๋งํ•˜๋Š” ๊ณผ์ •์—์„œ ์šฐ๋ฆฌ๋Š” ๊ฐ€๋…์„ฑ์„ ์œ„ํ•ด ๋งค์šฐ ์ค‘์š”ํ•œ ํ•จ์ˆ˜ ์ด๋ฆ„ ์ธ loose๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์— ์œ ์˜ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋ณด์‹ญ์‹œ์˜ค:

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

Discover Functional JavaScript๋Š” BookAuthority๊ฐ€ ๊ฐœ๋ฐœ ํ•œ ์ตœ๊ณ ์˜ ์ƒˆ๋กœ์šด Functional Programming eBook ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค!