関数 - JavaScriptクロージャはどのように機能しますか?




クロージャ メリット (20)

どのようにあなたは、彼らが構成する概念(例えば、関数、変数など)の知識を持つ人にJavaScriptクロージャを説明しますが、クロージャ自身を理解していませんか?

私はWikipediaで与えられたSchemeの例を見ましが、残念ながらそれは役に立たなかった。


子供たちは、両親がいなくても、彼らが両親と分かち合った秘密をいつも覚えています。これはクロージャが関数のためのものです。

JavaScript関数の秘密はプライベート変数です

var parent = function() {
 var name = "Mary"; // secret
}

呼び出すたびに、ローカル変数 "name"が作成され、 "Mary"という名前が付けられます。関数が終了するたびに変数が失われ、名前は忘れられます。

あなたが推測しているように、関数が呼び出されるたびに変数が再作成され、誰もそれらを知ることはないので、変数が格納される秘密の場所が必要です。これは秘密の部屋と呼ばれることもありますし、スタックローカルスコープと呼ばれることもありますが、それは問題ではありません。私たちは彼らがどこかに存在し、記憶に隠されていることを知っています。

しかし、JavaScriptでは、他の関数の内部で作成された関数、親のローカル変数を知り、生存している限り、それらを保持するという非常に特殊なことがあります。

var parent = function() {
  var name = "Mary";
  var child = function(childName) {
    // I can also see that "name" is "Mary"
  }
}

したがって、私たちが親関数にいる限り、秘密変数を秘密の場所から共有する1つ以上の子関数を作成することができます。

しかし、悲しいことは、もし子供が親の機能の私的な変数でもあれば、親が終わると死ぬだろう、そして秘密は彼らと共に死ぬだろうということです。

生きるために、子供は遅刻する前に出なければならない

var parent = function() {
  var name = "Mary";
  var child = function(childName) {
    return "My name is " + childName  +", child of " + name; 
  }
  return child; // child leaves the parent ->
}
var child = parent(); // < - and here it is outside 

そして今、メアリーは「もはや走っていなくても」、彼女の記憶は失われず、彼女の子供はいつも彼女の名前と一緒に一緒に共有した他の秘密を覚えています。

あなたが子供を「アリス」と呼ぶと、彼女は答えます

child("Alice") => "My name is Alice, child of Mary"

それがすべてです。


ストローマン

私はボタンがクリックされた回数を知り、3回目のクリックごとに何かをする必要があります...

かなり明白な解決策

// Declare counter outside event handler's scope
var counter = 0;
var element = document.getElementById('button');

element.addEventListener("click", function() {
  // Increment outside counter
  counter++;

  if (counter === 3) {
    // Do something every third time
    console.log("Third time's the charm!");

    // Reset counter
    counter = 0;
  }
});
<button id="button">Click Me!</button>

これはうまくいくでしょうが、変数を追加することで外側のスコープに侵入します。その目的はカウントを追跡することです。 場合によっては、外部アプリケーションがこの情報にアクセスする必要がある場合があるため、これが望ましい場合もあります。 しかしこの場合、3回目のクリックごとの動作を変更するだけなので、 この機能をイベントハンドラ内囲むことをお勧めします

このオプションを検討する

var element = document.getElementById('button');

element.addEventListener("click", (function() {
  // init the count to 0
  var count = 0;

  return function(e) { // <- This function becomes the click handler
    count++; //    and will retain access to the above `count`

    if (count === 3) {
      // Do something every third time
      console.log("Third time's the charm!");

      //Reset counter
      count = 0;
    }
  };
})());
<button id="button">Click Me!</button>

ここにいくつか注意してください。

上記の例では、JavaScriptのクロージャー動作を使用しています。 この動作により、任意の関数が作成されたスコープに無期限にアクセスできるようになります。 実際にこれを適用するには、直ちに別の関数を返す関数を呼び出し、返す関数は(前述のクロージャの振る舞いのために)内部のcount変数にアクセスできるため、結果として使用するためのプライベートスコープとなります機能...それほど単純ではない? それを薄くしましょう...

シンプルなワンラインクロージャー

//          _______________________Immediately invoked______________________
//         |                                                                |
//         |        Scope retained for use      ___Returned as the____      |
//         |       only by returned function   |    value of func     |     |
//         |             |            |        |                      |     |
//         v             v            v        v                      v     v
var func = (function() { var a = 'val'; return function() { alert(a); }; })();

