まず最初に、「メイン」IIFEを呼び出すという事実はns
、それを名前空間オブジェクトと見なしていることを示唆していますが、これは完全には正しくありません。名前空間は、クロージャスコープの利点が追加されているため、IIFEを使用して作成されることがよくあります。しかし、結局のところ、名前空間はObject(リテラル)の単なる空想の言葉です。
最も人気のあるlib/toolkit /frameworkを取り出してください:jQuery。基本的に、これは1つの巨大なIIFEであり、同じように広大なオブジェクトを構築し、いくつかのメソッドとプロパティが割り当てられます(とにかく関数オブジェクトへの参照)。そのIIFEで作成された他のオブジェクトと変数がいくつかありますが、それらはグローバルオブジェクトにまったく公開されていないか、(非常に)間接的に公開されています。
明確にさせてください:
var myNameSpace = (function()
{
var invisibleVar = 'can\'t touch this';
var objectLiteral = {sing: function()
{
return invisibleVar;//exposed, albeit indirectly
},
property: 'Hammertime'
};
var semiExposed;
objectLiteral.getSemi = function(newVal)
{
return semiExposed;//change closure var
};
objectLiteral.changeSemi = function(newVal)
{
semiExposed = newVal;//change closure var
};
objectLiteral.restoreSemi = (function(initVal)
{
return function()
{
semiExposed = initVal;//restore to value set when main IIFE was executed
//don't worry about what this references: use the force... of the scope
return objectLiteral.getSemi();//<-- return init val
};
}(semiExposed));//pass initial value to this scope
var notExposedAtAll = function()
{//can't be called but inside the main IIFE scope (and subsequent scopes)
objectLiteral.foo = 'But it adds a public property';
};
objectLiteral.changeMe = function()
{
notExposedAtAll();//called in default context (either null or global, but it doesn't matter here)
};
return objectLiteral;//direct exposure
}());
これは、すべてのツールキット/ライブラリの基本プリンシパルの一部を使用し、実際にはすべての適切なJSスクリプトが共有します。関数をファーストクラスオブジェクトとして使用し、それらを式として使用して一時スコープを作成するなど...)
IMO、IIFEの適切なケースになります:スコープを使用すると、オブジェクトを変数に割り当てるための十分な時間が与えられるため、メソッドの作成方法(IIFEの有無に関係なく)this
に関係なく、いつでもどの参照を使用するかを気にする必要はありません。変数。
いくつかの基本的なデータ非表示を実装することもできます。この例では、の初期値がsemiExposed
IIFEに渡され、そのスコープ内に保持されます。何もこれを台無しにすることはできません(まあ、それは現時点では完全に真実ではありません)ので、あなたはいつでもできます任意のプロパティの初期値に戻します。
ただし、IIFEを使用すると、コードが大きくなるにつれてコードが読みにくくなる可能性があることを認めます。また、IIFEを使いすぎない理由を完全に理解しています。あなたは調べることができますbind
、それはあなたが多くのIIFEを減らすのを助けるでしょう、しかし欠点があります。たとえば、一部のpplはまだIE8を使用していますが、これはをサポートしていませんbind
。
しかし、他のオプションは次のようになります。単純なIIFEファクトリ関数を作成します。
function giveScope(varsFromScope,toFunction)
{
return function()
{
var passArguments = Array.prototype.slice.apply(arguments,[0]);//get args from call
passArguments.push({scope:varsFromScope});
toFunction.apply(this,passArguments);
};
}
var pseudoClosure = giveScope({scopeContext: this, something:'else'},function(arg1,arg2)
{
//function body here
arguments[arguments.length - 1].currentContext;//<== "closure scope"
this;//called context
});
そうすれば、オブジェクトを渡す単純な関数呼び出しに置き換えることで、いくつかのIIFEを取り除くことができます。簡単で、Xブラウザと互換性があります。
最後に、最初のスニペットは、イベントの委任で使用する傾向があるものです。
var target = e.target || e.srcElement;
var parentDiv = (function(targetRef)
{
while(targetRef.tagName.toLowerCase() !== 'div')
{
targetRef = targetRef.parentNode;
}
return targetRef;
}(target));
そうすれば、同じスコープで別の検証可能ファイルを作成する必要はありません。divが見つかったときにtargetRefが割り当てられ、targetRefがGCさparentDiv
れて終了します。したがって、その変数を作成する必要はありません。範囲内にとどまります。
今はかなり遅くなっていて、私があまり意味をなさないかどうかはわかりません。結論は次のとおりです。IIFEは嫌いかもしれませんが、IIFEなしでは実際にはできません。
かっこがたくさんある場合は、かっこを使用する必要がないことを知って喜んでもらえるかもしれません。JSエンジンに関数宣言を式として解釈させる演算子は、次のようになります。
(function()
{
}());
//can be written as:
!function()
{
}();
//or
~function()
{
}();
//or when assigning the return value, you don't even need anything at all:
var foo = function()
{
return 'bar';
}();
console.log(foo);//logs bar
おそらくあなたは別の表記法を好みますか?しかし正直なところ、あなたは構文が気に入らないかもしれませんが、私はあなたがそれと一緒に暮らすか、coffeescriptか何かに切り替える必要があるのではないかと心配しています。