詳解立即執行函數(function(){}()),(function(){})()

来源:https://www.cnblogs.com/jdWu-d/archive/2019/09/27/11587805.html
-Advertisement-
Play Games

要知道這幾種寫法之間的區別,我們要先聊些題外話——js中函數的兩種命名方式,即表達式和聲明式。 函數的聲明式寫法為:function foo(){/*...*/},這種寫法會導致函數提升,所有function關鍵字都會被解釋器優先編譯,不管是聲明在什麼位置,都可以調用它,但是它本身不會被執行,定義只 ...


  要知道這幾種寫法之間的區別,我們要先聊些題外話——js中函數的兩種命名方式,即表達式和聲明式。

  函數的聲明式寫法為:function foo(){/*...*/},這種寫法會導致函數提升,所有function關鍵字都會被解釋器優先編譯,不管是聲明在什麼位置,都可以調用它,但是它本身不會被執行,定義只是讓解釋器知道其存在,只有在被調用的時候才會執行。

圖1 聲明式函數

  函數的表達式寫法為:var foo=function(){/*...*/},這種寫法不會導致函數提升,於是就必須先聲明,再調用,否則會出錯,如圖2。

圖2 表達式函數

  現在,回到正題,(function(){}()),(function(){})()這兩種是js中立即執行函數的寫法,函數表達式後加上()可以被直接調用,但是把整個聲明式函數用()包起來的話,則會被編譯器認為是函數表達式,從而可以用()來直接調用,如(function foo(){/*...*/})(),但是如果這個括弧加在聲明式函數後面,如function foo(){/*...*/}(),則會報錯,很多博客說這種寫法()會被省略,但實際是會出錯,因為不符合js的語法,所以想要通過瀏覽器的語法檢查,就必須加點符號,比如()、+、!等,具體可以查看圖3。

圖3 立即執行函數

 

 

 總結一下就是:

function foo(){console.log("Hello World!")}()//聲明函數後加()會報錯
(function foo(){console.log("Hello World!")}())//用括弧把整個表達式包起來,正常執行
(function foo(){console.log("Hello World!")})()//用括弧把函數包起來,正常執行
!function foo(){console.log("Hello World!")}()//使用!,求反,這裡只想通過語法檢查。
+function foo(){console.log("Hello World!")}()//使用+,正常執行
-function foo(){console.log("Hello World!")}()//使用-,正常執行
~function foo(){console.log("Hello World!")}()//使用~,正常執行
void function foo(){console.log("Hello World!")}()//使用void,正常執行
new function foo(){console.log("Hello World!")}()//使用new,正常執行

  立即執行函數一般也寫成匿名函數,匿名函數寫法為function(){/*...*/},就是使用function關鍵字聲明一個函數,但未給函數命名,倘若需要傳值,直接將參數寫到括弧內即可如圖4所示。

圖4 立即執行函數的傳參

  將它賦予一個變數則創建函數表達式,賦予一個事件則成為事件處理程式等。但是需要註意的是匿名函數不能單獨使用,否則會js語法報錯,至少要用()包裹起來。上面的例子可以寫成如下形式:

(function(){console.log("我是匿名函數。")}())
(function(){console.log("我是匿名函數。")})()
!function(){console.log("我是匿名函數。")}()
+function(){console.log("我是匿名函數。")}()
-function(){console.log("我是匿名函數。")}()
~function(){console.log("我是匿名函數。")}()
void function(){console.log("我是匿名函數。")}()
new function(){console.log("我是匿名函數。")}()

  立即執行函數的作用是:1.創建一個獨立的作用域,這個作用域裡面的變數,外面訪問不到,這樣就可以避免變數污染。2.閉包和私有數據。提到閉包,不得不提下那道經典的閉包問題。

 1 <ul id=”test”>
 2     <li>這是第一條</li>
 3     <li>這是第二條</li>
 4     <li>這是第三條</li>
 5 </ul>
 6 
 7 <script>
 8     var liList=document.getElementsByTagName('li');
 9     for(var i=0;i<liList.length;i++)
10     {
11         liList[i].onclick=function(){
12             console.log(i);
13         }
14     };
15 </script>

  很多人覺得這樣的執行效果是點擊第一個li,則會輸出1,點擊第二個li,則會輸出二,以此類推。但是真正的執行效果是,不管點擊第幾個li,都會輸出3,如圖5所示。因為 i 是貫穿整個作用域的,而不是給每個 li 分配了一個 i,用戶觸發的onclick事件之前,for迴圈已經執行結束了,而for迴圈執行完的時候i=3。

