web-dev-qa-db-ja.com

JavaScriptの「抽象」関数のベストプラクティス?

クロージャといくつかの関数を使用してオブジェクトを作成するためのグッドプラクティスと思われるものに沿って、次のJavaScriptコードを記述しました。

var myStuff = (function() {
 var number = 0;
 var fn = {};
 fn.increment = function() { number++; };
 fn.decrement = function() { number--; };
 fn.getNumber = function() { return number; };
 return fn;
})();

myStuff.increment();
myStuff.increment();
alert(myStuff.getNumber()); // alerts '2'

前のスニペットのようなコードを書くのに問題はありません。 OOP "abstract"クラスに似た機能を備えたコードを書きたいと思います。これが私の努力の結果です。

var myStuff = (function () {
var number = 0;
var fn = {};
fn.increment = function () { number++; };
fn.decrement = function () { number--; };
fn.doSomethingCrazy = function () { throw new Error('not implemented'); }; // I want to specify later what this does.
fn.doSomethingCrazyTwice = function () { fn.doSomethingCrazy(); fn.doSomethingCrazy(); };
fn.getNumber = function () { return number; };
return fn;
})();

myStuff.doSomethingCrazy = function () { this.increment(); this.increment(); };
myStuff.doSomethingCrazyTwice();
alert(myStuff.getNumber()); // alerts '4'

上記のコードスニペットは機能しますが、適切ではないようです。おそらく私はJavaScript(関数型言語)に設計されていないことを強制しようとしています(オブジェクトの継承)

JavaScriptでオブジェクトを定義して、そのオブジェクトの関数を後で定義できるようにするための良い方法は何ですか?

19

関数を定義しないでください。

Javascriptはduck-typed言語です。アヒルのように見えて、アヒルのように鳴くなら、それはアヒルです。
この作業を行うために特別なことをする必要はありません。呼び出したときに関数が存在する限り、正常に機能します。

関数を持たないインスタンスで呼び出すと、コールサイトでエラーが発生します。

21
SLaks

SLaksに同意します。関数を定義する必要はありませんが、とにかく傾向があります。それは私にとって重要な部分がドキュメントにあるからです。誰かが私のクラスを読んだとき、これらのメソッドを実装する必要があること、どの引数が渡され、何が返されるかを明確にしたいと思います。

これは、作業中のファイルからのものです。間隔を置いてデータの読み込みを行う基本クラスを持つ機能の複数の実装がありました。

/**
 * Called when data is received and should update the data buffer
 * for each of the charts 
 * 
 * @abstract
 * @param {cci.ads.Wave[]} waves
 * @void
 */
updateChartsData: function(waves){
    throw "Abstract method updateChartsData not implemented";
},

2019アップデート

可能であればTypeScriptを使用してください TypeScriptで抽象メソッドを宣言する

9
Juan Mendes

チームが成長し、JavaScriptプロジェクトがより複雑になるにつれて、OO機能の実装も開始する必要があります。

Javascriptの「abstract」メソッドでは、単にエラーをスローするか、アラートをポップアップします。これは、outPageオブジェクトの例です。

Page.initialLoad = function() { //abstract
    alert('Page.initialLoad not implemented');
};

Javaの世界では、次のことに類似しています:

public void abstract initialLoad();

Javaコードはコンパイル時エラーを出しますが、Javascriptではランタイムエラーを受け取ります。実装オブジェクトはまだそのメソッドを実装していません)。

Pageオブジェクトを使用するさまざまなチームがあります。 「ダックタイピング」の哲学は絶対に私たちと一緒にそれをカットしません。これらの疑似「抽象」メソッドがないと、API通信が一般的に不足し、スーパーオブジェクトが妨害されることがあります(つまり、ユーザーがメソッドを実装することになっていることを知らないため)。

私はこの「ダックタイピング」の哲学にうんざりしています。提案者が10人以上の開発者による複雑なJavascriptプロジェクトに参加したことがあるかどうかはわかりません。

7
Oliver Watkins

優雅な方法が見つからない場合は、プロセスを階層化して見栄えを良くするための関数を作成する方法がおそらくあります。しかし、トピックに戻ります...

はい、Javascriptには委任が組み込まれています、別名継承、プロトタイプを介して。

プロトタイプオブジェクトが与えられた場合:

var proto = {
    f: function(){ console.log(this.x); }
}

それを継承する新しいオブジェクトを作成できます。

var obj = Object.create(proto);
obj.x = 42;

obj.f(); //should work!

for(var i in obj) console.log(i);
//should print x, f and some other stuff perhaps

Object.createを介して直接物事を行うことが常にサポートされているわけではないことに注意してください(古いブラウザなど)。古い(そして、normal)と言う人もいますが、物事を行う方法は、ファンキーなnew演算子を使用することです(考えないでください)名前が多すぎる-意図的にJavaの人々)の気を散らすために混乱している

function Constructor(arg){
    this.x = arg;
}

Constructor.prototype = {
    f: function(){ ... }
};

var obj = new Constructor(17);
obj.f();

プロトタイプの継承で考慮すべき重要な違いは、プライベート変数がないことです。 継承できるのはパブリック変数のみです!このため、一般的な規則では、プライベート変数と保護変数のプレフィックスとしてアンダースコアを使用します。

3
hugomg

この前の投稿をご覧になることをお勧めします JavaScriptで抽象基本クラスを作成するにはどうすればよいですか?

OOPとJavaScriptに関するいくつかの簡単な読み物のためのほんのいくつかのサイト、私はあなたのコメントに基づいたOOP言語としてのJavaScriptの初心者だと思います前記

http://mckoss.com/jscript/object.htm

http://www.codeproject.com/KB/aspnet/JsOOP1.aspx

http://www.javascriptkit.com/javatutors/oopjs.shtml

0
Spider