ホームページ >ウェブフロントエンド >jsチュートリアル >jsのスコープとクロージャの詳しい説明

jsのスコープとクロージャの詳しい説明

angryTom
angryTom転載
2019-11-29 14:02:022789ブラウズ

jsのスコープとクロージャの詳しい説明

スコープ

JS には 2 種類のスコープがあります: グローバル スコープ|ローカル スコープ

Lizi 1

console.log(name);      //undefined
var name = '波妞';
var like = '宗介'
console.log(name);      //波妞
function fun(){
    console.log(name);  //波妞
    console.log(eat)    //ReferenceError: eat is not defined
    (function(){
        console.log(like)   //宗介
        var eat = '肉'
    })()
}
fun();

[関連コースの推奨事項: JavaScript ビデオ チュートリアル ]

1. 名前はグローバルに定義され、グローバルにアクセスできるため、(2) 印刷は可能です。正しく出力される;

2. 関数 fun では、name 属性が定義されていない場合、その親スコープで見つかるため、(3) も正しく出力できます。

3. 内部環境はスコープ チェーンを通じてすべての外部環境にアクセスできますが、外部環境は内部環境の変数や関数にはアクセスできません。 一方向透過性と同様に、これはスコープ チェーンであるため、(4) は不可能ですが、(5) は可能です。

次に、なぜ最初の出力が「ReferenceError: name is not generated」ではなく「unknown」なのかという疑問が生じます。原理は単純に、JS の 変数プロモーションです。

変数プロモーション: JS がコードを解析すると、すべての宣言がスコープの前に進みます


Chestnut 2

console.log(name);      //undefined
var name = '波妞';
console.log(name);      //波妞
function fun(){
    console.log(name)   //undefined
    console.log(like)   //undefined
    var name = '大西瓜';
    var like = '宗介'
}
fun();

var name;
console.log(name);      //undefined
name = '波妞';
console.log(name);      //波妞
function fun(){
    var name;
    var like;
    console.log(name)   //undefined
    console.log(like)   //undefined
    name = '大西瓜';
    like = '宗介'
    console.log(name)   //大西瓜
    console.log(like)   //宗介
}
fun();

と同等です。 注: は現在のスコープに進みます。


Chestnut 3

printName();     //printName is not a function
var printName = function(){
    console.log('波妞')
}
printName();       //波妞

var printName;
printName();     //printName is not a function
printName = function(){
    console.log('波妞')
}
printName();       //波妞

と同等です。こうすると分かりやすくなります。関数式は次のとおりです。宣言すると単なる変数です


栗 4

{
    var name = '波妞';
}
console.log(name)   //波妞

(function(){
    var name = '波妞';
})()
console.log(name)   //ReferenceError: name is not defined

{
    let name = '波妞';
}
console.log(name)   //ReferenceError: name is not defined

上記の栗からも分かるように、JS で var で宣言した変数は、速攻で宣言することはできません。のスコープは中括弧の開始スコープと終了スコープです。ES5 にはブロック レベルのスコープはありませんが、本質的には関数スコープです。ES6 で let および const 定義が導入されて初めて、ブロック レベルのスコープがありました。範囲。


栗 5

function p1() { 
    console.log(1);
}
function p2() { 
    console.log(2);
}
(function () { 
    if (false) {
        function p1() {
            console.log(3);
        }
    }else{
        function p2(){
            console.log(4)
        }
    }
    p2();
    p1()
})();       
//4
//TypeError: print is not a function

これは非常に古典的な栗です、事前に宣言されていますが、判定条件が no であるため、関数本体は実行されませんでした。そのため、「TypeError: print は関数ではありません」が表示されます。 while、switch、for

#closure

#関数とその状態への参照、つまり字句環境 (字句環境) にも同じことが当てはまります。 ) 一緒にクロージャを形成します。)つまり、クロージャを使用すると、内部関数から外部関数のスコープにアクセスできるようになります。 JavaScript では、関数は作成されるたびにクロージャを生成します。

上記の定義は MDN からのもので、簡単に言うと、クロージャとは、別の関数のスコープ内の変数にアクセスする権利を持つ関数を指します。


# クロージャの鍵は、外部関数が呼び出された後にその変数オブジェクトが破棄されるべきであるということですが、クロージャが存在することで、外部関数の変数オブジェクトにアクセスできるようになります。 function.

,

//举个例子
function makeFunc() {
    var name = "波妞";
    function displayName() {
        console.log(name);
    }
    return displayName;
}

var myFunc = makeFunc();
myFunc();

JavaScript フォーム クロージャの関数。クロージャは、関数とその関数を作成する字句環境で構成されます。この環境には、このクロージャの作成時にアクセスできるすべてのローカル変数が含まれています。

この例では、myFunc は、makeFunc の実行時に作成される displayName 関数インスタンスへの参照であり、displayName インスタンスは引き続きアクセスできます。スコープ内のその字句変数は名前にアクセスできます。したがって、myFunc が呼び出された場合でも、name にはアクセスでき、その値 'Ponyo' が console.log に渡されます。
クロージャを作成する最も一般的な方法は、関数内に別の関数を作成することです


● 通常、関数のスコープとそのすべての変数は、関数の実行の終わりは後で破棄されました。ただし、クロージャを作成した後は、クロージャが存在しなくなるまで関数のスコープは保存されます。

//例二
function makeAdder(x) {
  return function(y) {
    return x + y;
  };
}

var add5 = makeAdder(5);
var add10 = makeAdder(10);

console.log(add5(2));  // 7
console.log(add10(2)); // 12

//释放对闭包的引用
add5 = null;
add10 = null;
本質的に、makeAdder は関数ファクトリであり、関数の合計を加算する関数を作成します。指定された値とその引数。上の例では、ファンクション ファクトリを使用して 2 つの新しい関数を作成しました。1 つは引数に 5 を加算したもので、もう 1 つは 10 を加算したものです。

add5 と add10 は両方ともクロージャです。これらは同じ関数定義を共有しますが、異なる語彙環境を保存します。 add5 のコンテキストでは、x は 5 です。そして、add10 では、x は 10 です。

クロージャのスコープ チェーンには、それ自体のスコープに加えて、それを含む関数のスコープとグローバル スコープが含まれます。


● クロージャは、包含関数内の変数の最後の値のみを取得できます。

//栗子1
function arrFun1(){
    var arr = [];
    for(var i = 0 ; i < 10 ; i++){
        arr[i] = function(){
            return i
        }
    }
    return arr
}
console.log(arrFun1()[9]());     //10
console.log(arrFun1()[1]());     //10

//栗子2
function arrFun2(){
    var arr = [];
    for(var i = 0 ; i < 10 ; i++){
        arr[i] = function(num){
            return function(){
                return num
            };
        }(i)
    }
    return arr
}
console.log(arrFun2()[9]());     //9
console.log(arrFun2()[1]());     //1
例 1 では、arr 配列にはそれぞれ 10 個の変数が含まれています。匿名関数は外部変数 i にアクセスできます。arrFun1 が実行された後、そのスコープは破棄されますが、その変数はメモリ内にまだ存在し、ループ内の匿名関数からアクセスできます。この場合、i は 10;

Chestnut 2 では、arr 配列内に無名関数があり、無名関数の中に無名関数が存在しますが、一番内側の無名関数でアクセスした num は、上位の無名関数でメモリに保存されるので、毎回 i の値にアクセスします。

この記事は js チュートリアル 列からのものです。ぜひ学習してください。

以上がjsのスコープとクロージャの詳しい説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はcnblogs.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。