圖5 各自點擊第1,2,3個li,或是之後再次點了多少次,都會輸出3,可見,右邊控制台輸出了8次3

  但是如果我們用了立即執行函數給每個 li 創造一個獨立作用域,就可以改寫為下麵的這樣,這樣就能實現點擊第幾條就能輸出幾的功能。

 1 <script>
 2     var liList=document.getElementsByTagName('li');
 3     for(var i=0;i<liList.length;i++)
 4     {
 5         (function(ii) {
 6            liList[ii].onclick=function(){
 7                console.log(ii);
 8            }
 9        })(i)
10     };
11 </script>

  在立即執行函數執行的時候,i 的值被賦值給 ii,此後 ii 的值一直不變,如圖6所示。i 的值從 0 變化到 3,對應3 個立即執行函數,這 3個立即執行函數裡面的 ii 「分別」是 0、1、2。

圖6 點擊第幾個li,就輸出幾

 

   其實ES6語法中的let也可以實現上述的功能,僅僅是將for迴圈中的var換成let,如下所示,有木有覺得很簡單明瞭。

1 <script>
2      var liList=document.getElementsByTagName('li');
3      for(let i=0;i<liList.length;i++)
4      {
5             liList[i].onclick=function(){
6                 console.log(i);
7              }
8      }
9 </script>

  那很多人就覺得用let可以完全取代立即執行函數,到目前為止,可能是我眼界所限制,我所能用到的立即執行函數的確能被let替代,前提是你的運行環境(包括舊的瀏覽器)支持ES2015。如果不支持,你將不得不求助於以前經典的函數。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 版權申明: 本文原創首發於以下網站,您可以自由轉載,但必須加入完整的版權聲明 博客園MogooStudio: csdn博客MogooStudio: 使用方法 Shell代碼設置到xcode運行腳本里 在每次成功構建後版本號會改變 Shell代碼 我的聯繫方式: QQ:2161044579 郵箱:mo ...
  • 系統環境要求 Flutter因為是新出的框架,所以對系統還是有一定的要求的。 MacOS(64 bit) 磁碟空間:大於700M,如果算上Android Studio等編輯工具,儘量大於3G。 命令號工具:bash、mkdir、rm、git、curl、unzip、which、brew 這些命令在都可 ...
  • jQuery(expression, [context]) 返回值:jQuery 概述 這個函數接收一個包含 CSS 選擇器的字元串,然後用這個字元串去匹配一組元素。 jQuery 的核心功能都是通過這個函數實現的。 jQuery中的一切都基於這個函數,或者說都是在以某種方式使用這個函數。這個函數最 ...
  • 上一章節,我們介紹了Hexo的基礎搭建,搭建完大家一定發現,是英文版本的,並且頁面有點醜陋。這一章節,就來跟大家介紹Hexo的配置和主題的設置。 站點信息 上一章有跟大家提到過_config.yml這個文件,這個我們先稱之為站點全局的配置文件,後續我們說到主題的時候,也會有一個這樣的文件,暫時稱它主 ...
  • <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>簡易計算器</title> <script src="./lib/vue.js"></script> </head> <body> <div id="app">... ...
  • 1.安裝 less 和 less-loader。 命令: npm install less less-loader --save-dev 2.打開 build/webpack.base.conf.js ,在 module.exports = 的對象的 module.rules 後面 添加一段:{te ...
  • 在面試題中,閉包應該是必問的問題吧(以下內容純屬個人理解,歡迎大家指正不足) 下麵我們就簡單的瞭解一下閉包這個東西到底是什麼 首先,我們先來講講什麼是閉包 簡單來說就是一個定義在函數內部的函數,可以讀取到其他函數內部變數的函數,本質上,閉包就是一個把函數內部和外部連接起來的橋梁 那我們讀取函數內部的 ...
  • Hexo 是一個輕量級、簡潔、高效且高逼格的博客框架。Hexo 使用 Markdown(或其他渲染引擎)解析文章,在幾秒內,即可利用靚麗的主題生成靜態網頁。同時有著豐富的主題,官網或者GitHub都可以輕鬆下載到。由於Hexo博客都是靜態文件,所以推薦部署在Github上,不需要額外的伺服器和後臺, ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...