返された関数の外にあるすべての変数は、返された関数で使用できますが、返された関数オブジェクトでは直接利用できません。

func();  // Alerts "val"
func.a;  // Undefined

それを得る? したがって、主な例では、count変数はクロージャー内に含まれ、イベントハンドラで常に使用できるため、クリックからクリックまでステートを保持します。

また、このプライベート変数状態は、読み込みとプライベートスコープ変数への割り当ての両方に完全にアクセス可能です。

そこに行く。 この動作を完全にカプセル化しています。

完全なブログ投稿 (jQueryの考慮事項を含む)


あなたは5歳の子供に閉鎖を説明できますか?*

私はまだGoogleの説明がうまく機能し、簡潔であると思う:

/*
*    When a function is defined in another function and it
*    has access to the outer function's context even after
*    the outer function returns.
*
* An important concept to learn in JavaScript.
*/

function outerFunction(someNum) {
    var someString = 'Hey!';
    var content = document.getElementById('content');
    function innerFunction() {
        content.innerHTML = someNum + ': ' + someString;
        content = null; // Internet Explorer memory leak for DOM reference
    }
    innerFunction();
}

outerFunction(1);​

* AC#質問


クロージャは簡単です:

次の簡単な例は、JavaScriptクロージャの主なポイントをすべてカバーしています。 *

ここでは、加算と乗算が可能な計算機を生産する工場があります:

function make_calculator() {
  var n = 0; // this calculator stores a single number n
  return {
    add: function(a) {
      n += a;
      return n;
    },
    multiply: function(a) {
      n *= a;
      return n;
    }
  };
}

first_calculator = make_calculator();
second_calculator = make_calculator();

first_calculator.add(3); // returns 3
second_calculator.add(400); // returns 400

first_calculator.multiply(11); // returns 33
second_calculator.multiply(10); // returns 4000

要点:それぞれの呼び出しmake_calculatorは新しいローカル変数を作成しますn。このローカル変数は、その計算機addmultiply関数によって使用可能な状態になりmake_calculatorます。

スタックフレームに慣れている場合、これらの電卓は奇妙に見えます。返品nmake_calculatorにどうしてアクセスできますか?答えは、JavaScriptが「スタックフレーム」を使用せず、代わりに関数呼び出しの後に保持できる「ヒープフレーム」を使用すると想像することです。

インナーのような関数addmultiply外側の関数で宣言された変数にアクセスし、**は、と呼ばれている閉鎖

それは閉鎖にあるすべてのものです。


*例えば、変数が宣言される前に使用できることを単に示している例6を除いて、別の答えで与えられた "Closure for Dummies"記事のすべての点をカバーしています。引数がローカル変数(名前付き関数引数)にコピーされる点(1)と、(2)数値をコピーすると新しい数値が作成される点を除いて、受け入れられた回答のすべての点をカバーしますが、オブジェクト参照同じオブジェクトに別の参照を与えます。これらは知っていてもよいが、閉鎖とはまったく無関係である。また、この答えの例に非常に似ていますが、少し短くて抽象的ではありません。それはこの答えまたはこのコメントはJavaScriptであり、現在のプラグインあなたの内部関数へのループ変数の値: "プラグイン"ステップは、内部関数を囲み、各ループ反復で呼び出されるヘルパー関数でのみ行うことができます。 (厳密に言えば、内部関数はプラグインされたものではなく、変数のヘルパー関数のコピーにアクセスします。)また、クロージャを作成するときには非常に便利ですが、クロージャが何であるか、変数が記憶空間ではなく値にバインドされているMLのような関数言語では、クロージャが異なる方法で動作するため、追加の混乱があります。つまり、クロージャをある意味で理解している人のストリームを提供しています。変数が常に記憶領域にバインドされ、決して値にバインドされないJavaScriptでは正しくありません。

**いくつかのネストされた外部関数、またはグローバルな文脈であっても、この答えが明確に指摘している。


閉鎖に関するWikipedia

コンピュータサイエンスでは、クロージャは、その関数の非局所的な名前(自由変数)の参照環境とともに関数です。

技術的には、JavaScriptでは、すべての関数はクロージャです。周囲のスコープで定義された変数には常にアクセスできます。

