什麼是匿名函數:沒有實際名字的函數瀏覽器
匿名函數的做用:bash
一、經過匿名函數能夠實現閉包(必須掌握的知識點)閉包
二、模擬塊級做用域,減小全局變量。執行完匿名函數,存儲在內存中相對應的變量會被銷燬,使用塊級做用域,會大大下降命名衝突的問題,沒必要擔憂搞亂全局做用域了。
函數
詳解匿名函數:ui
聲明一個普通函數:
this
function zxx () {
console.log('good girl')
}
複製代碼
將函數的名字去掉spa
function () { // 此時瀏覽器會報錯
console.log('good girl')
}
複製代碼
正肯定義的匿名函數.net
(function () {
// 因爲沒有執行該匿名函數,因此不會執行匿名函數體內的語句。
console.log('zxx')
})
複製代碼
對去掉名字的函數加入括號後就是一個匿名函數了:調試
小括號的做用:code
小括號能把咱們的表達式組合分塊,而且每一塊,也就是每一對小括號,都有一個返回值。這個返回值實際上也就是小括號中表達式的返回值。因此,當咱們用一對小括號把匿名函數括起來的時候,實際上小括號返回的就是一個匿名函數的Function對象。所以,小括號對加上匿名函數就如同有名字的函數般被咱們取得它的引用位置了。因此若是在這個引用變量後面再加上參數列表,就會實現普通函數的調用形式。 通俗點講就是,加入小括號後就實現了和具名函數同樣的形式。
匿名函數自執行,也稱爲當即執行函數表達式(IIFE)
// 無參數的匿名函數
(function () {
console.log('zxx')
})();
// 帶參數的匿名函數
(function (a, b, c) {
console.log('參數一:', a) // 參數一: 這是普通函數傳參的地方
console.log('參數二:', b) // 參數二: 我是參數二
console.log('參數三:', c) // 參數三: zxx
})('這是普通函數傳參的地方', '我是參數二', 'zxx')
複製代碼
// 推薦使用
(function () {
console.log('zxx')
}())
複製代碼
!function (zxx) {
console.log(zxx)
}('zxx')
複製代碼
let zxx = function (zxx) {
console.log(zxx)
}('zxx')
複製代碼
IIFE經常使用用法
IIFE 的另外一個很是廣泛的進階用法是把它們看成函數調用並傳遞參數進去。
var a = 2;
(function IIFE (global) {
var a = 3
console.log(a) // 3
console.log(global.a) // 2
})(window)
console.log(a) // 2
IIFE 還有一種變化的用途是倒置代碼的運行順序,
將須要運行的函數放在第二位,
在 IIFE 執行以後看成參數傳遞進去
var a = 2;
(function IIFE (def) {
def(window)
})(function def (global) {
var a = 3
console.log(a) // 3
console.log(global.a) // 2
})
複製代碼
匿名函數應用場景
1.事件
$('#zxx').onclick = function () {
console.log('給按鈕添加點擊事件')
}
2.對象
var obj = {
name: 'zxx',
zxx: function () {
return this.name + ' is' + ' good girl'
}
}
console.log(obj.zxx()) // zxx is good girl
3.函數表達式
var zxx = function () {
return 'zxx is good girl'
}
console.log(zxx()) // zxx is good girl
4.回調函數
setInterval(function () {
console.log('zxx is good girl')
}, 1000)
5.做爲函數的返回值
function zxx () {
// 返回匿名函數
return function () {
return 'zxx'
}
}
console.log(zxx()()) // zxx
複製代碼
匿名函數模仿塊級做用域
if (true) {
var a = 12 // a爲全局變量
}
console.log(a) // 12
for (var i = 0; i < 3; i++) {
// console.log(i)
}
console.log(i) // 3 for沒有本身的做用域,因此當循環結束後i就成爲全局變量
if () {}for () {} 等沒有本身的做用域。
若是有,出了本身的做用域,
聲明的變量就會當即被銷燬了。
但能夠經過匿名函數來模擬塊級做用域:
function fn () {
(function () { // 這裏是咱們的塊級做用域(私有做用域)
var zxx = 'good girl!' // 此變量在外部並未定義
console.log(zxx) // good girl!
})()
console.log(zxx) // 報錯Uncaught ReferenceError: zxx is not defined
}
fn()
複製代碼
習題一
function test(a, b, c, d){
console.log(a + b + c + d);
}(1, 2, 3, 4);
// 不執行也不報錯
==============
function test(){
console.log(a + b + c + d);
}();
// 報錯:Uncaught SyntaxError: Unexpected token )
複製代碼
習題二
function zxxFn (){
var arr = [];
for(var i = 0; i < 10; i ++){
arr[i] = function (){
console.log(i);
}
}
return arr;
}
var zxx = zxxFn();
for(var j = 0; j < 10; j++){
zxx[j]();
}
複製代碼
詳解
zxxFn中因爲for不是塊級做用域,因此var i 變成 zxxFn的局部變量,每次新的i都會覆蓋原來的,最終i=10。因此會輸出10個10
習題三
function zxxFn(){
var arr = [];
for(var i = 0; i < 10; i ++){
(function(j){
arr[i] = function (){
console.log(j + " ");
}
}(i))
}
return arr;
}
var zxx= zxxFn();
for(var j = 0; j < 10; j++){
zxx[j]();
}
複製代碼
詳解:
這題使用了當即執行函數,把zxxFn中的i當參數傳給了,匿名函數的j,因此每次執行j的狀態都會更新,因此會輸出0 1 2 3 4 5 6 7 8 9
匿名函數的缺點
1. 匿名函數在棧追蹤中不會顯示出有意義的函數名,使得調試很困難。
2. 若是沒有函數名,當函數須要引用自身時只能使用已通過期的 arguments.callee 引用, 好比在遞歸中。另外一個函數須要引用自身的例子,是在事件觸發後事件監聽器須要解綁自身。
3. 匿名函數省略了對於代碼可讀性 / 可理解性很重要的函數名。一個描述性的名稱可讓代碼不言自明。