質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
87.20%
ECMAScript

ECMAScriptとは、JavaScript類の標準を定めるために作られたスクリプト言語です。

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

関数型プログラミング

関数型プログラミングとは、関数を用いて演算子を構築し、算出し、コンピュータプログラムを構成する枠組みです。

解決済

javascript のクラスって継承をしないときでも使ったほうがいいの?

mit0223
mit0223

総合スコア3360

ECMAScript

ECMAScriptとは、JavaScript類の標準を定めるために作られたスクリプト言語です。

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

関数型プログラミング

関数型プログラミングとは、関数を用いて演算子を構築し、算出し、コンピュータプログラムを構成する枠組みです。

3回答

5評価

14クリップ

6506閲覧

投稿2016/10/05 07:47

編集2016/10/05 09:24

ご意見募集系の質問が良くないのはわかってますが、ご容赦ください。はい、具体的な課題が含まれていません。いえ、決して銀のバッジが欲しいから質問数を稼いでるわけではありません。あー、ベストアンサーはできるかぎり選ばせていただきたいと思います。

###クラス vs クロージャの塊

Javascript で、継承がない場合は、クラスで定義しなくても、クロージャをメンバに持つオブジェクトを生成する関数を作ることでコンストラクタを作れますよね?ここでは、このパターンをクロージャの塊と呼ぶことにします。

例を示します。ファイルから JSON オブジェクトの配列を読み込んで要素を追加して書き戻すだけのプログラムです。ES6で書いてます。

クラスで書いた場合:

javascript

import fs from 'babel-fs'; export default class Users { constructor(usersJSONPath) { this.usersJSONPath = usersJSONPath; } load() { return fs.readFile(this.usersJSONPath).then(data => { try { this.userList = JSON.parse(data); return this; } catch (err) { return Promise.reject(new Error('JSON parse error on reading file '+ this.usersJSONPath + ':' + err)); } }, err => { return Promise.reject(new Error('Fail to read users data:' + err)); }); } flush() { return fs.writeFile(this.usersJSONPath, JSON.stringify(this.userList, '', ' ')).then( data => { return this; }, err => { return Promise.reject(new Error('Fail to write users data :' + err)); }); } getAll() { return this.userList; } add(user) { var userIndex = this.userList.findIndex(one => one.userid===user.userid); if (userIndex >= 0) { return Promise.reject(new Error('User id = "' + user.userid + '" is already registered.')); } this.userList.push(user); return this; } } Promise.resolve(new Users("test.json")) .then(users => {return users.load();}) .then(users => {return users.add({userid:"xyz", passwd:"zzz"});}) .then(users => {return users.add({userid:"abc", passwd:"ccc"});}) .then(users => {return users.flush();}) .then(users => {console.log(JSON.stringify(users.getAll(),'',' '))}) .catch(err => console.error(err.stack));

クロージャの塊で書いた場合:

javascript

import fs from 'babel-fs'; export default function buildUsers(usersJSONPath) { var userList = []; var handlers = { load() { return fs.readFile(usersJSONPath).then(data => { try { userList = JSON.parse(data); return handlers; } catch (err) { return Promise.reject(new Error('JSON parse error on reading file '+ usersJSONPath + ':' + err)); } }, err => { return Promise.reject(new Error('Fail to read users data:' + err)); }); }, flush() { return fs.writeFile(usersJSONPath, JSON.stringify(userList, '', ' ')).then( data => { return handlers; }, err => { return Promise.reject(new Error('Fail to write users data :' + err)); }); }, getAll() { return userList; }, add(user) { var userIndex = userList.findIndex(one => one.userid===user.userid); if (userIndex >= 0) { return Promise.reject(new Error('User id = "' + user.userid + '" is already registered.')); } userList.push(user); return handlers; } } return handlers; } Promise.resolve(buildUsers("test.json")) .then(users => {return users.load()}) .then(users => {return users.add({userid:"xyz", passwd:"zzz"});}) .then(users => {return users.add({userid:"abc", passwd:"ccc"});}) .then(users => {return users.flush()}) .then(users => {console.log(JSON.stringify(users.getAll(),'',' '))}) .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 を使って自由変数を避けるができることを教えていただきました。自由変数、クロージャを避けたほうが良い理由というのはありますでしょうか?

良い質問の評価を上げる

以下のような質問は評価を上げましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

気になる質問をクリップする

クリップした質問は、後からいつでもマイページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

まだ回答がついていません

会員登録して回答してみよう

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
87.20%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

ECMAScript

ECMAScriptとは、JavaScript類の標準を定めるために作られたスクリプト言語です。

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

関数型プログラミング

関数型プログラミングとは、関数を用いて演算子を構築し、算出し、コンピュータプログラムを構成する枠組みです。