以来JavaScriptで範囲を規定する工事が関数ではなく、他の多くの言語のようにコードブロック、によって我々は通常、何を意味するの閉鎖 JavaScriptではありすでに実行周囲の関数で定義された非ローカル変数を扱う機能

クローズは、隠されたプライベートデータを持つ関数を作成するためによく使用されます(ただし、必ずしもそうではありません)。

var db = (function() {
    // Create a hidden object, which will hold the data
    // it's inaccessible from the outside.
    var data = {};

    // Make a function, which will provide some access to the data.
    return function(key, val) {
        if (val === undefined) { return data[key] } // Get
        else { return data[key] = val } // Set
    }
    // We are calling the anonymous surrounding function,
    // returning the above inner function, which is a closure.
})();

db('x')    // -> undefined
db('x', 1) // Set x to 1
db('x')    // -> 1
// It's impossible to access the data object itself.
// We are able to get or set individual it.

ems

上記の例では、一度実行された無名関数を使用しています。しかし、そうである必要はありません。それmkdbは、呼び出されるたびにデータベース関数を生成し、後で実行され、実行されます(例:)。生成されるすべての関数は、独自の隠しデータベースオブジェクトを持ちます。クロージャの別の使用例は、関数を返さないときですが、目的ごとに複数の関数を含み、それぞれが同じデータにアクセスできるオブジェクトです。


なぜ答えがここで複雑であるのか分かりません。

ここに閉鎖があります:

var a = 42;

function b() { return a; }

はい。 あなたはおそらくそれを1日に数回使用します。


特定の問題に対処するためにクロージャが複雑な設計のハックだと考える理由はありません。いいえ、クロージャは、関数が宣言された(実行されていない)という観点から、より高いスコープから来る変数を使用することです。

今あなたができることは、もっと壮観になることができます、他の答えを見てください。


JavaScript関数は次のものにアクセスできます:

  1. 引数
  2. ローカル(ローカル変数とローカル関数)
  3. 環境には以下が含まれます:
    • DOMを含むグローバル
    • 外部機能のもの

関数がその環境にアクセスすると、その関数はクロージャになります。

外部関数は必須ではありませんが、ここでは説明しない利点があります。環境内のデータにアクセスすることにより、クロージャはそのデータを有効に保ちます。外部/内部関数のサブケースでは、外部関数がローカルデータを作成して終了することができますが、外部関数が終了しても内部関数が存続する場合、内部関数は外部関数のローカルデータを保持します生きている。

グローバル環境を使用するクロージャの例:

上の Vote UpイベントとVote Downボタンイベントは、グローバル変数isVotedUpとisVotedDownにアクセスできるクロージャーvoteUp_clickとvoteDown_clickとして実装されているとします。(簡単にするために、私はのQuestion Voteボタンを参照しています。Answer Voteボタンの配列ではありません)。

ユーザがVoteUpボタンをクリックすると、voteUp_click関数はisVotedDown == trueであるかどうかをチェックして投票するか、単に投票を取り消すかを決定します。関数voteUp_clickは、その環境にアクセスしているためクロージャです。

var isVotedUp = false;
var isVotedDown = false;

function voteUp_click() {
  if (isVotedUp)
    return;
  else if (isVotedDown)
    SetDownVote(false);
  else
    SetUpVote(true);
}

function voteDown_click() {
  if (isVotedDown)
    return;
  else if (isVotedUp)
    SetUpVote(false);
  else
    SetDownVote(true);
}

function SetUpVote(status) {
  isVotedUp = status;
  // Do some CSS stuff to Vote-Up button
}

function SetDownVote(status) {
  isVotedDown = status;
  // Do some CSS stuff to Vote-Down button
}

これらの4つの機能はすべて、すべて環境にアクセスするため、クロージャです。


dlaliberteによる最初のポイントの例:

クロージャーは、内部関数を返すときに作成されるだけではありません。実際、囲み関数はまったく返す必要はありません。代わりに、内側の関数を外側のスコープ内の変数に代入したり、引数としてすぐに使用できる別の関数に渡したりすることもできます。したがって、内部関数が呼び出されるとすぐに内部関数にアクセスできるため、内部関数のクロージャは、内部関数が呼び出された時点ですでに存在している可能性があります。

var i;
function foo(x) {
    var tmp = 3;
    i = function (y) {
        console.log(x + y + (++tmp));
    }
}
foo(2);
i(3);

