JS進撃の道:クローズド

3004 ワード

ことばを引く
クローズドという言葉は多くの先端開発者にとってよく知られています.よく知っているのは、多くの人がクローズドを使っていますが、知らない人はクローズドを理解していません.
定義
クローズドはどのように定義されていますか?関数が既存の語法のスコープを覚えてアクセスできると、関数が現在の語法のスコープ外で実行されても、クローズドが発生します.具体例を見てみます.
function foo () {
  var a = 2
  function bar () {
    console.log(a)
  }
  return bar
}
var baz = foo()
baz() //2
関数barの語法作用領域はfooの内部作用領域にアクセスでき、barは戻り値としてbazに割り当てられたとき、bar関数は定義時の語法作用領域以外で呼び出されますが、依然としてfoo関数の内部作用領域変数aにアクセスできます.これはクローズドです.
分析
ここでは、閉包が定義された語法作用域外で記憶され、定義された語法作用領域の変数にアクセスできる理由を見てみましょう.まず簡単な例を見て関数の実行過程を見たいです.
function foo (a) {
  console.log(a)
}
foo (a)
上記は簡単な関数呼び出しであり、実行時のコンテキスト環境、実行時のコンテキスト環境に重点を置いて、foo関数を作成すると、大域変数オブジェクトをあらかじめ含んでいる作用ドメインチェーンが作成されます.この作用ドメインチェーンは内部の[Scape]属性に保存されています.foo関数を呼び出したとき、関数の実行環境が作成されます.その後、関数の[Scrope]属性のオブジェクトをコピーして、環境を実行するためのスコープチェーンを構築します.その後、アクティブなオブジェクトがもう一つあります.(this、argments、aを含む)作成された環境作用分域チェーンの先端に押し込まれると、foo関数には2つの変数オブジェクト、1つはグローバル変数オブジェクト、1つは局所的な活動変数オブジェクトで、一般的には関数実行が完了すると、局部的な活動変数オブジェクトは破壊され、全体的にのみ残されますが、クローズド実行プロセスは異なります.子:
function foo () {
  var a = 2
  function bar (b) {
    console.log(a + b)
  }
  return bar
}
var baz = foo()
baz(3) //5
次に、上記のクローズドの実行環境を分析します.一つの関数の内部で定義された関数は、関数を含むアクティブなオブジェクトをそのアクティブなドメインチェーンに追加します.したがって、bar関数の作用領域チェーンにはfoo関数のアクティブなオブジェクトが含まれています.bar関数がfooから返された後、そのスコープチェーンはグローバル変数とfoo中のアクティブなオブジェクトに初期化されます.ar関数はfoo関数で定義されているすべての変数にアクセスできます.同時にfoo関数は実行が完了しても、その活動対象は破壊されません.bar関数の作用領域チェーンはまだこの活動対象を参照しています.
よくある問題
クローズド関連の問題といえば、最も典型的なのは変数とthisがこの二つの問題を指すことです.
変数
function test () {
  var result = new Array()
  for (var i = 0; i < 6; i++) {
    result[i] = function () {
      return i
    }
  }
  return result
}
上のコードの展示は面接問題の中でよくあります.このresultの結果は上からスクリーンショットで見られます.作用領域に保存されているiは全部6です.なぜですか?クローズドは関数の中の活動対象ですので、それらは同じ変数で、しかも変数の最後の値を参照しています.この問題はどう解決しますか?一番簡単なのは間違いなくvarをletに変えてもいいです.以下のようにしてもいいです.
function test () {
  var result = new Array()
  for (var i = 0; i < 6; i++) {
    result[i] = (function () {
      return i
    })()
  }
  return result
}
クローズドを直接自己実行関数に変更します.自己実行関数自体は変数の作用領域がないので、外層関数の変数作用領域を使用します.これは私たちが望む効果をも達成できます.
this指向
var name = "window"
var obj = {
  name: "object",
  getName: function () {
    return function () {
      return this.name
    }
  }
}
console.log(obj.getName()())
上記のjsコードのthis.nameの戻り値はなぜwindowなのでしょうか?上記のように、この匿名関数は実行中に、自分の活動対象、getName関数の活動対象とグローバル変数オブジェクトの3つの部分が含まれています.同じ時に活動対象ごとに自動的に2つの特殊な変数を取得します.thisとargmentsですが、内部関数です.thisを検索するときは、外部関数に直接アクセスできないthis変数です.したがって、作用ドメインチェーンに沿って大域変数を検索し続けます.外部関数のthisの値を取るのも簡単です.次のコードだけが必要です.
var name = "window"
var obj = {
  name: "object",
  getName: function () {
    var that = this
    return function () {
      return that.name
    }
  }
}
console.log(obj.getName()())
thisを変数に割り当てます.内部関数は外部関数変数にアクセスできます.これで解決されます.
締め括りをつける
この文章は闭锁の定义、実行、よくある问题について简単に绍介しました.この文章を通じて、皆さんの理解と使用に対して、闭包の助けになりたいです.