JavaScriptには、JavaScriptでクラス/名前空間を作成および管理するための、いくつかの明らかに目立つテクニックがあります。
ある手法と他の手法のどちらを使用する必要があるのか、知りたいです。一つ選んでこれからも頑張りたいです。
複数のチームで保守および共有されるエンタープライズコードを作成していますが、保守可能なJavaScriptを作成する際のベストプラクティスを知りたいのですが?
私は自己実行匿名機能を好む傾向がありますが、私はこれらの手法に対するコミュニティの投票が何であるかに興味があります。
プロトタイプ:
function obj()
{
}
obj.prototype.test = function() { alert('Hello?'); };
var obj2 = new obj();
obj2.test();
自己完結型匿名関数:
//Self-Executing Anonymous Function
(function( skillet, $, undefined ) {
//Private Property
var isHot = true;
//Public Property
skillet.ingredient = "Bacon Strips";
//Public Method
skillet.fry = function() {
var oliveOil;
addItem( "\t\n Butter \n\t" );
addItem( oliveOil );
console.log( "Frying " + skillet.ingredient );
};
//Private Method
function addItem( item ) {
if ( item !== undefined ) {
console.log( "Adding " + $.trim(item) );
}
}
}( window.skillet = window.skillet || {}, jQuery ));
//Public Properties
console.log( skillet.ingredient ); //Bacon Strips
//Public Methods
skillet.fry(); //Adding Butter & Fraying Bacon Strips
//Adding a Public Property
skillet.quantity = "12"; console.log( skillet.quantity ); //12
//Adding New Functionality to the Skillet
(function( skillet, $, undefined ) {
//Private Property
var amountOfGrease = "1 Cup";
//Public Method
skillet.toString = function() {
console.log( skillet.quantity + " " +
skillet.ingredient + " & " +
amountOfGrease + " of Grease" );
console.log( isHot ? "Hot" : "Cold" );
};
}( window.skillet = window.skillet || {}, jQuery ));
//end of skillet definition
try {
//12 Bacon Strips & 1 Cup of Grease
skillet.toString(); //Throws Exception
} catch( e ) {
console.log( e.message ); //isHot is not defined
}
自己実行の匿名関数はjQueryチームが使用するパターンであることを私は言及する必要があると思います。
更新この質問をしたとき、自分が理解しようとしていることの重要性が本当にわかりませんでした。手元にある実際の問題は、オブジェクトのインスタンスを作成するためにnewを使用するか、コンストラクター/ new
キーワードの使用を必要としないパターンを使用するかどうかです。
私の意見では、new
キーワードを使用しないパターンを使用する必要があるため、自分の回答を追加しました。
詳細については、私の回答を参照してください。
更新 javascriptについての理解が深まり、質問に適切に対応できると感じています。私はそれは言葉遣いが悪いが、対処する非常に重要なjavascriptトピックだったと思います。
自己実行匿名関数パターンは、関数の外でこれを使用しない場合に新しいキーワードを使用する必要があるパターンではありません。 newの使用は古い手法であるという考えに同意します。代わりに、newの使用を回避するパターンの使用に努めるべきです。
自己実行匿名関数はこの基準を満たしています。
この質問への答えは主観的です。JavaScriptには非常に多くのコーディングスタイルがあるためです。ただし、私の調査と経験に基づいて、APIを定義し、可能な場合は常に新しいAPIを使用しないように、自己実行匿名関数を使用することをお勧めします。
自己実行匿名関数は、外部イベント(つまりwindow.onload)にフックすることなくスクリプトの実行を自動化するために使用されます。
この例では、クラシックモジュールパターンを形成するために使用されます。その主な目的は、グローバル環境に名前空間を導入し、そうでない内部プロパティにencapsulationを提供することです名前空間に「エクスポート」またはアタッチされます。
一方、オブジェクトプロトタイプの変更は、継承の確立(またはネイティブの拡張)に使用されます。このパターンは、一般的なメソッドまたはプロパティを持つ1:nオブジェクトを生成するために使用されます。
preferenceで1つのパターンを選択しないでください。他のパターンは異なるタスクを実行するためです。ネームスペースに関しては、自己実行機能が適切な選択です。
これが私が使用し始めたパターンです(昨日までそのバリエーションを使用してきました):
function MyClass() {
// attributes
var privateVar = null;
// function implementations
function myPublicFunction() {
}
function myPrivateFunction() {
}
// public declarations
this.myPublicFunction = myPublicFunction;
}
MyClass.prototype = new ParentClass(); // if required
これに関するいくつかの考え:
(anonymous)
デバッガースタック内のトレースは、すべてが指定されたものとしてトレースします(無名関数はありません)。私がprototype
を使用するのは、本当に継承を定義するときだけです。
私はprototypesを使用しています。これは、それらがよりクリーンで、標準の継承パターンに従っているためです。自己呼び出し機能は、ブラウザの開発や、コードがどこで実行されているのかわからない場合に最適ですが、それ以外の場合は単なるノイズです。
例:
var me;
function MyObject () {
this.name = "Something";
}
MyObject.prototype.speak = function speak () {
return "Hello, my name is " + this.name;
};
me = new MyObject();
me.name = "Joshua";
alert(me.speak());
私は自己実行機能を使いますが、少し違いがあります:
MyClass = (function() {
var methodOne = function () {};
var methodTwo = function () {};
var privateProperty = "private";
var publicProperty = "public";
return function MyClass() {
this.methodOne = methodOne;
this.methodTwo = methodTwo;
this.publicProperty = publicProperty;
};
})();
返されたグローバル変数を任意の入力パラメーター(jQueryなど)から分離しているため、このアプローチがはるかにクリーンであることがわかった場合(これを書き込んだ方法は、voidを返し、C#でrefパラメーターを使用することと同じです。ポインターをポインターに渡し、それをC++で再割り当てする)。次に、クラスに追加のメソッドまたはプロパティをアタッチする場合、プロトタイプの継承を使用します(jQueryの$ .extendメソッドの例ですが、独自のextend()をロールするのは簡単です)。
var additionalClassMethods = (function () {
var additionalMethod = function () { alert('Test Method'); };
return { additionalMethod: additionalMethod };
})();
$.extend(MyClass.prototype, additionalClassMethods);
var m = new MyClass();
m.additionalMethod(); // Pops out "Test Method"
このようにして、追加されたメソッドと元のメソッドを明確に区別します。
(function _anonymouswrapper(undefined) {
var Skillet = {
constructor: function (options) {
options && extend(this, options);
return this;
},
ingredient: "Bacon Strips",
_isHot: true,
fry: function fry(oliveOil) {
this._addItem("\t\n Butter \n\t");
this._addItem(oliveOil);
this._addItem(this.ingredient);
console.log("Frying " + this.ingredient);
},
_addItem: function addItem(item) {
console.log("Adding " + item.toString().trim());
}
};
var skillet = Object.create(Skillet).constructor();
console.log(skillet.ingredient);
skillet.fry("olive oil");
var PrintableSkillet = extend(Object.create(Skillet), {
constructor: function constructor(options) {
options && extend(this, options);
return this;
},
_amountOfGrease: "1 Cup",
quantity: 12,
toString: function toString() {
console.log(this.quantity + " " +
this.ingredient + " & " +
this._amountOfGrease + " of Grease");
console.log(this._isHot ? "Hot" : "Cold");
}
});
var skillet = Object.create(PrintableSkillet).constructor();
skillet.toString();
function extend(target, source) {
Object.getOwnPropertyNames(source).forEach(function (name) {
var pd = Object.getOwnPropertyDescriptor(source, name);
Object.defineProperty(target, name, pd);
});
return target;
}
}());
IIFEを使用して、コードの「モジュールスコープ」をエミュレートできます。その後、通常どおりオブジェクトを使用できます。
クロージャーを使用してプライベート状態を「エミュレート」しないでください。クロージャーを使用すると、メモリのペナルティが大きくなります。
エンタープライズアプリケーションを作成していて、メモリ使用量を1GB未満に維持したい場合は、不必要にクロージャを使用して状態を保存しないでください。
これが、IIFE
をMyclass.anotherFunction()
で拡張するために、このSelfExecutingFunction
Myclass
をどのように使用するかです。
MyClass = (function() {
var methodOne = function () {};
var methodTwo = function () {};
var privateProperty = "private";
var publicProperty = "public";
//Returning the anonymous object {} all the methods and properties are reflected in Myclass constructor that you want public those no included became hidden through closure;
return {
methodOne = methodOne;
methodTwo = methodTwo;
publicProperty = publicProperty;
};
})();
@@@@@@@@@@@@@@@@@@@@@@@@
//then define another IIFE SEF to add var function=anothermethod(){};
(function(obj){
return obj.anotherfunction=function(){console.log("Added to Myclass.anotherfunction");};
})(Myclass);
//the last bit : (function(obj){})(Myclass); obj === Myclass obj is an alias to pass the Myclass to IIFE
var myclass = new Myclass();
myclass.anotherfunction(); //"Added to Myclass.anotherfunction"