目標(biāo):
* 如何定義和使用函數(shù)
* 如何向函數(shù)傳遞參數(shù)
* 了解預(yù)定義函數(shù)(內(nèi)建函數(shù))
* 了解變量作用域 ?
* “函數(shù)也是數(shù)據(jù)”
* 匿名函數(shù)的調(diào)用
* 回調(diào)函數(shù)
* 自調(diào)函數(shù) ?
* 內(nèi)嵌函數(shù)
* 以函數(shù)為返回值的函數(shù) ?
* 能重定義自身的函數(shù)
* 閉包 ?
*****
# 函數(shù)
實(shí)質(zhì)為代碼分組形式,便于重用;
組成:`function + 函數(shù)名 + 參數(shù) + 函數(shù)體(代碼塊) + return (undefined)`
調(diào)用/請求:函數(shù)名 + ([參數(shù)])
傳遞的參數(shù),少了,參數(shù)設(shè)為undefined,多了,忽略。
函數(shù)內(nèi)建有**arguments**數(shù)組(類似數(shù)組的對象),可返回所接收的全部參數(shù)。
```
function args(){return arguments;}
args();
// Arguments?[callee: ?, Symbol(Symbol.iterator): ?]
args(1,2,3,4,true);
// Arguments(5)?[1, 2, 3, 4, true, callee: ?, Symbol(Symbol.iterator): ?]
```
# 內(nèi)建函數(shù)
* parseInt()
* parseFloat()
* isNaN()
* isFinite()
* encodeURI()
* decodeURI()
* encodeURIComponent()
* decodeURIComponent()
* eval()
*****
## parseInt(a1,radix)
將a1轉(zhuǎn)換成整數(shù)類型,失敗返回NaN;
最好指明radix進(jìn)制。
```
parseInt('abc123')
// NaN
parseInt('123abc')
// 123 在遇到第一個(gè)異常字符時(shí)會(huì)放棄轉(zhuǎn)換 ?
parseInt(NaN);
// NaN
parseInt(1e1)
// 10
parseInt('1e1');
// 1
```
`radix`一般默認(rèn)為10,即10進(jìn)制,例外情況:
首參數(shù)字符串是0x開頭,radix=16;
首參數(shù)字符串是0開頭,radix=8;
## parseFloat(a)
只支持轉(zhuǎn)換為10進(jìn)制數(shù),多余參數(shù)會(huì)忽略
可轉(zhuǎn)換指數(shù)數(shù)據(jù),parseInt不支持 ?
```
parseFloat('123e2');
// 12300
parseInt('123e2', 10);
// 123
parseFloat('1e1');
// 10
```
## isNaN()
用于判斷輸入值是否是非數(shù)值,`true-非數(shù),false-數(shù)值`,即返回false才可作算術(shù)運(yùn)算
```
isNaN('a');
// true
isNaN('123');
// false
isNaN(parseInt(NaN));
// true
```
## isFinite()
檢查輸入是否一個(gè)既非infinity也非NaN數(shù)字,是否有限數(shù)值,true-有限
```
isFinite(Infinity);
// false
isFinite(12);
// true
```
## URI編碼與解碼
`encodeURI()`——域名部分不編碼
`encodeURIComponent()`——全部編碼
`decodeURI()`——域名部分不編碼
`decodeURIComponent()`——全部編碼
## eval()
欺騙函數(shù),類似Function()
將傳入的string作為代碼執(zhí)行,動(dòng)態(tài)代碼,
* 性能差;
* 安全性差;
## alert()
# 變量的作用域 ?
全局變量:聲明在所有函數(shù)之外的變量;
局部變量:聲明在某個(gè)函數(shù)內(nèi)部的變量,在該函數(shù)外是不可見的。
> 聲明一個(gè)變量如果沒有使用var語句,該變量會(huì)被默認(rèn)為全局變量!
> 減少全局變量的數(shù)量
函數(shù)域優(yōu)先于全局域
```
var a= 123;
function f() {
alert(a);
var a = 1; // 局部變量a聲明被提升至函數(shù)域頂部,只聲明被提升!
alert(a);
}
f(); // undefined 1
```
# 函數(shù)也是數(shù)據(jù)
函數(shù)標(biāo)識(shí)記法,像變量一樣使用函數(shù)
函數(shù)名不能以數(shù)字開頭;
```
// function f(){return;}
var f = function(){return;}
typeof f; // "function"
```
函數(shù)特性:
* 它們所包含的是代碼;
* 它們是可執(zhí)行的;
## 匿名函數(shù)
兩種用法:
* 將匿名函數(shù)作為參數(shù)傳遞給其他函數(shù);
* 定義匿名函數(shù)來執(zhí)行某些一次性任務(wù);
## 回調(diào)函數(shù) Callback()
將函數(shù)A傳遞給函數(shù)B,由B來執(zhí)行A,A就是一個(gè)(匿名)回調(diào)函數(shù)
優(yōu)勢:
* 匿名傳遞函數(shù),節(jié)省全局變量;
* 將調(diào)用A的操作委托給B,節(jié)省代碼量;
* 提升性能;
## 自調(diào)函數(shù) IIFE
`(function(參數(shù)){函數(shù)體})('入?yún)?#039;)`
## 內(nèi)部(私有)函數(shù)
好處:
* 確保全局名字空間的純潔性;
* 私有性,暴露該暴露的,封裝其余的;
## 返回函數(shù)的函數(shù)
`return function(){...};`
## 能重寫自己的函數(shù)
利用返回函數(shù)覆蓋舊函數(shù);
執(zhí)行一次性初始化工作;
* 外部重寫;
* 內(nèi)部重寫;
```
function a(){
alert('A!');
a = function(){
alert('B!');
}
}
a(); // A!
a(); // B!
```
"瀏覽器特性探測"技術(shù)實(shí)現(xiàn)原理
# 閉包
## 作用域鏈
在函數(shù)中可訪問的變量,既可以來自自身作用域,也可以來自其父級(jí)作用域。這就是一條作用域鏈(scope chain)。
## 詞法作用域
每個(gè)函數(shù)在被**定義時(shí)**都會(huì)創(chuàng)建一個(gè)屬于自己的環(huán)境(作用域)
```
function f1(){var a = 1; f2();}
function f2(){return a;}
f1();
// Uncaught ReferenceError: a is not defined
```
我們可以在函數(shù)中對變量執(zhí)行添加、移除和更新等操作,但函數(shù)只會(huì)看到該變量的最終狀態(tài)。因此我們可以重寫函數(shù)執(zhí)行體,依舊能正常工作。
## 利用閉包突破作用域鏈
將函數(shù)移動(dòng)到詞法作用域以外,函數(shù)仍記得其所定義作用域的路徑,保持著對原定義作用域的引用,依舊可以訪問原作用域的變量。
### 閉包1
```
function f(){
var b = 'b';
return function(){
return b;
}
}
b;
// Uncaught ReferenceError: b is not defined
var n = f(); // n 為全局變量,可以訪問f()私有空間
n;
// ? (){ return b; }
n();
// "b"
```
### 閉包2
```
var n;
function f(){
var b = "b";
n = function(){
return b;
}
}
f();
n();
// "b"
```
### 閉包3
函數(shù)綁定的是作用域本身,而非變量或返回值
```
function f(arg){
var n = function(){
return arg;
}
arg++;
return n;
}
var m = f(123);
m();
124
```
## Getter & Setter
通過匿名自調(diào)函數(shù),供全局函數(shù)間接訪問局部變量secret
```
var getValue, setValue;
(function(){
var secret = 0;
getValue = function(){
return secret;
};
setValue = function(v){
secret = v;
};
})()
getValue(); // 0
setValue(123);
getValue(); // 123
```
