3

以下を使用して関数を宣言する専門家を見てきました。

(function () {
  function f(n) {
        // Format integers to have at least two digits.
        return n < 10 ? '0' + n : n;
    }
  //etc

}());

例: https://github.com/douglascrockford/JSON-js/blob/master/json.js

上記のパターンをいつ使用する必要があり、どのように使用するかを誰かが理解するのを手伝ってくれませんか?

ありがとう。

4

3 に答える 3

2

まあ、ECMA6 はまだ到着していないので、関数は JS でスコープを作成する最良の方法です。ある種の変数宣言を IIFE (即時呼び出し関数式) でラップすると、その変数はグローバルには作成されません。関数宣言についても同様です。
スクリプトからすべてのグローバル変数をクリアするという一見困難なタスクを与えられた場合、スクリプト全体を単純な でラップするだけでよく(function(){/*script here*/}());、暗黙のグローバルにならないようにグローバルは作成されませんが、それはただの怠惰な修正です。 . このパターンはもっと強力です。

IIFE の使用については、こちらこちら、およびこちらの両方で詳しく説明しました。

基本的な JS 関数呼び出しのライブ サイクルの並べ替えは、次のように機能します。

f();//call function
 ||
 ====> inside function, some vars are created, along with the arguments object
        These reside in an internal scope object
     ==> function returns, scope object (all vars and args) are GC'ed

JS のすべてのオブジェクトと同様に、オブジェクトが参照されなくなるとすぐに、GC (ガベージ コレクション) のフラグが立てられます。ただし、次の点を考慮してください。

var foo = (function()
{
    var localFoo = {bar:undefined};
    return function(get, set)
    {
        if (set === undefined)
        {
            return localFoo[get];
        }
        return (localFoo[get] = set);
    }
}());

IIFE が戻ると、別の関数である戻り値が foo に割り当てられます。現在localFooは IIFE のスコープで宣言されており、そのオブジェクトに直接アクセスする方法はありません。一見すると、GC されていると思うかもしれませんlocalFoo
しかし、待ってください、返されている関数 (およびに割り当てられている関数はfooまだそのオブジェクトを参照しているため、gcできません。つまり、スコープ オブジェクトは関数呼び出しよりも長く存続し、クロージャーが作成されます。

変数がスコープ外になるか、別の値が再割り当てされ、返された関数へのすべての参照が失われるまでlocalFoo、オブジェクトは GC されません。foo

リンクされた回答の1つ(図付きのもの)を見てください。その回答には、使用した画像を盗んだ記事へのリンクがあります。これがまだ解決されていない場合は、これで問題が解決するはずです。

IIFE は何も返すことができませんが、関係なくそのスコープを公開します。

var foo = {};
(function(obj)
{
    //obj references foo here
    var localFoo = {};
    obj.property = 'I am set in a different scope';
    obj.getLocal = function()
    {
        return localFoo;
    };
}(foo));

この IIFE は何も返しませんが (暗黙的undefinedに)、console.log(foo.getLocal())空のオブジェクト リテラルをログに記録します。foo自体も割り当てられpropertyます。でも待ってください、私はあなたにもう1つうまくやることができます。上記のコードで foo が 1 回渡されたとします。

var bar = foo.getLocal();
bar.newProperty = 'I was added using the bar reference';
bar.getLocal = function()
{
    return this;
};
console.log(foo.getLocal().newProperty === bar.newProperty);
console.log(bar ==== foo.getLocal());
console.log(bar.getLocal() === foo.getLocal().getLocal());
//and so on

これは何をログに記録しますか? 確かに、true何度も何度もログに記録されます。JS ではオブジェクトがコピーされることはなく、その参照はコピーされますが、オブジェクトは常に同じです。あるスコープで一度変更すると、それらの変更はすべての参照間で (論理的に) 共有されます。
これは、クロージャーが最初は理解するのが難しいことを示すためのものですが、クロージャーがいかに強力であるかも示しています。さまざまな IIFE を介してオブジェクトを渡すことができ、そのたびに独自のメソッドにアクセスできる新しいメソッドを設定できます。 、他のメソッドが到達できない一意のスコープ。

注:
クローザーは、JS エンジンがガベージ コレクションを実行するのにそれほど簡単ではありませんが、最近ではそれほど大きな問題ではなくなりました。
また、時間をかけてこれらの用語をグーグルで検索してください。

IIFE も関数に名前を付けることができますが、その関数を参照できる唯一の場所はその関数のスコープ内です。

(function init (obj)
{
    //obj references foo here
    var localFoo = {};
    obj.property = 'I am set in a different scope';
    obj.getLocal = function()
    {
        return localFoo;
    };
    if (!this.wrap)
    {//only assign wrap if wrap/init wasn't called from a wrapped object (IE foo)
        obj.wrap = init;
    }
}(foo));
var fooLocal = foo.getLocal();
//assign all but factory methods to fooLocal:
foo.wrap(fooLocal);
console.log(fooLocal.getLocal());//circular reference, though
console.log(init);//undefined, the function name is not global, because it's an expression

これは、クロージャを使用してラッパー オブジェクトを作成する方法の基本的な例にすぎません...

于 2013-06-05T12:10:59.007 に答える
1

ブラウザーベースの JavaScript で使用できるスコープは、Global と Function の 2 つだけです。これは、作成した変数がグローバル スコープ内にあるか、現在使用している関数のスコープに限定されていることを意味します。

場合によっては、多くの場合、初期化中に、一度しか必要としない一連の変数が必要になることがあります。それらをグローバルスコープに入れるのは適切ではありません。特別な関数でそれを実行したくないからです。

即時機能を入力してください。これは、定義された直後に呼び出される関数です。それが、Crockford (およびその他) のコードで見られるものです。関数の名前は関数本体に対してローカルであるため、グローバルスコープの汚染を回避するという目的を損なうことなく、匿名または名前付きにすることができます。

関数をそのままにしておくことなく、変数を含めるためのスコープを提供します。物事をきれいに保ちます。

于 2013-06-05T12:14:36.923 に答える
1

さて、上記のパターンは即時関数と呼ばれます。この関数は 3 つのことを行います:-

このコードの結果は、1 つのステートメントで次のすべてを実行する式です。

  1. 関数インスタンスを作成します
  2. 関数を実行します
  3. 関数を破棄します (ステートメントが終了した後は関数への参照がなくなるため)

これは、変数と関数の独自のプライベート スコープを作成するため、グローバル スペースを汚染することなく変数と関数を作成するために JS 開発者によって使用されます。

上記の例では、関数 f(){} は即時関数のプライベート スコープにあり、グローバルまたはウィンドウ スコープでこの関数を呼び出すことはできません。

于 2013-06-05T12:11:43.240 に答える