作用域-函式包圍程式碼
考慮一個函式傳統的方式是 ,宣告一個函式,在它內部新增程式碼。標題這裡做了一個角度的切換:在編寫程式碼外圍包裝一個函式說明,去“隱藏”這段程式碼。
我們看第一個程式碼片段:
function doSomething(a) { b = a + doSomethingElse( a * 2 ); console.log( b * 3 ); } function doSomethingElse(a) { return a - 1; } var b; doSomething( 2 ); // 15 複製程式碼
關注這裡的變數b
和doSomethingElse
函式,很可能是doSomething
函式的"私有細節",允許外圍的作用可訪問不僅沒必要而且可能是危險的。更加恰當的設計是將所有私有細節隱藏在doSomething
內部:
function doSomething(a) { function doSomethingElse(a) { return a - 1; } var b; b = a + doSomethingElse( a * 2 ); console.log( b * 3 ); } doSomething( 2 ); // 15 複製程式碼
驅使做這樣的程式碼隱藏,是一種成為“最低許可權原則”的軟體設計原則,也被稱為“最低授權”或“最少曝光”,即僅暴露所需要的最低限度的東西。結合上個程式碼片段,結合函式包圍程式碼這個主體,是用哪個作用域來包含變數和函式最適合的選擇 。
IIFE與函式包圍程式碼
我們看第二個程式碼片段:
var a = 2; function foo() { // <-- 插入這個 var a = 3; console.log( a ); // 3 } // <-- 和這個 foo(); // <-- 還有這個 console.log( a ); // 2 複製程式碼
在這段程式碼中,有函式包圍程式碼的痕跡,foo
函式存在的意義只是保障內部變數a
的宣告和a
的輸出。但是額外引入了兩個問題:
-
識別符號名稱
foo
汙染了外部作用域 -
需要手動呼叫函式
foo
——foo()
IIFE——立即呼叫的函式表示式可以解決這個問題:
var a = 2; (function foo(){ // <-- 插入這個 var a = 3; console.log( a ); // 3 })(); // <-- 和這個 console.log( a ); // 2 複製程式碼
識別符號名稱foo
僅存在於函式foo
內,且函式立即呼叫。
命名函式和匿名函式的比較
YDKJS-SCOPE CLOSURES-ch3 在討論IIFE時候,引入了命名函式和匿名函式的比較,認為命名函式完勝,三條理由:
arguments.callee
但架不住匿名函式方便阿,比如像arr#map
、arr#filter
等第一個引數傳函式,使用箭頭函式()=>{}
比較便利。所以我們來試著反駁這三條命名函式完勝的理由:
(anonymous)
總結一下:如果函式需要在之後呼叫自己,使用命名函式,否則其實匿名函式更加方便;如果使用了命名函式,函式命名要講究,找了找函式命名規範 :
- 考慮使用字首
動詞 | 含義 | 返回值 |
---|---|---|
can | 判斷是否可執行某個動作 ( 許可權 ) | 函式返回一個布林值。true:可執行;false:不可執行 |
has | 判斷是否含有某個值 | 函式返回一個布林值。true:含有此值;false:不含有此值 |
is | 判斷是否為某個值 | 函式返回一個布林值。true:為某個值;false:不為某個值 |
get | 獲取某個值 | 函式返回一個非布林值 |
set | 設定某個值 | 無返回值、返回是否設定成功或者返回鏈式物件 |
比如:
//是否可閱讀 function canRead(){ return true; } //獲取姓名 function getName{ return this.name } 複製程式碼
- 建議動賓結構——doSomething,比如 openFile、setName、addNumber
- 謹慎使用縮寫,除非是hi約定成俗廣泛使用的縮寫,否則老老實實使用完整拼寫