さて、6歳の子供と話して、私はおそらく次の団体を使うでしょう。

想像してみてください。あなたはあなたの兄弟姉妹と一緒に家の中で遊んでいます。あなたはおもちゃを持って移動し、あなたの兄の部屋にそれらの一部を持ってきました。しばらくして、あなたの兄弟は学校から戻って自分の部屋に行きました。彼はその中に閉じ込められました。しかし、あなたはドアをノックして、あなたの兄弟にそのおもちゃを頼むことができます。これはおもちゃの閉鎖と呼ばれます。あなたの兄はあなたのためにそれを作って、彼は今、外の範囲に入っています。

ドアがドラフトで閉じられていて誰も内部に閉じ込められていない(一般的な機能の実行)状況が発生し、地元の火災が発生してガレージコレクタ(D)を部屋に焼き付けた後、新しい部屋が建設され、そこに別のおもちゃ(新しい関数のインスタンス)が、最初の部屋のインスタンスに残っていた同じおもちゃを得ることはありません。

先進的な子供のために、私は次のようなものを置くでしょう。それは完璧ではありませんが、あなたはそれが何であるかを感じさせます:

function playingInBrothersRoom (withToys) {
  // We closure toys which we played in the brother's room. When he come back and lock the door
  // your brother is supposed to be into the outer [[scope]] object now. Thanks god you could communicate with him.
  var closureToys = withToys || [],
      returnToy, countIt, toy; // Just another closure helpers, for brother's inner use.

  var brotherGivesToyBack = function (toy) {
    // New request. There is not yet closureToys on brother's hand yet. Give him a time.
    returnToy = null;
    if (toy && closureToys.length > 0) { // If we ask for a specific toy, the brother is going to search for it.

      for ( countIt = closureToys.length; countIt; countIt--) {
        if (closureToys[countIt - 1] == toy) {
          returnToy = 'Take your ' + closureToys.splice(countIt - 1, 1) + ', little boy!';
          break;
        }
      }
      returnToy = returnToy || 'Hey, I could not find any ' + toy + ' here. Look for it in another room.';
    }
    else if (closureToys.length > 0) { // Otherwise, just give back everything he has in the room.
      returnToy = 'Behold! ' + closureToys.join(', ') + '.';
      closureToys = [];
    }
    else {
      returnToy = 'Hey, lil shrimp, I gave you everything!';
    }
    console.log(returnToy);
  }
  return brotherGivesToyBack;
}
// You are playing in the house, including the brother's room.
var toys = ['teddybear', 'car', 'jumpingrope'],
    askBrotherForClosuredToy = playingInBrothersRoom(toys);

// The door is locked, and the brother came from the school. You could not cheat and take it out directly.
console.log(askBrotherForClosuredToy.closureToys); // Undefined

// But you could ask your brother politely, to give it back.
askBrotherForClosuredToy('teddybear'); // Hooray, here it is, teddybear
askBrotherForClosuredToy('ball'); // The brother would not be able to find it.
askBrotherForClosuredToy(); // The brother gives you all the rest
askBrotherForClosuredToy(); // Nothing left in there

ご覧のように、部屋に残されたおもちゃは、お部屋がロックされていても、兄弟からアクセスできます。ここでそれを使って遊ぶjsbinがあります。


すでに多くの解決策があることはわかっていますが、この小さくてシンプルなスクリプトがこのコンセプトを実証するのに役立つと思います。

// makeSequencer will return a "sequencer" function
var makeSequencer = function() {
    var _count = 0; // not accessible outside this function
    var sequencer = function () {
        return _count++;
    }
    return sequencer;
}

var fnext = makeSequencer();
var v0 = fnext();     // v0 = 0;
var v1 = fnext();     // v1 = 1;
var vz = fnext._count // vz = undefined

別の関数内でfunctionキーワードを見ると、内部関数は外部関数の変数にアクセスできます。

function foo(x) {
  var tmp = 3;

  function bar(y) {
    console.log(x + y + (++tmp)); // will log 16
  }

  bar(10);
}

foo(2);

barfooへの引数として定義されたxアクセスでき、 fooからもtmpアクセスできるので、これは常に16を記録します。

それ閉鎖です。 クロージャと呼ばれるために関数を返す必要はありません。 直近のレキシカルスコープの外にある変数にアクセスするだけで、クロージャーが作成されます。

