一、函數的作用域
首先,作用域就是指變量的作用范圍
然后,在JS中只有兩個作用域:1.全局作用域,2.局部作用域(函數作用域)
-
全局作用域
- 簡介:
全局作用域就是函數作用域外的作用域,處于window對象之中; -
全局變量:
1.全局變量是指不在函數內部創建的變量,全局變量都處于window對象之中,如下變量就是在一個全局變量:
全局變量
2.另外,在函數內部創建變量時,如果不加var進行聲明,那么這個變量也是全局變量,
不加var聲明的變量都是全局變量
- 簡介:
-
局部作用域(函數作用域)
- 簡介:
局部作用域是指在創建了函數后,在函數內部形成的作用域; -
局部變量:
1.局部變量是指在函數內部通過var進行聲明的變量,如下變量就是一個局部變量:
局部變量
- 簡介:
-
全局變量和局部變量的調用
-
在函數中,如果函數需要傳入一個變量,而這個變量并不在它自身內部,那么就可以調用全局下的變量:
函數調用全局變量 -
全局作用域下不能調用函數內的局部變量
提示錯誤變量a沒有聲明 -
那么如何在全局作用域下對局部變量進行調用呢?有兩個辦法:1、函數return這個變量再賦值;2、使用閉包;
1.函數return這個變量,再將return的值賦值給一個全局變量:
把變量return后賦值
2.使用閉包,在函數內部再創建一個函數,返回這個函數:
使用閉包
-
- 關于關鍵詞var的兩點
-
在全局作用域下的函數中不加var對變量進行聲明時,就是全局變量:
不加var進行聲明的變量都是全局變量 -
在同一個作用域內,當一個變量已經被聲明并被賦值,后面再次對其進行聲明,該變量的值不變:
重復聲明值不變
-
二、關于函數的作用域鏈
簡介
1.函數的作用域鏈就是指函數在調用變量時所經過的路徑,比如函數fn調用變量a,但是它自身并沒有變量a(沒有在函數內部用var進行聲明),于是就從全局作用域下找變量a,找到就調用全局變量a,那么這個過程就是函數fn的作用域鏈;
2.要了解函數作用域鏈,首先就要知道在函數對象中,擁有一個內部屬性[[Scope]]
,該內部屬性包含了函數被創建的作用域中對象的集合,這個集合被稱為函數的作用域鏈,它決定了哪些數據能被函數訪問。
3.簡單來說:函數對變量的調用是由自身開始向外一層一層找的,距離自身最近變量被找到,就調用該變量;-
畫出函數的作用域鏈
1.代碼如下:
2.首先因為變量提升和聲明前置,我們將代碼修改成下面這樣:
變量提升和聲明前置
3.第一步找到全局作用域下,發現有全局變量i和全局變量fn,然后全局變量fn變成了一個函數,于是可以寫出如下偽代碼:
全局作用域下
4.找到函數fn作用域下,發現有局部變量i和函數fn2,但是因為沒有執行,所以這兩項并未被創建,又因為函數fn處于全局作用域下,所以它也可以對全局作用域下的變量進行調用,所以fn的[[Scope]]
包含全局作用域globalScope
:
fn作用域下
5.然后在函數fn中有一個函數fn2,發現它里面沒有自身的局部變量,但是因為fn2是在函數fn內被聲明,所以fn2的[[Scope]]
包含fn的作用域fnScope
,并且fn2也可以對全局作用域下的變量進行調用,所以也包含全局作用域globalScope(全局作用域)
;
fn2作用域下
6.執行函數fn,進入了fn的執行上下文中fn execution context
,此時聲明了變量i以及函數fn2,i此時未被賦值,所以是i的值是undefined:
7.因為i的值是undefined,所以console.log(i)
得到的就是undefined,所以執行fn得到的第一個結果就是undefined,然后將99賦值給了i,i變為99
8.然后執行fn2,進入到fn2的執行上下文fn2 execution context
,fn2將100賦值給i,但是因為它自身沒有變量i,于是先到上一層,也就是函數fn中找變量i,得到fn中的i后進行賦值,函數fn中的i變為了100,所以下面的console.log(i)
得到的值就是100,函數fn執行的第二個結果就是100;
9.執行完函數fn后,進入到全局作用域的執行上下文global execution context
中,將10賦值給全局變量i,20賦值給全局變量fn,然后因為下面的console.log(i)
是在全局作用域下執行,所以這里的i是全局變量的i,得到最后一個結果10;
10.所以這段代碼的執行結果依次為undefined、100、10
,而以上這個一層一層向上找變量的過程就是作用域鏈;
結果
三、函數遞歸
- 什么是遞歸
遞歸簡單說來就是不斷地重復執行同樣的代碼來解決問題 - 函數的遞歸
1.特點:
①:自己調用自己;
②:要設定終止條件;
2.優缺點
①:算法簡單;
②:效率低; - 一個使用遞歸的簡單例子,求n的階乘
n!
比如求5的階乘就是5! = 5*4*3*2*1
由此可知,n的階乘就是n! = n*(n-1)*(n-2)....
而(n-2) = (n - 1) - 1
由此可知代碼如下:
求階乘
輸出結果: