ホームページ  >  記事  >  ウェブフロントエンド  >  JS フロントエンド クロージャ インタビューの question_javascript スキルの分析

JS フロントエンド クロージャ インタビューの question_javascript スキルの分析

WBOY
WBOYオリジナル
2016-05-16 15:23:281703ブラウズ

質問

コード A

function fun(n,o){
  console.log(o);
  return {
    fun:function(m){//[2]
      return fun(m,n);//[1]
    }
  }
}

var a=fun(0);
a.fun(1);
a.fun(2);
a.fun(3);
var b=fun(0).fun(1).fun(2).fun(3);
var c=fun(0).fun(1);
c.fun(2);
c.fun(3);

プログラム出力を見つける

これはクロージャ テストの質問です

同等のコードに変換

return によって返されるオブジェクトの fun 属性は、新しく作成された関数オブジェクトに対応します。この関数オブジェクトは、外部関数の変数 n と外部関数 fun にアクセスできるようにします。 fun 関数と fun 属性を組み合わせます。 fun 属性が混乱しているため、上記のコードを次のように変更します。
コード B

function _fun_(n,o){
  console.log(o);
  return {
    fun:function(m){
      return _fun_(m,n);
    }
  }
}

var a=_fun_(0);//undefined
a.fun(1);//0
a.fun(2);//0
a.fun(3);//0

var b=_fun_(0).fun(1).fun(2).fun(3);
//undefined,0,1,2

var c=fun(0).fun(1);//undefined,0,
c.fun(2);//1
c.fun(3); //1

そこで、何人かの生徒が、なぜこのように変更できるのかと尋ねました。コードが配置されている [1] の fun が [2] の fun ではないことをどうやって確認できるのですか? ここの fun 属性を知っておく必要があります。 ~
関数オブジェクトを指します。 ここでは、JS の字句スコープについて説明します。JS 変数のスコープは関数本体、つまり関数本体に存在し、変数のスコープは関数の実行時ではなく関数定義の宣言時に決定されます。
次のコード

var name="global";
function foo(){
  console.log(name);
}

function fooOuter1(){
  var name="local";
  foo();
}
fooOuter1();//输出global 而不是local,并且和闭包没有任何关系

function fooOuter2(){
  var name="local";
  function foo(){
    console.log(name);
  }
  foo();
}
fooOuter2();//输出local 而不是global,在函数声明是name变量作用域就在其外层函数中,嗯嗯就是闭包~<br />

さて、関数宣言の定義段階で、[2] の無名関数を定義し、[1] で fun という名前の関数オブジェクトを参照する必要があることがわかります。まず現在の関数本体でそれを見つけて、存在しないことがわかったら、その外側の関数、つまりこの匿名関数のラッピング関数に移動して、それが存在しないことがわかります。関数を実行して、外部に関数ラッパーがないことを確認してから、グローバル環境に移動して見つけました。ええ、ついに見つけました...グローバル環境で fun 関数オブジェクトとして fun 関数を指定し、それをクロージャに追加するだけです。匿名関数。この時点で、コード B がコード A と同等である理由がわかりました~~~

クロージャースコープの作成

字句解析後、JS は、返されたオブジェクトの fun 属性に対応する匿名関数のクロージャー、つまりグローバル環境の _func_ にアクセスする関数内部変数 n とその外部関数のクロージャーを決定します。 > _func_ が実行されるたびに、クロージャ内の変数のスコープ情報が関数実行環境に渡され、関数実行時の変数値の取得に使用されます

実行出力

var a=_fun_(0);//undefined
a.fun(1);//0
a.fun(2);//0
a.fun(3);//0
_fun_ 関数が実行されると、2 番目のパラメーターが未定義であるため、出力は未定義になります。次に、関数オブジェクトを指す fun 属性を持つオブジェクトを返します。クロージャーを使用すると、_fun_ と変数 n_

にアクセスできます。 a.fun(1) は、返されたオブジェクトの fun メソッドを実行し、m 1 の値を渡し、呼び出しは _fun_(1,0)
を返します。 したがって、出力は 0、a.fun(2)、a.fun(3)、および a.fun(1)
になります。

var b=_fun_(0).fun(1).fun(2).fun(3); 同等のコード:

var b=_fun_(0); var b1=b.fun(1);
var b2=b1.fun(2);//[3]
var b3=b2.fun(3);//[4]

最初の 2 つの文は、上記の出力 unknown,0 と同じです。[3] が呼び出されるとき、b1 オブジェクト内にクロージャーがあり、_fun_ 関数と外部関数変数 n=1 を参照します。したがって、匿名関数によって実行される関数呼び出しは _fun_(2,1) で、出力結果は 1 で、新しいオブジェクトが返されます。
[4] が実行されると、b2 オブジェクトにもクロージャがあり、_fun_ 関数と外部関数変数 n=2 を参照します。_fun_(3,2) が実行されると、出力結果は 2
になります。

var c=fun(0).fun(1);//undefined,0,
c.fun(2);//1
c.fun(3); //1
前のコード実行の説明を理解し、上記のコード実行出力を理解できれば問題ないと思います。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。