function foo(x) {
  var tmp = 3;

  return function (y) {
    console.log(x + y + (++tmp)); // will also log 16
  }
}

var bar = foo(2); // bar is now a closure.
bar(10);

上の関数は、もはやスコープの内部にはなくても、 barはまだxtmp参照できるので、16を記録します。

しかし、 tmpはまだbarのクロージャの内側にぶら下がっているので、それも増分されています。 これは、あなたがbarを呼び出すたびに増分されbar

クロージャの最も簡単な例は次のとおりです。

var a = 10;

function test() {
  console.log(a); // will output 10
  console.log(b); // will output 6
}
var b = 6;
test();

JavaScript関数が呼び出されると、新しい実行コンテキストが作成されます。 この実行コンテキストは、関数の引数と親オブジェクトとともに、その外部で宣言されたすべての変数を受け取ります(上記の例では、 'a'と 'b'の両方)。

複数のクロージャ関数を作成するには、それらの関数のリストを返すか、グローバル変数に設定します。 これらはすべて同じ xと同じtmpを参照しますが、それらは独自のコピーを作成しません。

ここで、番号xはリテラル番号です。 JavaScriptの他のリテラルと同様に、 fooが呼び出されると、 xが引数xとしてfoo コピーされます。

一方、JavaScriptは、オブジェクトを扱うときに常に参照を使用します。 たとえば、 fooをオブジェクトで呼び出すと、それが返すクロージャは元のオブジェクトを参照します。

function foo(x) {
  var tmp = 3;

  return function (y) {
    console.log(x + y + tmp);
    x.memb = x.memb ? x.memb + 1 : 1;
    console.log(x.memb);
  }
}

var age = new Number(2);
var bar = foo(age); // bar is now a closure referencing age.
bar(10);

予想どおり、 bar(10)x.membが増えます。 予想できないことは、 xage変数と同じオブジェクトを単に参照していることです。 barに2 age.membコールした後、 age.membは2になります! この参照は、HTMLオブジェクトのメモリリークの基礎となります。


本文:この回答は質問があったときに書かれました:

古いアルバートのように言った: "あなたは6歳に説明できないなら、あなたは本当に自分でそれを理解していない" ...まあ、私は27歳の友人にJSの閉鎖を説明しようとし、完全に失敗しました。

誰かが私が6歳で、その話題に興味をそそられていると考えることができますか?

私は文字通り最初の質問をしようとした唯一の人の一人であると確信しています。 それ以来、質問は何度か突然変異してしまったので、私の答えは今や信じられないほどばかげているかもしれません。 うまくいけば、物語の一般的なアイデアは、いくつかのために楽しいままです。

私は、難解な概念を説明するときのアナロジーとメタファーの大きなファンです。私は物語で私の手を試してみましょう。

昔々:

プリンセスがいた...

function princess() {

彼女は冒険がいっぱいの素敵な世界に住んでいました。 彼女は彼女の魅力的な皇太子と出会い、ユニコーン、戦った竜、話す動物に遭遇し、彼女の世界の周りを飛び回った。

    var adventures = [];

    function princeCharming() { /* ... */ }

    var unicorn = { /* ... */ },
        dragons = [ /* ... */ ],
        squirrel = "Hello!";

    /* ... */

しかし、彼女はいつも家事や大人の鈍い世界に戻らなければなりません。

    return {

そして彼女はしばしば彼女に彼女の最新の素晴らしい冒険を姫として伝えます。

        story: function() {
            return adventures[adventures.length - 1];
        }
    };
}

しかし、彼らが見るのは小さな女の子だけです...

var littleGirl = princess();

...魔法とファンタジーについての物語を伝える。

littleGirl.story();

そして大人たちは本当の王女を知っていたにもかかわらず、ユニコーンやドラゴンを決して信じることができなかったので、彼らは決して信じません。 大人たちは、彼らは幼い少女の想像の中にしか存在しないと言った。

しかし、私たちは本当の真実を知っています。 姫の中にいる少女が...

...本当に奥の小さな女の子がいる姫です。


私はそれを6歳の子供に説明します:

大人が家を所有する方法を知っていて、彼らはそれを家に呼びますか?母親に子供がいるとき、子供は本当に何も所有していませんよね?しかし、両親は家を所有しているので、誰かが子供に「あなたの家はどこですか?」と尋ねると、「その家!」と答えることができ、両親の家を指すことができます。「閉鎖」とは、たとえそれが本当に親を所有しているにもかかわらず、(たとえ海外であっても)子供が常に家を持っていると言うことができる能力です。


