(1) 範囲
変数のスコープとは、プログラムのソースコード内で定義された変数の領域です。
1. JS で字句スコープが使用されます
関数内で宣言されていない変数 (関数内で var が省略されている場合もグローバルとみなされます) は、グローバル変数 (グローバル スコープ) と呼ばれます
関数内で宣言された変数は関数スコープを持ち、ローカル変数です
ローカル変数はグローバル変数よりも優先されます
関数内で var を省略すると、実際にはグローバル変数に書き換えられるため、グローバル変数に影響します
関数スコープ、つまり関数はスコープの基本単位です。js には if for などの c/c のようなブロックレベルのスコープがありません。
もちろん、js では高階関数も使用されており、実際には入れ子関数として理解できます
test1()の後、外側の関数が呼び出され、内側の関数が返され、Continue()すると、それに応じて内側の関数が呼び出されて実行されるため、「one」
が出力されます。ネストされた関数にはクロージャが含まれます。これについては後で説明します。ここで、内側の関数は外側の関数で宣言された変数名にアクセスできます。これにはスコープ チェーン メカニズムが関係します。
2. 事前にJSで宣言
js の関数スコープは、関数内で宣言されたすべての変数が関数本体内で常に表示されることを意味します。また、宣言前に変数を使用することもできます。この状況をホイスティング
と呼びます。ヒント: 事前宣言は、JS エンジンのプリコンパイル時に行われます。事前宣言は、コードが実行される前に発生します。
たとえば
上記により次のような効果が得られます
var をもう一度削除してみますか?これはグローバル変数になった関数内の名前なので、未定義ではなくなりました
3. テストにパラメータがある場合は、上記のパラメータが渡されないことに注意してください。
前に述べたように、基本型は値によって渡されるため、テストに渡される名前は実際には単なるコピーであり、関数が返された後にこのコピーはクリアされます。
関数内の name="two" がグローバル名を変更するとは考えないでください。これらは 2 つの独立した名前であるためです
(2) スコープチェーン
上記の高度な機能にはスコープ チェーンが含まれます
1. 説明するために大きな段落を導入します:
JavaScript コードの各部分 (グローバル コードまたは関数) には、スコープ チェーンが関連付けられています。
このスコープ チェーンは、オブジェクトのリストまたはリンクされたリストであり、このオブジェクトのグループは、このコードの「スコープ内」の変数を定義します。
js が変数 x の値を見つける必要がある場合 (このプロセスは変数解決と呼ばれます)、このオブジェクトに x という名前の属性がある場合、この属性の値は次のようになります。最初のオブジェクトに x という名前の属性がない場合、js はチェーン内の次のオブジェクトの検索を続けます。 2 番目のオブジェクトに x という名前の属性がまだない場合は、引き続き次のオブジェクトの検索が続きます。スコープ チェーン内のオブジェクトに属性 x が含まれていない場合、x はこのコードのスコープ チェーンに存在しないとみなされ、最終的に ReferenceError 例外がスローされます。
2. スコープチェーンの例:
js のトップレベル コード (つまり、関数定義が含まれていないコード) では、スコープ チェーンはグローバル オブジェクトで構成されます。
ネストを含まない関数本体には、スコープ チェーン上に 2 つのオブジェクトがあります。1 つ目は関数パラメータとローカル変数を定義するオブジェクトで、2 つ目はグローバル オブジェクトです。
ネストされた関数本体では、スコープ内に少なくとも 3 つのオブジェクトがあります。
3. スコープチェーン作成ルール:
関数が定義されると (定義されたときに関数が開始されることに注意してください)、実際にはスコープ チェーンが保存されます。
この関数が呼び出されると、そのパラメーターまたはローカル変数を格納するための新しいオブジェクトが作成され、そのオブジェクトがそのスコープ チェーンに追加され、関数呼び出しスコープの新しいより長い表現「チェーン」が作成されます。
入れ子関数の場合は、状況が再び変わります。外部関数が呼び出されるたびに、内部関数が再定義されます。外部関数が呼び出されるたびにスコープ チェーンが異なるためです。内部関数は定義されるたびに微妙に異なる必要があります。内部関数のコードは外部関数が呼び出されるたびに同じであり、このコードに関連付けられたスコープ チェーンも異なります。
(ヒント: 上記の 3 つのポイントをよく理解して、覚えておいてください。自分の言葉で言うのが最善です。そうでないと、面接官が直接「スコープ チェーンについて説明してください。」と質問するため、覚えておく必要があります。 )
スコープチェーンの実際的な例:
上記はネストされた関数です。これに応じて、スコープ チェーンには 3 つのオブジェクトが存在する必要があります
次に、呼び出し時に name の値を見つける必要があります。スコープ チェーンで
test1() が正常に呼び出された場合、順序は test1()->test()-> グローバル オブジェクト ウィンドウです。 name の値 3 が test1() で見つかったので、検索が完了し、
test1() が正常に呼び出された場合、順序は test2()->test()->global object window になります。test2() では name の値が見つからないため、test() で探します。 ) を検索し、name の値が 2 の場合、検索は完了し、が返されます。
別の例としては、面接中に時々間違いを犯したり、騙されたりすることがよくあります。
为什么?
根据作用域链中变量的寻找规则:
这里有一个函数,它是匿名函数,既然是函数,那就在作用域链上具有一个对象,这个函数里边使用到了变量i,它自然会在作用域上寻找它。
查找顺序是 这个匿名函数 -->外部的函数buttonInit() -->全局对象window
匿名函数中找不到i,自然跑到了buttonInit(), ok,在for中找到了,
这时注册事件已经结束了,不要以为它会一个一个把i放下来,因为函数作用域之内的变量对作用域内是一直可见的,就是说会保持到最后的状态
当匿名函数要使用i的时候,注册事件完了,i已经变成了4,所以都是Button4
那怎么解决呢?
给它传值进去吧,每次循环时,再使用一个匿名函数,把for里边的i传进去,匿名函数的规则如代码
这样就可以 Button1..2..3了
4.上述就是作用域链的基本描述,另外,with语句可用于临时拓展作用域链(不推荐使用with)
语法形如:
with(object)
statement
这个with语句,将object添加到作用域链的头部,然后执行statement,最后把作用域链恢复到原始状态
简单用法:
比如给表单中各个项的值value赋值
一般可以我们直接这样
After introducing with (because using with will cause a series of problems, so let’s use the form above)
In addition, if an object o has an x attribute, o.x = 1;
Then use
can be converted into o.x = 2;
If o does not define attribute x, its function is just equivalent to x = 2; a global variable.
Because with provides a shortcut to read the attributes of o, but it cannot create attributes that o itself does not have.
The above is the entire content of this article. I hope it will be helpful to everyone learning javascript.