JavaScriptã®ãã¶ã€ã³ãã¿ãŒã³å°çšã®æ¬¡ã®Bill Soroãããªã¢ã«ã®ç¿»èš³ã«æ³šç®ããŠãã ããã
åå ROROãã¿ãŒã³ã«ã€ããŠè©±ããŸããããä»æ¥ã®ããŒãã¯Ice Factoryãã¿ãŒã³ã§ãã ç°¡åã«èšãã°ããã®ãã³ãã¬ãŒãã¯ãåçµããªããžã§ã¯ããè¿ãé¢æ°ã§ãã ããã¯éåžžã«éèŠã§åŒ·åãªãã¿ãŒã³ã§ããã解決ããããšãç®çãšããJSåé¡ã®1ã€ã«ã€ããŠèª¬æããŠãããŸãã

JavaScriptã¯ã©ã¹ã®åé¡
å€ãã®å Žåãé¢é£ããæ©èœãåäžã®ãªããžã§ã¯ãã«ã°ã«ãŒãåãã䟡å€ããããŸãã ããšãã°ããªã³ã©ã€ã³ã¹ãã¢ã¢ããªã±ãŒã·ã§ã³ã«ã¯ããããªãã¯ã¡ãœãã
addProduct
ããã³
removeProduct
ãå«ã
cart
ãªããžã§ã¯ããããå ŽåããããŸãã ãããã®ã¡ãœããã¯ã
cart.addProduct()
ããã³
cart.removeProduct()
ã³ã³ã¹ãã©ã¯ãã䜿çšããŠ
cart.addProduct()
ããšãã§ããŸãã
JavaãCïŒãªã©ã®èšèªããJavaScriptéçºã«æ¥ãå Žåãã¯ã©ã¹ãæåç·ã«ããããã¹ãŠããªããžã§ã¯ãã«çŠç¹ãåãããŠããå Žåãäžèšã®ç¶æ³ã¯ããããå®å
šã«èªç¶ãªãã®ãšããŠèªèãããŸãã
ããã°ã©ãã³ã°ãç¿ãå§ããã°ããã§ããã°ãä»ã¯
cart.addProduct()
ãšãã圢åŒã®åŒã«ç²ŸéããŠããŸãã ãããŠãåäžã®ãªããžã§ã¯ãã®ã¡ãœããã«ãã£ãŠè¡šãããé¢æ°ãã°ã«ãŒãåãããšããèãæ¹ããããªãã«ãšã£ãŠæããã ãšæããŸãã
cart
ãªããžã§ã¯ãã®äœææ¹æ³ã«ã€ããŠèª¬æããŸãããã ãããããçŸä»£ã®JavaScriptã®æ©èœãèãããšãæåã«æãæµ®ãã¶ã®ã¯ã
class
ããŒã¯ãŒãã«ã¢ã¯ã»ã¹ããããšã§ãã ããšãã°ã次ã®ããã«ãªããŸãã
// ShoppingCart.js export default class ShoppingCart { constructor({db}) { this.db = db } addProduct (product) { this.db.push(product) } empty () { this.db = [] } get products () { return Object .freeze(this.db) } removeProduct (id) { // } // } // someOtherModule.js const db = [] const cart = new ShoppingCart({db}) cart.addProduct({ name: 'foo', price: 9.99 })
db
ãã©ã¡ãŒã¿ãšããŠé
åã䜿çšããŠããããšã«æ³šæããŠãã ããã ããã¯ãäŸãåçŽåããããã«è¡ãããŸãã å®éã®ã³ãŒãã§ã¯ããã®ãããªå€æ°ã¯ãå®éã®ããŒã¿ããŒã¹ãšããåããã
ModelãŸãã¯
Repoãªããžã§ã¯ãã®ãããªãã®ã§è¡šãããŸãã
æ®å¿µãªãããããã¯ãã¹ãŠèŠæ ãã¯è¯ããã®ã®ãJavaScriptã®ã¯ã©ã¹ã®åäœã¯äºæ³ãšã¯ãŸã£ããç°ãªããŸãã æ¯urçã«èšãã°ãJSã§ã¯ã©ã¹ãæäœãããšãã«æ³šæãæ ããšãåã¿ä»ãããå¯èœæ§ããããŸãã
ããšãã°ã
new
ããŒã¯ãŒãã䜿çšããŠäœæããããªããžã§ã¯ãã¯å€æŽå¯èœã§ãã ããã¯ãããšãã°ãã¡ãœããããªãŒããŒã©ã€ãã§ããããšãæå³ããŸãã
const db = [] const cart = new ShoppingCart({db}) cart.addProduct = () => 'nope!'
å®éã
new
ããŒã¯ãŒãã䜿çšããŠäœæããããªããžã§ã¯ãã¯ããããã®äœæã«äœ¿çšãããã¯ã©ã¹ã®ãããã¿ã€ããç¶æ¿ãããããããã«æªåããŸãã ãããã£ãŠããã®ã¯ã©ã¹ã®ãããã¿ã€ãã®å€æŽã¯ããã®ã¯ã©ã¹ã«åºã¥ããŠäœæããããã¹ãŠã®ãªããžã§ã¯ãã«åœ±é¿ãããããã®å€æŽããªããžã§ã¯ãã®äœæåŸã«è¡ãããå Žåã§ãåæ§ã§ãã
以äžã«äŸã瀺ããŸãã
const cart = new ShoppingCart({db: []}) const other = new ShoppingCart({db: []}) ShoppingCart.prototype .addProduct = () => 'nope!' // ! cart.addProduct({ name: 'foo', price: 9.99 }) // : "nope!" other.addProduct({ name: 'bar', price: 8.88 }) // : "nope!"
次ã«ãJavaScriptã®
this
åçãã€ã³ãã£ã³ã°ãèŠããŠãããŠãã ããã
cart
ãªããžã§ã¯ãã®ã¡ãœãããã©ããã«æž¡ããšã
this
ãžã®å
ã®åç
§ã倱ãããå¯èœæ§ããããŸãã ãã®åäœã¯çŽæçã§ã¯ãªããå€ãã®åé¡ã®åå ã«ãªãå¯èœæ§ããããŸãã
this
ãããã°ã©ãã«é©ããŠããéåžžã®è¿·æã¯ããªããžã§ã¯ãã¡ãœãããã€ãã³ããã³ãã©ã«å²ãåœãŠãããŠããå Žåã§ãã ãã¹ã±ããã空ã«ããããã®
cart.empty
ã¡ãœãããèããŸãïŒ
empty () { this.db = [] }
ãã®ã¡ãœãããWebããŒãžäžã®ç¹å®ã®ãã¿ã³ã®
click
ã€ãã³ããã³ãã©ãŒã«å²ãåœãŠãŸãã
<button id="empty"> Empty cart </button> --- document .querySelector('#empty') .addEventListener( 'click', cart.empty )
ãŠãŒã¶ãŒããã®ãã¿ã³ãã¯ãªãã¯ããŠããäœãå€ãããŸããã
cart
ãªããžã§ã¯ãã§è¡šããããã¹ã±ããã¯ãã£ã±ãã®ãŸãŸã§ãã
åæã«ãããã¯ãã¹ãŠãšã©ãŒã¡ãã»ãŒãžãªãã§çºçããŸãã
this
ã¯ããã¹ã±ããã§ã¯ãªããã¿ã³ã䜿çšããå¿
èŠãããããã§ãã ãã®çµæã
cart.empty
ãåŒã³åºããšã
cart
ãªããžã§ã¯ãã®
db
ããããã£ã«åœ±é¿ãäžããã®ã§ã¯ãªãã
db
ãšããååã®ãã¿ã³ã®æ°ããããããã£ãäœæããããã®ããããã£ã«ç©ºã®é
åãå²ãåœãŠãããŸãã
ãã®ãšã©ãŒã¯ãéçºè
ãæåéãçãããããšãã§ãããã®ã®ã«ããŽãªã«å±ããŸããããã¯ãäžæ¹ã§ã¯ãšã©ãŒã¡ãã»ãŒãžããªããä»æ¹ã§ã¯åžžèã®èŠ³ç¹ããã¯éåžžã«æ©èœããå®éã«ã¯ãã®ããã«åäœããªãã³ãŒãäºæ³éãã
äžèšã®ã³ãŒãã«æåŸ
ã©ããã®åŠçã匷å¶ããã«ã¯ã次ã®ããã«ããå¿
èŠããããŸãã
document .querySelector("#empty") .addEventListener( "click", () => cart.empty() )
ãŸãã¯ïŒ
document .querySelector("#empty") .addEventListener( "click", cart.empty.bind(cart) )
ãã®ãããªã§ã¯ãããããã¹ãŠã®åªãã説æãèŠã€ããããšãã§ãããšæããŸãã
ããã®ãããªããã®åŒçšã¯æ¬¡ã®ãšããã§ãã
«new
JavaScriptã®
«new
ãã®ã¯ãéè«ççã§ãå¥åŠã§ãç¥ç§çãªtrapã§ãã
JSã¯ã©ã¹ã®åé¡ã®è§£æ±ºçãšããŠã®Ice Factoryãã¿ãŒã³
æ¢ã«è¿°ã¹ãããã«ãIce Factoryãã¿ãŒã³ã¯ããåçµããªããžã§ã¯ããäœæããŠè¿ãé¢æ°ã§ãã ãã®ãã¶ã€ã³ãã¿ãŒã³ã䜿çšããå Žåãã·ã§ããã³ã°ã«ãŒãã®äŸã¯æ¬¡ã®ããã«ãªããŸãã
// makeShoppingCart.js export default function makeShoppingCart({ db }) { return Object.freeze({ addProduct, empty, getProducts, removeProduct, // }) function addProduct (product) { db.push(product) } function empty () { db = [] } function getProducts () { return Object .freeze(db) } function removeProduct (id) { // } // } // someOtherModule.js const db = [] const cart = makeShoppingCart({ db }) cart.addProduct({ name: 'foo', price: 9.99 })
ãå¥åŠã§ç¥ç§çãªtrapããæ¶ããããšã«æ³šæããŠãã ããã ã€ãŸãããã®ã³ãŒããåæããŠã次ã®çµè«ãå°ãåºãããšãã§ããŸãã
new
ããŒã¯ãŒãã¯äžèŠã«ãªãnew
ã ããã§ã cart
ãªããžã§ã¯ããäœæããã«ã¯ãéåžžã®JSé¢æ°ãåŒã³åºããŸãã
this
äžèŠã«ãªããŸããã ããã§ããªããžã§ã¯ãã®ã¡ãœããããçŽæ¥db
ã¢ã¯ã»ã¹ã§ããŸãã
- çŸåšã
cart
ãªããžã§ã¯ãã¯äžå€ã§ãã Object.freeze()
ã³ãã³ãã¯ãããããªãŒãºããŸãã ããã«ãããæ°ããããããã£ãè¿œå ããããæ¢åã®ããããã£ãåé€ãŸãã¯å€æŽããããšã¯ã§ããŸããã ãŸãããããã¿ã€ããå€æŽã§ããŸããã ããã§ã¯ã Object.freeze()
ã³ãã³ãããªããžã§ã¯ãã®ãããããå°ããªããªãŒãºããå®è¡ããããšã ããèŠããŠãã䟡å€ããããŸãã ã€ãŸããè¿ããããªããžã§ã¯ãã«é
åãŸãã¯å¥ã®ãªããžã§ã¯ããå«ãŸããŠããå Žåã Object.freeze()
ã³ãã³ãããããã«é©çšããå¿
èŠããããŸãã ããã«ãåçµããããªããžã§ã¯ããESã¢ãžã¥ãŒã«ã®å€éšã§äœ¿çšãããå Žåããªããžã§ã¯ãã«å€æŽãå ããããšãããšãã«ãšã©ãŒãçæãããããšãä¿èšŒããããã«ã å³æ Œã¢ãŒãã䜿çšããå¿
èŠããããŸãã
ãã©ã€ããŒãããããã£ãšã¡ãœãã
Ice Factoryãã³ãã¬ãŒãã®ãã1ã€ã®å©ç¹ã¯ããã³ãã¬ãŒãã§äœæããããªããžã§ã¯ãã«ãã©ã€ããŒãããããã£ãšã¡ãœãããå«ããããšãã§ããããšã§ãã äŸãèããŠã¿ãŸãããïŒ
function makeThing(spec) { const secret = 'shhh!' return Object.freeze({ doStuff }) function doStuff () { // spec, // secret } } // secret const thing = makeThing() thing.secret // undefined
ããã¯ãã¯ããŒãžã£ãŒã¡ã«ããºã ã®ãããã§å¯èœ
ã§ã ãã¯ããŒãžã£ãŒã¡ã«ããºã ã®è©³çŽ°ã«ã€ããŠã¯ã
ãã¡ããåç
§ããŠãã ãã ã
Ice Factoryãã¿ãŒã³ã®èµ·æºã«ã€ããŠ
Factory Functionsã¯åžžã«JavaScriptã«å«ãŸããŠããŸãããIce Factoryãã¿ãŒã³ãèšèšããããã«
ãã°ã©ã¹ã¯ããã¯ãã©ãŒãã
ãã®ãããªã§ç€ºããã³ãŒãã«çå£ã«è§ŠçºãããŸããã ããã¯ã圌ããã³ã³ã¹ãã©ã¯ã¿ãŒããšåŒã¶é¢æ°ã䜿çšããŠãªããžã§ã¯ãã®äœæãå®èšŒããã·ã§ããã§ãã
ãã°ã©ã¹ã»ã¯ããã¯ãã©ãŒãã¯ç§ã«ã€ã³ã¹ãã¬ãŒã·ã§ã³ãäžããã³ãŒãã瀺ããŠããŸãCrockfordã瀺ãããã®ã®ããªãšãŒã·ã§ã³ã§ããç§ã®ããŒãžã§ã³ã®ã³ãŒãã¯ã次ã®ããã«ãªããŸãã
function makeSomething({ member }) { const { other } = makeSomethingElse() return Object.freeze({ other, method }) function method () { // , "member" } }
ãäžæãé¢æ°ãå©çšããŠããªã¿ãŒã³åŒãã³ãŒãã®äžéšã«è¿ã¥ããŸããã ãã®çµæã詳现ãæãäžããåã«ããã®ã³ãŒããããã«èªã人ã¯ãäœãèµ·ãã£ãŠããã®ãã«ã€ããŠã®å
šäœåãèŠãããšãã§ããŸãã
ããã«ã
spec
ãã©ã¡ãŒã¿ãŒãç Žæ£ããããã«äœ¿çšããŸããã ãŸãããã®ãã³ãã¬ãŒãã«ååãä»ããŠãIce Factoryãšããååãä»ããŸããã èŠãããããJSã¯ã©ã¹ã®
constructor
é¢æ°ãšæ··åãã«ãããšæããŸãã ããããäžè¬çã«ãç§ã®ãã¿ãŒã³ãšã³ã³ã¹ãã©ã¯ã¿ãŒã¯ãŸã£ããåãã§ãã
ãããã£ãŠããã®ãã¿ãŒã³ã®äœæè
ã«ã€ããŠè©±ããŠããå Žåãããã¯ãã°ã©ã¹ã»ã¯ããã¯ãã©ãŒãã«å±ããŸãã
Crockfordã¯æ©èœåŒ·åãJavaScriptã®ã匱ç¹ããšèŠãªããŠãããããããããç§ã®ã¢ãããŒãã¯æ°ã«å
¥ããªãã§ãããã ããã«å¯Ÿããç§ã®æ
床ã«ã€ããŠã¯ã
以åã®èšäºã® 1ã€ãç¹ã«
ãã®è§£èª¬ã§èª¬æããŸããã
ç¶æ¿ãšè£œæ°·å·¥å Ž
ãªã³ã©ã€ã³ã¹ãã¢çšã®ã¢ããªã±ãŒã·ã§ã³ã®äœæã«ã€ããŠèãç¶ãããšããã¹ã±ãããæäœãããšãã«è£œåãè¿œå ããã³åé€ãããšããæŠå¿µãããŸããŸãªå Žæã«äœåºŠãçŸããããšãããã«ç解ã§ããŸãã
è²·ãç©ããã«å ããŠããããããªããžã§ã¯ãã«ã¿ãã°ïŒ
Catalog
ïŒãšæ³šæïŒ
Order
ïŒããããŸãã åæã«ããããã®ãªããžã§ã¯ãã«ã¯ãå€ãã®å ŽåãéããŠãã
addProduct
removeProduct
ãš
removeProduct
ããªã¢ã³ãããã
removeProduct
ã
ã³ãŒãã®è€è£œãæªãããšã¯ããã£ãŠãããããæçµçã«ã¯ãã¹ã±ãããã«ã¿ãã°ã泚æãªããžã§ã¯ããç¶æ¿ãã補åã®ãªã¹ãã§ãã
productList
ãªããžã§ã¯ãã®ãããªãã®ãäœæããããšã«ãªããŸãã
Ice Factoryãã³ãã¬ãŒãã䜿çšããŠäœæããããªããžã§ã¯ãã¯å±éã§ããªããããä»ã®ãªããžã§ã¯ãããç¶æ¿ããããšã¯ã§ããŸããã ãããèããŠãã³ãŒãã®è€è£œãã©ãããŸããïŒ ååã®ãªã¹ãã§ãããªããžã§ã¯ãã䜿çšããããšã§ãããã€ãã®ã¡ãªãããåŸãããšãã§ããŸããïŒ
ãã¡ããã§ããŸãïŒ
Ice Factoryãã¿ãŒã³ã¯ãæã圱é¿åã®ããããã°ã©ãã³ã°ã®æ¬ã®1ã€ã§ããããªããžã§ã¯ãæåããã°ã©ãã³ã°ãã¯ããã¯ãã§åŒçšãããŠããæ°žé ã®ååãé©çšããããã«å°ããŸãã ãã¶ã€ã³ãã¿ãŒã³ãã ãã®ååïŒãã¯ã©ã¹ç¶æ¿ãããæ§æãåªå
ãããã
Gang of FourãšããŠç¥ããããã®æ¬ã®èè
ã¯ã次ã®ããã«è¿°ã¹ãŠããŸãããããããç§ãã¡ã®çµéšã¯ããã¶ã€ããŒãç¶æ¿ãä¹±çšããŠããããšã瀺ããŠããŸãã å€ãã®å Žåãäœæè
ããªããžã§ã¯ãã®æ§æã«ãã£ãšäŸåããã°ãèšèšã¯ããè¯ãç°¡åã«ãªããŸããã
ã ãããããã«è£œåã®ãªã¹ãããããŸãïŒ
function makeProductList({ productDb }) { return Object.freeze({ addProduct, empty, getProducts, removeProduct, // )} // // addProduct ... } : function makeShoppingCart({ addProduct, empty, getProducts, removeProduct, // }) { return Object.freeze({ addProduct, empty, getProducts, removeProduct, someOtherMethod, // )} function someOtherMethod () { // } }
ããã§ã補åã®ãªã¹ããè¡šããªããžã§ã¯ãããã¹ã±ãããè¡šããªããžã§ã¯ãã«ç°¡åã«åã蟌ãããšãã§ããŸãã
const productDb = [] const productList = makeProductList({ productDb }) const cart = makeShoppingCart(productList)
ãŸãšã
äœãæ°ããããšãåŠã¶ãšããç¹ã«ã¢ããªã±ãŒã·ã§ã³ãèšèšããããã®ã¢ãŒããã¯ãã£ãŒã¢ãããŒããªã©ãããªãè€éãªããšã«ãªããšãç§ãã¡ã¯åŠã¶ããšã«é¢ããæ確ãªã«ãŒã«ãæåŸ
ããåŸåããããŸãã ç§ãã¡ã¯æ¬¡ã®ãããªããšãèââããããšæã£ãŠããŸãïŒãåžžã«ãããè¡ããããã決ããŠããªããã
ãœãããŠã§ã¢éçºç°å¢ã§ã®ããŒããŒã·ã§ã³ãé·ããã°é·ãã»ã©ããåžžã«ãã決ããŠããšããæŠå¿µã¯ãªãããšãããç解ã§ããŸãã ããã°ã©ããŒã¯åžžã«ãç¹å®ã®ç¶æ³ã«é©çšãããç¹å®ã®ææ³ã®é·æãšçæã®çµã¿åããã«ãã£ãŠæ±ºå®ãããéžæè¢ãæã£ãŠããŸãã
äžèšã§ã¯ãIce Factoryãã¿ãŒã³ã®é·æã«ã€ããŠèª¬æããŸããã ãããã圌ã«ã¯æ¬ ç¹ããããŸãã ãããã¯ããã®ãã¿ãŒã³ã䜿çšãããªããžã§ã¯ãã®äœæãã¯ã©ã¹ã䜿çšãããããé
ããããå€ãã®ã¡ã¢ãªãå¿
èŠãšãããšããäºå®ã«ãããŸãã
äžèšã®ãã®ãã¿ãŒã³ã®äœ¿çšã§ã¯ããããã®ãã€ãã¹ã¯åé¡ã«ãªããŸããã ç¹ã«ãIce Factoryã¯ã¯ã©ã¹ã䜿çšãããããé
ããªããŸããããã®ãã¿ãŒã³ã¯éåžžã«é«éã«åäœããŸãã
ããã°äœåäžãã®ãªããžã§ã¯ããäœæããå¿
èŠãããå ŽåããŸãã¯ããã©ãŒãã³ã¹ãšã¡ã¢ãªæ¶è²»ãæåç·ã«ããç¶æ³ã«ããå Žåã¯ãéåžžã®ã¯ã©ã¹ã®æ¹ãããããé©ããŠããŸãã
äž»ãªãã®-ã¢ããªã±ãŒã·ã§ã³ã®ãããã¡ã€ã«ãäœæããããšãå¿ããªãã§ãã ããããŸããææå°æ©ãªæé©åã«åªããŸããã ãªããžã§ã¯ãã®äœæãããã°ã©ã ã®ããã«ããã¯ã«ãªãããšã¯ãã£ãã«ãããŸããã
ç§ãäžã§èšã£ããšããäºå®ã«ãããããããJSã¯ã©ã¹ã®æ©èœã¯åžžã«äžå©ãšèŠãªããããšã¯éããŸããã ããšãã°ãã¯ã©ã¹ãããã§äœ¿çšãããŠãããšããçç±ã ãã§ã©ã€ãã©ãªãŸãã¯ãã¬ãŒã ã¯ãŒã¯ãæåŠããã¹ãã§ã¯ãããŸããã
ããã¯ããã®ããŒãã«é¢ãã
ãã³ã»ã¢ãã©ã¢ãã®åªããè³æã§ãã
ãããŠæåŸã«ãäžã§åŒçšããã³ãŒãã¹ããããã§ã¯ã絶察çãªçå®ã®ãããªãã®ã§ã¯ãªããèªåã®å¥œã¿ã ãã§æ±ºãŸãå€ãã®ã¢ãŒããã¯ãã£ãœãªã¥ãŒã·ã§ã³ã䜿çšããããšãèªããªããã°ãªããŸããã ãããã®ããã€ãã次ã«ç€ºããŸãã
ã³ãŒãã¹ã¿ã€ã«ã«ã¯ä»ã®ã¢ãããŒãã䜿çšã§ããŸãããããã¯
å®å
šã«æ£åžžã§ãã ã¹ã¿ã€ã«ã¯ãã¿ãŒã³ã§ã¯ãããŸããã
äžè¬ã«ãIce Factoryã®èšèšãã¿ãŒã³ã¯ãåçµãªããžã§ã¯ããäœæããŠè¿ãé¢æ°ã䜿çšããããšã«èŠçŽãããŸãã ãããŠããã®ãããªé¢æ°ãã©ã®ããã«æ£ç¢ºã«æžããã¯ãèªåã§æ±ºããããšãã§ããŸãã
芪æãªãèªè
ïŒ ãããžã§ã¯ãã§Ice Factoryãã¿ãŒã³ã®ãããªãã®ã䜿çšããŠããŸããïŒ