閉鎖は非常にオブジェクトのようなものです。関数を呼び出すたびにインスタンス化されます。

JavaScriptにおけるクロージャの範囲はレキシカルであり、クロージャが属する関数内に含まれるすべてのものがそのクロージャ内にある変数にアクセスできることを意味します。

変数はクロージャに含まれています

  1. それを割り当てる var foo=1; または
  2. 書くだけ var foo;

内部関数(別の関数の中に含まれている関数)がvarを使用して独自のスコープ内で変数を定義せずにそのような変数にアクセスすると、外部クロージャの変数の内容が変更さます。

クロージャは、それを生み出した関数の実行時間をoutlives。他の関数が、それらが定義されているクロージャ/スコープから(例えば戻り値として)それを作る場合、それらはそのクロージャを引き続き参照します。

function example(closure) {
  // define somevariable to live in the closure of example
  var somevariable = 'unchanged';

  return {
    change_to: function(value) {
      somevariable = value;
    },
    log: function(value) {
      console.log('somevariable of closure %s is: %s',
        closure, somevariable);
    }
  }
}

closure_one = example('one');
closure_two = example('two');

closure_one.log();
closure_two.log();
closure_one.change_to('some new value');
closure_one.log();
closure_two.log();

出力

somevariable of closure one is: unchanged
somevariable of closure two is: unchanged
somevariable of closure one is: some new value
somevariable of closure two is: unchanged

OK、6歳のファンが閉鎖します。あなたは閉鎖の最も単純な例を聞きたいですか?

次の状況を想像してみましょう:運転手が車に座っています。その車は飛行機の中にあります。飛行機が空港にあります。彼の車の外にあるが、飛行機の内部にいる物にアクセスする能力は、たとえその飛行機が空港を離れるとしても閉鎖である。それでおしまい。あなたが27歳になったら、より詳細な説明を見てください。

私の飛行機物語をコードに変換する方法は次のとおりです。

var plane = function(defaultAirport) {

  var lastAirportLeft = defaultAirport;

  var car = {
    driver: {
      startAccessPlaneInfo: function() {
        setInterval(function() {
          console.log("Last airport was " + lastAirportLeft);
        }, 2000);
      }
    }
  };
  car.driver.startAccessPlaneInfo();

  return {
    leaveTheAirport: function(airPortName) {
      lastAirportLeft = airPortName;
    }
  }
}("Boryspil International Airport");

plane.leaveTheAirport("John F. Kennedy");


あなたは眠りにつき、ダンを招待します。あなたはDanに1つのXBoxコントローラを持ってくるよう伝えます。

ダンはポールを招待します。ダンはポールにコントローラを1つ持って来るように頼みます パーティーに持ち込まれたコントローラーの数はいくつですか?

function sleepOver(howManyControllersToBring) {

    var numberOfDansControllers = howManyControllersToBring;

    return function danInvitedPaul(numberOfPaulsControllers) {
        var totalControllers = numberOfDansControllers + numberOfPaulsControllers;
        return totalControllers;
    }
}

var howManyControllersToBring = 1;

var inviteDan = sleepOver(howManyControllersToBring);

// The only reason Paul was invited is because Dan was invited. 
// So we set Paul's invitation = Dan's invitation.

var danInvitedPaul = inviteDan(howManyControllersToBring);

alert("There were " + danInvitedPaul + " controllers brought to the party.");

クロージャは、内部関数が外部関数内の変数にアクセスできる場所です。おそらく、閉鎖のために得ることができる最も簡単な一行の説明です。


現在、幼児を教える6歳の父親(正式な教育なしでコーディングするという初心者からの訂正が必要になる)の父親として、私はレッスンがハンズオン・プレイを通して最高のスティックとなると考えています。 6歳の人が閉鎖が何であるかを理解する準備ができていれば、彼らは自分自身を持つために十分な年齢です。私はjsfiddle.netにコードを貼り付け、ちょっと説明して独特の曲を作るためにそれらを残しておくことをお勧めします。以下の説明文は、おそらく10歳の方に適しています。

