JavaScriptの語法の作用の領域と閉鎖を深く理解します.

41474 ワード

包みを閉じる
クローズドの定義について:A closure is the commbination of a function and the lexical environment within which that function was declead.–MDN A closure is the local variables for a function-kept alive after the funcer the function hanced.japtection.jancevanced.
語法のスコープ(lexical environment)
スコープチェーン:
  • 関数の実行中に、まず自分の内部から変数を探します.
  • もし見つけられなかったら、現在の関数を作成するスコープからこれを探してwindow
  • まで上げます.
  • 注意して探しているのは変数の現在の状態
  • です.
    語法のスコープを深く理解する
    関連概念
    実行コンテキスト(execution Contect)
    アクティブオブジェクトAO:関数の内部に作成された変数や関数のパラメータなどが、関数が呼び出されたときに作成されます.
    [Scope]属性:活動対象から見つからないときはScopeから関数を探します.宣言時には[Scope]属性を作成し、この関数の語法作用領域を含む作用ドメインチェーンをscope属性に保存します.関数を呼び出す時は実行コンテキスト、すなわち実行環境を作成し、コピー関数の[Scope]を通じて属性のオブジェクトは、関数として作用するドメインチェーンを構築します.
    コードの理解:
    var test = 0;
     function createCompareFunction(property) {
             return function (object1,object2) {
                 var value1 = object1[property];
                 var value2 = object2[property];
                 if(value1 > value2) {
                     return value1;
                 }else  if(value1 < value2) {
                     return value2;
                 }else {
                     return 0;
                 }
             }       
        }
        var compare  = createCompareFunction("age");
        compare({"age":10},{"age":20});//20
    
    理解:
            createCompareFunction 
    globalContext = {
    	AO: {
    		x : 10,
    		createCompareFunction: function,
    		compare : undefined
    	}
    	Scope: null
    }
    
    createCompareFunctionContext.[[Scope]] = globalContext
    
    createCompareFunctionContext = { //createCompareFunction            
    	AO:{
    		property:'age',
    		argumets:'age'
    	},
    	Scope:{
    		globalContext
    	}
    }
    //   createCompareFunction                
        Context = {
    	AO: {
    		object1 : {age:10},
    		object2 : {age:20},
    		argumets: [{age:10},{age:20}]
    	},
    	Scope:{
    		arguments:{"age"},
    		property : 'age',
    		createCompareFunction.[[Scope]] : globalContext
    	}
    }
              AO[[Scope]]     
     [[Scope]][[Scope]]    createCompareFunction                  
                               。
               
    
    閉包とは何ですか
    JavaScriptアドバンストプログラムの設計定義:クローズドは別の関数のスコープにアクセスする変数の関数です.
    function a() {
    	var j;
    	function b(){
    		return j;
    	}
    	return b;
    }
    var c  = a();
    console.log(c());
    
    つまり、関数bは外部関数cによって引用されるので、関数bはaの活動対象を引用します.aの活動対象はまだ引用されているので、廃棄されません.ですから、aの活動対象内の変数などを間接的に保存しました.外部関数は、関数aの関連データを参照して、aのアクティブオブジェクト中の関連データを一時保存することができる.
    ブラウザ回収メカニズムGCメカニズムから、クローズドを理解する:
    JavaScriptでは、オブジェクトがもう引用されないと、このオブジェクトはGCによって回収されます.2つのオブジェクトが相互に参照され、第三者によって参照されない場合は、この2つのオブジェクトも回収されます.この時、関数aは関数bによって参照され、bはa以外のc(つまり第三者)によって参照され、関数aが実行された後は回収されない.同じように、その内部の関数bも内部の変数は回収されないし、回収されない.これはパッケージデータと一時保存データの目的を果たした.また、参照された関数bと、この関数bの品詞作用領域、すなわち作用ドメインチェーンの組み合わせは、クローズドとなる.
    閉包の役割
    パッケージデータ一時保存データ
    閉包式の例
    function car(){
      var speed = 0  /
      function fn(){
        speed++
        console.log(speed)
      }               /      fn               spedd
      return fn     
    }
    
    var speedUp = car()
    speedUp()   //1
    speedUp()   //2
    
    変数は一時的に保存できます.変数は破壊されません.
    つまり、関数carの内部関数fnが関数car以外の変数によって参照されると、クローズドパケットが作成される.
    閉包に関する判例理解:
    [01]次のコードの出力はどれぐらいですか?もし3を出力したいなら、コードはどうやって改造しますか?
    var fnArr = [];
    for (var i = 0; i < 10; i ++) {
      fnArr[i] =  function(){
        return i
      };
    }
    console.log( fnArr[3]() ) // 10
    
    
    なぜ10で、3ではないですか?
    fnArr[i]  =  function(){
        return i;
    };  fnArr[i]       return   i  i        
        :
    fnArr[3] = function(){
        return i;
    }   
    fnArr[3] = function(){
        return 3;
    }
    
    クローズド改造:
    01:
    
    
    var fnArr = [];
    
    for (var i = 0; i < 10; i ++) {
      fnArr[i] =  (function(j){
        return function(){
          return j
            } 
      })(i)
    }
    console.log( fnArr[3]() ) // 3        10          
        //   10                          10     10    
    
    理解する
    var fnArr = [];
    for(var i  = 0;i<10;i++) {
    	fnArr[i] = (function(j){
    		return function(){
    			return j;
    		}
    	})(i);
    }
         
    function a(i) {
    	var j = i;
    	function b(){
    		return j; 
    		//       j                     。   j         	
    	}
    	return b;
    }
    var c = a(); //    (function(j){})(i)    
    c(); //  fnArr[i]()         fnArr[i]     b
    
    02:
     for(var i = 0;i<10;i++) {
            (function (j) {
                fnArr[j] = function () {
                    console.log(j);
                }
            })(i)
        }
        fnArr[3]();
    
    
    03: ES6  
    
    var fnArr = []
    for (let i = 0; i < 10; i ++) { //let es6   
      fnArr[i] =  function(){
        return i
      } 
    }
    console.log( fnArr[3]() ) // 3
    
    [02]Casオブジェクトをパッケージ化する
    var Car = (function(){
       var speed = 0;
       function set(s){
           speed = s
       }
       function get(){
          return speed
       }
       function speedUp(){
          speed++
       }
       function speedDown(){
          speed--
       }
       return {
          setSpeed: setSpeed,
          get: get,
          speedUp: speedUp,
          speedDown: speedDown
       }
    })()
    Car.set(30)
    Car.get() //30
    Car.speedUp()
    Car.get() //31
    Car.speedDown()
    Car.get()  //30
    
    //  speed                         
    
    [03]次のコードの出力はどれぐらいですか?どのように連続して0、1、2、3、4を出力しますか?
    for(var i=0; i<5; i++){
      setTimeout(function(){
        console.log('delayer:' + i )
      }, 0)
    }
    //   setTimeout                                
    //     i    5  i      
    
    クローズドの変更:
    for(var i=0; i<5; i++){
      (function(j){
        setTimeout(function(){
          console.log('delayer:' + j )
        }, 0)    
      })(i)
    }
      
    for(var i=0; i<5; i++){
      setTimeout((function(j){
        return function(){
          console.log('delayer:' + j )
        }
      }(i)), 0)    
    }
    
    [04]次のコードの出力はどれぐらいですか?
    function makeCounter() {
      var count = 0
    
      return function() {
        return count++
      };
    }
    
    var counter = makeCounter();  
    var counter2 = makeCounter(); //                  
    
    console.log( counter() ) // 0   
    console.log( counter() ) // 1  
    
    console.log( counter2() ) // ?  2 
    console.log( counter2() ) // ?   3
    
    [05]補完コードで、配列は名前、年齢、任意のフィールドで並べ替えられます.
    var users = [
      { name: "John", age: 20, company: "Baidu" },
      { name: "Pete", age: 18, company: "Alibaba" },
      { name: "Ann", age: 19, company: "Tecent" }
    ]
    
    users.sort(byName) 
    users.sort(byAge)
    users.sort(byField('company'))
    
    答え:
    function byName(user1, user2){
      return user1.name > user2.name
    }
    
    function byAge (user1, user2){
      return user1.age > user2.age
    }
    
    function byFeild(field){
      return function(user1, user2){
        return user1[field] > user2[field]
      }
    }
    users.sort(byField('company'))     field    
    
    関数コリック化
    関数コリゼーション-関数の一部のパラメータだけに渡して呼び出して、残りのパラメータを処理するための関数を返します.
    sum関数を書いて、次のような呼び方を実現します.
    console.log( sum(1)(2) ) // 3
    console.log( sum(5)(-1) ) // 4
    
    function sum(a) {
      return function(b) {
        return a + b
      }
    }