ご意見募集系の質問が良くないのはわかってますが、ご容赦ください。はい、具体的な課題が含まれていません。いえ、決して銀のバッジが欲しいから質問数を稼いでるわけではありません。あー、ベストアンサーはできるかぎり選ばせていただきたいと思います。
###クラス vs クロージャの塊
Javascript で、継承がない場合は、クラスで定義しなくても、クロージャをメンバに持つオブジェクトを生成する関数を作ることでコンストラクタを作れますよね?ここでは、このパターンをクロージャの塊と呼ぶことにします。
例を示します。ファイルから JSON オブジェクトの配列を読み込んで要素を追加して書き戻すだけのプログラムです。ES6で書いてます。
クラスで書いた場合:
javascript
1import fs from 'babel-fs'; 2 3export default class Users { 4 constructor(usersJSONPath) { 5 this.usersJSONPath = usersJSONPath; 6 } 7 load() { 8 return fs.readFile(this.usersJSONPath).then(data => { 9 try { 10 this.userList = JSON.parse(data); 11 return this; 12 } catch (err) { 13 return Promise.reject(new Error('JSON parse error on reading file '+ this.usersJSONPath + ':' + err)); 14 } 15 }, err => { 16 return Promise.reject(new Error('Fail to read users data:' + err)); 17 }); 18 } 19 flush() { 20 return fs.writeFile(this.usersJSONPath, JSON.stringify(this.userList, '', ' ')).then( data => { 21 return this; 22 }, err => { 23 return Promise.reject(new Error('Fail to write users data :' + err)); 24 }); 25 } 26 getAll() { 27 return this.userList; 28 } 29 add(user) { 30 var userIndex = this.userList.findIndex(one => one.userid===user.userid); 31 if (userIndex >= 0) { 32 return Promise.reject(new Error('User id = "' + user.userid + '" is already registered.')); 33 } 34 this.userList.push(user); 35 return this; 36 } 37} 38 39Promise.resolve(new Users("test.json")) 40 .then(users => {return users.load();}) 41 .then(users => {return users.add({userid:"xyz", passwd:"zzz"});}) 42 .then(users => {return users.add({userid:"abc", passwd:"ccc"});}) 43 .then(users => {return users.flush();}) 44 .then(users => {console.log(JSON.stringify(users.getAll(),'',' '))}) 45 .catch(err => console.error(err.stack));
クロージャの塊で書いた場合:
javascript
1import fs from 'babel-fs'; 2 3export default function buildUsers(usersJSONPath) { 4 var userList = []; 5 var handlers = { 6 load() { 7 return fs.readFile(usersJSONPath).then(data => { 8 try { 9 userList = JSON.parse(data); 10 return handlers; 11 } catch (err) { 12 return Promise.reject(new Error('JSON parse error on reading file '+ usersJSONPath + ':' + err)); 13 } 14 }, err => { 15 return Promise.reject(new Error('Fail to read users data:' + err)); 16 }); 17 }, 18 flush() { 19 return fs.writeFile(usersJSONPath, JSON.stringify(userList, '', ' ')).then( data => { 20 return handlers; 21 }, err => { 22 return Promise.reject(new Error('Fail to write users data :' + err)); 23 }); 24 }, 25 getAll() { 26 return userList; 27 }, 28 add(user) { 29 var userIndex = userList.findIndex(one => one.userid===user.userid); 30 if (userIndex >= 0) { 31 return Promise.reject(new Error('User id = "' + user.userid + '" is already registered.')); 32 } 33 userList.push(user); 34 return handlers; 35 } 36 } 37 return handlers; 38} 39 40Promise.resolve(buildUsers("test.json")) 41 .then(users => {return users.load()}) 42 .then(users => {return users.add({userid:"xyz", passwd:"zzz"});}) 43 .then(users => {return users.add({userid:"abc", passwd:"ccc"});}) 44 .then(users => {return users.flush()}) 45 .then(users => {console.log(JSON.stringify(users.getAll(),'',' '))}) 46 .catch(err => console.error(err.stack));
質問1. クロージャの塊のパターンには呼び名がありますでしょうか? あれば教えて下さい。
質問2. javascript のクラスって継承をしないときでも使ったほうがいいのでしょうか?
C→C++→Java からきた私には、クラスのほうが自然なので、何か概念モデルがわかりにくいなぁと思いながらも、クラスでコーディングしようとしていました。しかし、Javascript で書かれたいろいろなプログラムを見ていると、結構クロージャの塊パターンが多くて、見慣れてくると Javascript にとっては、そっちのほうが自然なように見えてきました。
上の例でいいますと、usersJSONPath, userList, handlers が自由変数になっており、クロージャ間で共有されています。これらはクラスの場合だとインスタンス変数になるところですが、new せずにインスタンスができるところが、ラムダ式っぽくてスマートなように見えます。this も prototype も new も不要です。
もちろん、継承がある場合はクロージャの塊では対応できないと思いますが、継承のないクラスであれば、クロージャの塊のほうが Javascript にとっては自然なような気がしてきて質問しています。
頂いた回答から派生した質問を追加させていただきます。
質問3. クロージャの塊パターンでは関数オブジェクトが大量にできてしまい、性能負担になる場合がありそうなことを教えていただきました。その点を考慮して、シングルトンにしか使わなければ、クロージャの塊パターンでも問題は無いと考えて良いでしょうか?
質問4. オブジェクトを new を使わずに生成するパターンでも this を使って自由変数を避けるができることを教えていただきました。自由変数、クロージャを避けたほうが良い理由というのはありますでしょうか?
回答3件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/10/05 09:15
2016/10/05 10:05
2016/10/05 10:27
2016/10/05 11:46 編集