function sing(person) {

    var firstPart = "There was " + person + " who swallowed ";

    var fly = function() {
        var creature = "a fly";
        var result = "Perhaps she'll die";
        alert(firstPart + creature + "\n" + result);
    };

    var spider = function() {
        var creature = "a spider";
        var result = "that wiggled and jiggled and tickled inside her";
        alert(firstPart + creature + "\n" + result);
    };

    var bird = function() {
        var creature = "a bird";
        var result = "How absurd!";
        alert(firstPart + creature + "\n" + result);
    };

    var cat = function() {
        var creature = "a cat";
        var result = "Imagine That!";
        alert(firstPart + creature + "\n" + result);
    };

    fly();
    spider();
    bird();
    cat();
}

var person="an old lady";

sing(person);

説明書

DATA:データは事実の集合です。数字、言葉、測定値、観測値、あるいは物事の説明だけでも可能です。あなたはそれに触れることはできません、それをにおいまたは味わうことはできません。書き留めて、話し、聞くことができます。あなたはそれを使用して、コンピュータを使って触覚と風味をつくることができます。それは、コードを使用してコンピュータによって有用にすることができます。

コード:上のすべてのコードコードと呼ばれます。JavaScriptで書かれています。

JAVASCRIPT:JavaScriptは言語です。英語やフランス語、中国語などの言語があります。コンピュータや他の電子プロセッサが理解できる多くの言語があります。 JavaScriptがコンピュータによって理解されるためには、インタプリタが必要です。ロシア語だけを話す教師が学校であなたのクラスを教えるようになると想像してみてください。教師が「всесадятся」と言うと、クラスは理解できません。しかし、幸いなことに、あなたのクラスにはロシアの弟子がいて、誰もが "すべての人が座っている"ということを教えてくれます。クラスはコンピュータのようで、ロシアの生徒は通訳です。 JavaScriptの場合、最も一般的なインタプリタはブラウザと呼ばれます。

ブラウザ:コンピュータ、タブレット、または携帯電話でインターネットに接続してウェブサイトにアクセスすると、ブラウザが使用されます。あなたが知っているかもしれない例はInternet Explorer、Chrome、Firefox、Safariです。ブラウザはJavaScriptを理解し、コンピュータに何をする必要があるかを伝えることができます。JavaScript命令は関数と呼ばれます。

機能:JavaScriptの関数はファクトリのようです。それは内部に1台のマシンしかない小さな工場かもしれません。それとも、多くの機械が別の仕事をしている他の小さな工場もたくさんあるかもしれません。実際の生活服の工場では、糸の入った織物や糸のボビン、Tシャツやジーンズが出てくるかもしれません。私たちのJavaScript工場はデータを処理するだけで、縫うことができず、穴を掘ったり金属を溶かしたりすることはできません。JavaScriptファクトリでは、データが入りデータが出力されます。

このすべてのデータはちょっと退屈ですが、実際にはとてもクールです。我々はロボットに夕食のために何を作るべきかを知らせる機能を持っているかもしれない。あなたとあなたの友人を私の家に招待してみましょう。あなたは鶏の脚が一番好きです、私はソーセージが好きです、あなたの友人はいつもあなたが望むものを望み、私の友人は肉を食べません。

私は買い物に行く時間がないので、機能は、私たちが冷蔵庫で持っているものが意思決定をするのを知る必要があります。各成分は調理時間が異なり、ロボットが同時にすべてを熱く召し上がるようにします。私たちが好きなものについてのデータを関数に提供し、関数が冷蔵庫に「話す」ことができ、関数がロボットを制御できるようにする必要があります。

関数は通常、名前、カッコおよび中カッコを持ちます。 このような:

function cookMeal() {  /*  STUFF INSIDE THE FUNCTION  */  }

なお/*...*///ブラウザによって読まれているコードを停止します。

名前:必要な単語だけを呼び出すことができます。"cookMeal"の例は、2つの単語を結合し、最初に大文字を付けるのが典型的ですが、これは必須ではありません。それにはスペースを入れることはできず、それ自身の数字にすることはできません。

PARENTHESES: "括弧" ()は、JavaScriptファクトリのドアのレターボックス、または情報パケットを工場に送るための通りのポストボックスです。ポストボックスにマークが付い cookMeal(you, me, yourFriend, myFriend, fridge, dinnerTime)いる場合があります。

