js採用的是詞法做用域鏈,在代碼書寫階段,做用域鏈就被定義了,因此 對於新手來講,要搞讀懂js代碼,首先就要弄清楚js的做用域鏈,下面看一份代碼數組
function test(a){ var b = a+2; var bar = function(c){ console.log(a,b,c); } bar(b*a); } test(2);
這個函數中 咱們定義了一個test 函數,該函數中咱們能夠看出做用域鏈層層嵌套,首先是全局的,而後是test,而後是bar,在上下文執行棧中,全局執行環境會被放在棧底,而咱們的test函數會第二我的入棧,而後發現裏面嵌套了一個bar函數,又會將bar函數入棧瀏覽器
咱們用一個數組來比做執行上下文棧,那麼上面代碼能夠寫成閉包
var Esc = []; Esc.push(gloabContext);//首先全局上下文先壓入棧底 Esc.push(test); //其次是test的執行上下文 Esc.push(bar);//最後入棧的是bar Esc.pop(bar);//而後bar 執行完以後就彈出 變量回收,閉包變量會存在 Esc.pop(test);// test 彈出 Esc.pop(gloabContext);// 瀏覽器或者也頁面關閉時 全局執行環境清空
上面就是一個靜態做用域的執行流程,也就是說做用域只跟當前函數變量代碼聲明時有關,下面再看一個例子,函數
var test = "global test"; function foo(){ var test = "local test"; var bar = function(){ console.log(test); } bar(); } foo() //輸出 localtest
上面輸出的是local test ,由於當今入bar的執行上下文的時候,test 會在上一層做用域鏈foo的執行上下文中找到,也就是在做用域創建階段,bar函數和test變量會綁定在foo的執行上下文環境中,咱們再看一個例子spa
var value = 1; function foo() { console.log(value); } function bar() { var value = 2; foo(); } bar();//輸出爲1
上面的代碼,若是按照常規的思惟,咱們就會想到value 會在bar中找到,應該輸出2,但這種想法是錯的,由於做用域綁定在代碼書寫的時候就肯定了,也就是說,當foo函數在全局上下文執行環境書寫時,就跟全局value一塊綁定了,因此看成用域鏈向上查找的時候code
就會找到全局value,而不是bar中的,因此,js中的做用域鏈是在書寫代碼時肯定的,而不是在執行的時候肯定的。blog
咱們再看一到題目,作用域
var test = "global test"; function foo(){ var test = "local test"; var bar = function(){ console.log(test); } bar(); } foo() var test1 = "global test1"; function foo1(){ var test1 = "local test1"; var bar = function(){ console.log(test1); } return bar; } foo1()();
這兩段代碼輸出是同樣的嗎,若是同樣,那麼他們有不一樣點嗎?io