jsのプリコンパイル、スコープチェーン
20596 ワード
プリコンパイル
1.jsコードの実行手順文法解析:主にコードをスキャンしますが、文法上の誤りがありますか?例えば、括弧が少ない、中国語の記号を書きました. プリコンパイル:変数の宣言アップグレードを行い、関数全体を向上させ、直前の準備を行う. 解釈実行:jsコードを実行し、行を解釈し、行を実行する. 2.プリコンパイルの前奏は、大域変数を意味します.宣言なしに値が割り当てられ、この変数は大域的に所有されます. すべてのグローバル変数はwindowの属性 です.
たとえば:
スクリプトコードブロックスクリプトが実行される前に、システムが実行する操作は、GOオブジェクトを作成します.つまり、windowグローバルオブジェクト です.は、グローバル変数宣言(暗黙的大域変数宣言を含み、var宣言を省略する)を検索し、変数名作のグローバルオブジェクトの属性、値はundefined である.関数宣言を検索します.関数名は大域オブジェクトの属性として、値は関数参照 です.
例えばは、AOオブジェクト(実行期間コンテキスト) を作成する.は、関数内のモダリティを発見し、変数宣言はAOの属性名として、undefined とする.は、実参加と形参を統一する .は、定義された関数名をAOの属性に付け、値は関数体とする. 面接の問題を見に来ました.
1.グローバルスコープ
JSにはグローバルオブジェクトがあります.windowでは、グローバル宣言の変数はすべてwindowの属性に属します.
関数を定義するとき、関数はデフォルトでscopeという暗黙的な属性が存在します.すなわちドメインは、この属性は配列を指します.配列中に存在するのはチェーン式の関数セットがコンテキストを実行します.関数が定義されている時には、直接に親モジュールの役割領域を持ちます.例えば、windowで定義されている関数は、直接windowの役割領域を持ちます.関数が実行されると、独自の実行期間コンテキストが生成されます.
この例です
内部関数を外部に保存すると、クローズドが生成されます.クローズドが生成された後も、内部関数は外部関数の変数にアクセスできます.
原理
内部関数が定義されているときに内部関数に属するscope属性がスコープチェーンを保存しています.これは直接親関数のスコープチェーンを継承します.これは親関数に対する変数のアクセスがあるときに、このスコープは親レベル関数が破壊されないので、内部関数は親レベル関数の変数にアクセスできます.これはクローズドです.
解決方法
直ちに関数、letを実行します.
例えば
クローズドを使ってカウンタを実現します.は、1つの変数が長くメモリに記憶されることを望む .グローバル変数の汚染を避ける プライベートメンバの存在 はキャッシュ のために使用されます.
クローズドのデメリット
メモリ漏れの原因になりやすい
1.jsコードの実行手順
たとえば:
var a = 100;
console.log(window.a); //100
if(1){
a = 10;
}
console.log(window.a); //10
3.プリコンパイルスクリプトコードブロックスクリプトが実行される前に、システムが実行する操作
例えば
console.log(a); //undefined
console.log(func); //func
var a = 100;
function func(){
return 1;
}
関数実行前の操作a = 100;
function demo(e){
function e(){}
arguments[0] = 2;
console.log(e);
if(a){
var b = 123;
function c(){}
}
var c;
a = 10;
var a;
console.log(b);
f = 123;
console.log(c);
console.log(a);
}
var a;
demo(1);
console.log(a);
console.log(f);
予編訳を使ってこの問題を分析してみます.1, GO
GO = {}
2, , 62,46 ,
G0 = {
a:undefined,
demo:function(){...}
}
3, , 45 ,
GO = {
a:100,
demo:function(){...}
}
4,63 ,
AO={}
5, , AO , undefined
AO={
e:undefined,
d:undefined,
c:undefined,
d:undefined,
}
6,
AO={
e:1,
d:undefined,
c:undefined,
d:undefined,
}
7, AO ,
AO={
e:function(){...},
d:undefined,
c:undefined, // if,
d:undefined,
}
8,
function demo(e){
function e(){}
arguments[0] = 2; // AO , AO e 2
console.log(e); //2
if(a){ // if
var b = 123;
function c(){}
}
var c;
a = 10; // AO , AO a 10
var a;
console.log(b); // ,undefined
f = 123; // var, GO
console.log(c); // ,undefined
console.log(a); //10
}
var a;
demo(1);
console.log(a); // GO a
console.log(f); // GO f
最後の結果2
undefined
undefined
10
100
123
スコープ1.グローバルスコープ
JSにはグローバルオブジェクトがあります.windowでは、グローバル宣言の変数はすべてwindowの属性に属します.
var a = 10;
b = 10;
function fun(){
c = 10;
var d = 10;
}
fun();
console.log("window.a",window.a); //10
console.log("window.b",window.b); //10
console.log("window.c",window.c); //10
console.log("window.d",window.d); //undefined
2.作用ドメインチェーン関数を定義するとき、関数はデフォルトでscopeという暗黙的な属性が存在します.すなわちドメインは、この属性は配列を指します.配列中に存在するのはチェーン式の関数セットがコンテキストを実行します.関数が定義されている時には、直接に親モジュールの役割領域を持ちます.例えば、windowで定義されている関数は、直接windowの役割領域を持ちます.関数が実行されると、独自の実行期間コンテキストが生成されます.
この例です
var a=10
// window{
// a:10
//}
function fun1(){
var b=20;
function fun2(){
//
}
fun2();
}
fun1();
上述のように、プリコンパイルとスコープによってコード運行の具体的な手順を解読します.1. , GO, window
2. fun1 , window , scope , , GO,
scope(fun1):GO -->
2 fun1 , fun1 AO, scope AO ,
scope(fun1):AO(fun1) --> GO -->
3. fun1 , fun1 , fun2, fun2 scope , fun1,
scope(fun2): AO(fun1) --> GO -->
4. fun2 , fun2 , ,fun2 scope ,
scope(fun2): AO(fun2) --> AO(fun1) --> GO -->
5, fun2 ,
6, fun1 ,
アクセス変数の順番を見てください.var cc = 123;
function a(){
function b(){
var bb = 234;
aa = 0;
console.log(cc);
}
var aa = 123;
var cc = 111;
b();
console.log(aa);
}
a();
今関数bで変数にアクセスすると、関数bのscopeの中にシステムが探しに行きます.scopeは1つの配列です.0番目からアクセスします.1番目は関数bの作用領域です.見つけられないなら、関数aの作用領域を探し続けます.見つけられないなら、windowの作用領域で探し続けます.最後に見つけられない変数を探してください.間違ったことを投げることがあります.関数の実行結果は111
0
包みを閉じる内部関数を外部に保存すると、クローズドが生成されます.クローズドが生成された後も、内部関数は外部関数の変数にアクセスできます.
原理
内部関数が定義されているときに内部関数に属するscope属性がスコープチェーンを保存しています.これは直接親関数のスコープチェーンを継承します.これは親関数に対する変数のアクセスがあるときに、このスコープは親レベル関数が破壊されないので、内部関数は親レベル関数の変数にアクセスできます.これはクローズドです.
解決方法
直ちに関数、letを実行します.
例えば
クローズドを使ってカウンタを実現します.
function counterCreate(){
var count = 0;
return function(){
count++;
console.log(` ${count} `);
}
}
var addCount = counterCreate(); //
addCount();// 1
addCount();// 2
addCount();// 3
addCount();// 4
クローズドを使ってループ印刷を行います.for (var i = 0; i < 5; i++) {
setTimeout(function timer() {
console.log(i);
}, i * 100);
}
// 5 5 5 5 5
即時実行関数を使うfor (var i = 0; i < 5; i++) {
(function (i) {
setTimeout(function timer() {
console.log(i);
}, i * 100);
})(i);
}
// 0 1 2 3 4
クローズドのメリットクローズドのデメリット
メモリ漏れの原因になりやすい