【You Don't Know JS: Scope & Closures】Chapter 2 笔记

範畴有两种模型:

语彙範畴(Lexical Scope)动态範畴(Dynamic Scope)

Lex-time

语彙範畴(lexical scope)是在lexing time时期所定义的範畴。

换句话说,语彙範畴(lexical scope)是基于撰写程式码与程式区块的实际位置所定义出来的。

example

function foo(a) {    var b = a * 2;    function bar(c) {        console.log(a, b, c);    }    bar(b * 3);}foo(2); // 2 4 12

这个範例,有3个巢状範畴(nested scopes):
http://img2.58codes.com/2024/20112573bh6GWcqi0N.png
图片来源:You Don't Know JS: Scope & Closures

scope1:全域範畴(global scope),里面包含函式识别子(identifier) foo。scope2:函式foo的範畴,里面包含参数a,区域变数b,函式bar。scope3:函式bar的範畴,里面包含参数c

上面的图并不是文氏图(Venn diagram)。函式是无法同时存在于2个同层级的範畴。

Look-ups

上面範例的执行过程:

Engine执行foo(2);,接着执行bar(b * 3);,最后执行console.log(a, b, c);。这时需要对a,b,c执行RHS,所以Engine会从最内层的範畴开始搜寻。a,b不在bar的範畴中,所以Engine会往外层的範畴(foo)找,并且找到。在呼叫bar的同时,b * 3的运算结果,作为引数,传给c

Look-ups的动作,会在找到第一个符合的时候,就停止。

如果相同的识别子(identifier)名称,分别定义在不同层级的範畴,会发生shadowing的情况。

「shadowing」意思是,内层範畴的识别子遮住了外层範畴同名的识别子(identifier),换句话说,只要在当时执行的範畴中找到符合的识别子(identifier),Look-ups的动作就会停止,不管外层是否有同名的识别子(identifier)都不会採用。

无论是否有shadowing的情况。Engine执行Look-ups的动作,都会从当下的範畴开始执行,视情况再往外层推移。

全域变数(global variables)本身会成为全域物件(global object)window的属性。
我们可以藉由此特性,来存取被遮蔽的全域变数。

全域变数被遮蔽:

var c = 10;function foo(a) {    var b = a * 2;    var c = 5;    function bar(c) {        console.log(a, b, c);    }    bar(c);}foo(2); //2 4 5

使用全域物件取得属性值:

var c = 10;function foo(a) {    var b = a * 2;    var c = 5;    function bar(c) {        console.log(a, b, c);    }    bar(window.c);}foo(2); //2 4 10

但如果被遮蔽的是非全域变数(non-global)的话,就无法使用此方法。

不管在何处呼叫函式,也不管是如何呼叫的,该函式在宣告(declaration)的时候,就已经决定其语彙範畴(lexical scope)了,不会改变。

重点整理

语彙範畴(Lexical scope)在宣告函式的时候就已经定义好了,也就是实际撰写程式码的位置。

不要使用eval & with。

参考来源:
http://img2.58codes.com/2024/20112573OWtzPwjWh4.jpg

此为You Don't Know JS系列的笔记。


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章