BRACES:このような "ブレース" {}は、私たちの工場の色付きの窓です。工場内から見ることができますが、外から見ることはできません。

上記の長いコード例

私たちのコードはfunctionという単語から始まります。したがって、それは1つです!そして、関数の名前は歌います - それは関数が何であるかについての私自身の記述です。次にカッコ()。カッコは常に関数のためにあります。時々彼らは空であり、時々彼らは何かを持っています(person)。この後、このようなブレースがあります{。これは関数sing()の開始を示します。それは歌()の終わりをこのようにマークするパートナーを持っています}

function sing(person) {  /* STUFF INSIDE THE FUNCTION */  }

だから、この機能は歌と関係があり、人についての何らかのデータが必要かもしれません。そのデータで何かをするための指示が内部にあります。

さて、関数sing()の後、コードの終わり近くでは、行

var person="an old lady";

VARIABLE:文字varは "変数"を表します。変数はエンベロープのようなものです。外側では、この封筒は「人」と記されています。内部には、私たちの機能が必要とする情報を含む紙切れが入っています。いくつかの文字とスペースは、「老婦人」と読むフレーズを作る文字列(文字列と呼ばれます)のようにつながっています。私たちのエンベロープには、数値(整数と呼ばれる)、命令(関数と呼ばれる)、リスト(配列と呼ばれる)などの他の種類のものを含めることができます。この変数はすべての中括弧の外側に書かれているため、中括弧{}内にあるときに色付きのウィンドウを見ることができるため、この変数はコードのどこからでも見ることができます。これを「グローバル変数」と呼びます。

GLOBAL VARIABLE:はグローバル変数です。つまり、「老婦人」から「若者」に値を変更すると、そのは再び変更するまで若者になります。コードはそれが若い男であることを見ることができます。押しF12ボタンまたはブラウザのデベロッパーコンソールを開き、この値が何であるかを確認するために、「人」と入力するには、[オプションの設定を見てください。タイプperson="a young man"して変更した後、再び "人"と入力して変更されたことを確認してください。

この後、私たちは

sing(person);

この行は、犬を呼び出しているかのように関数を呼び出しています

歌いなさい、来て、を手に入れよう!

ブラウザがこの行に達したJavaScriptコードをロードすると、関数が開始されます。私は最後に行を置いて、ブラウザが実行するために必要なすべての情報を持っていることを確認します。

関数はアクションを定義します - 主な機能は歌についてです。これにはfirstPartという変数が含まれています。この変数は、曲の各節に適用される人についての歌に適用されます。「そこにいる人+人+人を飲み込んだ人」あなたが入力した場合FIRSTPARTコンソールに変数は関数の中でロックアップされているので、あなたは答えを得ることはありません-ブラウザは、中括弧の彩色の窓の内部を見ることができません。

クロージング:クロージャーは大きなsing()関数の中にある小さな関数です。大きな工場の中の小さな工場。彼らはそれぞれ内部の変数が外部から見ることができないことを意味する独自のブレースを持っています。だからこそ、変数の名前(生き物結果)はクロージャで繰り返すことができますが、値は異なります。これらの変数名をコンソールウィンドウに入力すると、色付きウィンドウの2つのレイヤーによって隠されているため、その値は取得されません。

クロージャーはすべて、sing()関数の変数firstPartと呼ばれるものが何であるかを知っています。

閉鎖後にラインが来る

fly();
spider();
bird();
cat();

sing()関数は、これらの関数のそれぞれを与えられた順序で呼び出します。その後、sing()関数の処理が行われます。


私は単にそれらをMozilla Closuresページに指しておきます。私が見つけたクロージャの基礎と実用的な使い方の最も簡潔で簡単な説明です。JavaScriptを習得している人なら誰でもお勧めします。

そして、はい、私は6歳にそれをお勧めします - もし6歳が閉鎖について学んでいるなら、記事で提供されている簡潔で簡単な説明を理解する準備ができていることは論理です。


私は閉鎖を説明しながらブログ投稿を書いた。なぜ私はあなたが1つを望むのという点で閉鎖について述べたことがあります。

クロージャは、関数に永続的なプライベート変数、つまり実行された前の時間からの情報を追跡できる1つの関数だけが知っている変数を持つようにする方法です。

その意味では、関数はプライベート属性を持つオブジェクトのように少し機能します。

完全な投稿:

では、これらの閉鎖物は何ですか?





closures