專題 JavaScript 函數基礎

你將知道:

  • 函數聲明和表達式
  • 函數聲明和表達式之間的區別
  • 什么是匿名函數
  • 什么是 IIFE
  • 命名函數表達式
  • this 關鍵字


函數是調用該函數時執行的代碼塊 。

函數聲明和表達式

讓我們回顧一下它的語法:

functionfunctionName(param1, param2, ..., paramN) {// Function's body
}

那么什么是函數聲明?

函數聲明是指作為獨立語句而不是表達式存在的函數定義。

// Standalone statement,
// hence a function declaration.
function sum(a, b) {return a + b;
}// Another function declaration.
function outerFn() {// A function declaration within outerFn().function innerFn() {console.log('Working with functions.')}}

這里 sum()outerFn()innerFn() 都是函數聲明,因為它們是獨立的語句:

在 JavaScript 中,還有另一種創建函數的方式,盡管其語法與函數聲明相同,但工作方式略有不同。我們稱之為函數表達式

函數聲明與函數表達式最重要的區別在于,后者可以定義一個沒有名稱的函數,這樣的函數通常被稱為匿名函數 。無論如何,假設函數被分配給一個變量,那么函數表達式在語法上看起來是這樣的:

var identifierName = function [functionName](param1, param2, ..., paramN) {// Function's body
}

請注意,使用函數表達式時,可以選擇在 function 關鍵字后包含函數名稱(即 functionName ),如上面的語法所示( functionName 周圍有 [ ] )。

讓我們創建相同的函數 sum() ,這次使用函數表達式:

var sum = function(a, b) {return a + b;
}

這里發生的事情是,一個沒有名稱的函數被賦值給了變量 sum 。由于 sum 指向內存中的一個函數對象,所以我們可以使用表達式 sum()

下面我們將一個函數表達式作為參數傳遞給另一個函數:

function execute(fn) {fn();
}execute(function() { console.log('Hello World!'); })

這是 JavaScript 應用程序中常見的另一種編碼實踐。將一個函數作為參數傳遞給另一個函數,我們稱之為回調函數 ,或者簡稱為回調

function getLogger() {return function(val) {console.log('We are learning ' + val + '.');}
}var langIntro = getLogger();langIntro('JavaScript');

回調在 JavaScript 的事件 API 以及大量其他 API 中扮演著至關重要的角色。

在第 7 行,當調用 getLogger() 時,執行會轉到第 1 行中它的定義處,并退出并返回另一個函數的返回值。這個 “另一個” 函數接受一個參數 val ,并創建一個包含該參數和其他文本的日志。

由于 getLogger() 返回一個函數,因此 langIntro 中保存的值是對函數的引用——具體來說,是對第 2 行定義的匿名函數的引用。這意味著我們可以使用表達式 langIntro () 來調用此函數。這正是我們在最后一行所做的。

從其他函數返回的函數構成了 JavaScript 中的另一個重要概念,稱為閉包 ,盡管這個概念不僅存在于從其他函數返回的函數中;它也存在于其他地方。

從核心執行層面來看,函數聲明和函數表達式之間沒有任何區別。調用時,兩者的執行方式相同。區別僅在于腳本編譯時解析它們的方式。

函數聲明和表達式之間的區別

函數聲明和函數表達式之間主要有兩個區別。

  • 其中一個被 提升,而另一個則沒有。
  • 一個可以創建匿名函數,而另一個則不能。

1. Hoisting 提升

提升是指在執行任何其他代碼之前處理各自范圍內的所有變量聲明的行為。

變量提升是以下代碼有效并且不會引發錯誤的原因:

// We think that x doesn't exist at this point, likewise
// the following statement would throw an error.
// However, that's not the case.
console.log(x);var x = 10;
console.log(x);

內部實現是這樣的:引擎首先在代碼中搜索所有變量聲明語句并在運行任何其他代碼之前執行它們。完成后,它會從頭開始解析代碼。

這意味著在實際執行上述第 4 行之前,變量 x 已被有效聲明,因此可以訪問。由于 var xx 初始化為 undefined ,因此在第 6 行賦值語句之前訪問 x 會返回 undefined

對于函數聲明,也會發生類似的情況。我們稱之為函數提升 (function hoisting)

整個聲明連同函數主體都被置于其范圍的最頂部。這意味著下面的代碼將完全正常工作:

console.log(sum(10, 20));function sum(a, b) {return a + b
}

在第 3 行中,函數 sum() 在實際定義之前就被訪問了。然而,由于函數提升,這次調用并沒有標記任何錯誤。

塊語句內的函數聲明

我們知道,所有函數聲明都會被提升到其作用域的頂部。然而,這個想法有一個小例外,事實上,不同瀏覽器之間存在不兼容性。

也就是說,如果函數聲明出現在塊語句內,那不是另一個函數的主體(也是一個塊語句),則函數聲明在大多數瀏覽器中不會正常提升 - 只有其名稱可以通過值 undefined 訪問。

這種行為有一個很好的理由,從下面的代碼中可以看出:

var userIsNew = false;if (userIsNew) {function greet() {console.log('Hello!');}
}

函數 greet() 被放在 if 語句塊內。該語句塊執行的條件是 userIsNewtrue 。然而,事實顯然并非如此。因此,理想情況下,這段代碼的作者希望該函數不會出現在全局作用域中,因為它的出現條件尚未滿足。同樣,在這種情況下,大多數瀏覽器不會提升函數聲明,但函數名稱在相應的范圍內可用作 undefined 標識符。

這里要認識到的最重要的一點是,函數提升僅限于函數聲明 — — 而不是函數表達式 。

引擎在第一次遍歷一段代碼時僅查找函數聲明,而不是表達式,并將它們提升。

console.log(sum(10, 20));var sum = function(a, b) {return a + b
}//Uncaught TypeError: sum is not a function

我們有一個變量聲明語句 var sum ,同樣,它在運行任何其他代碼之前會被提升。接下來,從腳本開頭的第 1 行開始執行。此時, sum 等于 undefined ,因此無法調用;同樣, sum() 會拋出錯誤。

可能會認為可以通過在表達式中為函數添加名稱來緩解此問題。然而,這也行不通:

console.log(sum(10, 20));var sumRef = function sum(a, b) {return a + b
}
//Uncaught TypeError: sum is not a function

引擎只會在給定代碼片段中搜索函數聲明, 并最終將其提升。函數表達式,無論是命名的還是匿名的,都無關緊要。它們最終還是表達式,同樣會在提升階段被忽略。

2. 匿名函數

沒有名稱的函數稱為匿名函數

當 JavaScript 遇到函數聲明時,它期望也看到函數的名稱。否則會導致語法錯誤。

只有在函數表達式中才可以省略函數名稱,如下所示:

var sum = function(a, b) {return a + b;
}

匿名函數只能使用函數表達式來表示,是 JavaScript 中的一個重要特性。幾乎所有涉及事件和回調的程序都會用到它們.我們將廣泛使用匿名函數。

IIFE

在 JavaScript 中,有一種特殊情況,即函數表達式在定義后立即被調用。我們稱之為 IIFE ,即立即調用函數表達式

IIFE 是一個在定義后立即調用的函數表達式。

(function() {console.log('I am in an IIFE.')
})();

IIFE 用非常簡潔的語法解決了這個問題。它們將代碼封裝在本地環境中,不會干擾全局作用域。

最棒的是,這個過程非常快捷——我們無需命名這些函數,也無需擔心如何將它們賦值給任何標識符。只需創建一個匿名(或命名)函數,用一對括號將其封裝起來,將代碼放入其中,然后立即調用即可。 瞧!

每個庫的代碼都封裝在 IIFE 中,并且彼此之間完全互不干擾。 簡直太棒了。

this 關鍵字

JavaScript 中有很多令人困惑的概念,其中之一就是 this 的概念。本節我們將深入介紹并解釋 this 的核心。

首先, this 是 JavaScript 中的保留關鍵字,這意味著它不能用作變量的名稱。

回到 this 背后的想法,它是為了提供一種引用調用函數的對象的方式。這就是它被創建的初衷。事實上,編程語言 Java 無疑是 JavaScript 的影響源泉,它也包含 this 功能,本質上服務于非常相似的用途。

當在函數內部使用時, this 指的是調用該函數的對象 。

例如,考慮下面的對象 o 。它有一個屬性 x 和一個方法 f()

var o = {x: 10,f: function() { console.log(this.x); }
};var x = 20;
o.f();

一旦執行此代碼,我們就會在控制臺中記錄值 10

怎么樣? 我們來看看吧。

在第 7 行中,調用表達式 of() 在對象 o 上調用存儲在 of 中的函數,同樣,它的 this 也指向 o 。這僅僅意味著函數對象內部的表達式 this.x 轉換為 o.x ,等于值 10 ,因此控制臺中打印的是 10

這是因為 this 會自動指向調用對象——我們不需要自己將其配置為所需的對象。相反,如果我們使用 ox (而不是 this.x ),當 o 的名稱將來發生變化或被分配給其他標識符時,我們必須重寫這個表達式。理想情況下,只要有可能,就使用 this 關鍵字引用方法定義中的容器對象 - 而不是使用對象本身的名稱。

當直接調用函數對象(而不是作為對象的一部分)時,如果腳本在非嚴格模式下運行,則其 this 值將解析為全局 window 對象。

// The global context.
console.log(this);
Window {window: Window, self: Window, document: document, name: "", location: Location, …}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/88863.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/88863.shtml
英文地址,請注明出處:http://en.pswp.cn/web/88863.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

數據結構——優先隊列(priority_queue)的巧妙運用

優先隊列是一種相對高級的數據結構,它的底層原理是二叉堆。然而本篇不會執著于深挖其背后的原理,更主要的是理一下它在題目中的一些實用方法,幫助你更快的上手使用。 優先隊列(priority_queue) 優先隊列的特別之處就在于它可以自動進行排序&…

Java:繼承和多態(必會知識點整理)

主要內容繼承多態向上轉型向下轉型方法重寫方法重載super關鍵字動態綁定封裝訪問控制構造方法規則一、繼承 1. 概念: 一句話說就是:“共性抽取,代碼復用”子類會將父類中的成員變量或者成員方法繼承到子類中子類繼承父類之后,必須…

基于esp32系列的開源無線dap-link項目使用介紹

基于esp32系列的開源無線dap-link項目使用介紹🔖有關esp32/8266相關項目:需要自己搭建編譯環境: https://github.com/windowsair/wireless-esp8266-dap/tree/master🌿支持esp32/c3/s3,支持在線固件燒錄,支持AP配網&…

深入了解linux系統—— 進程信號的產生

前言 進程在收到信號之后,可以立即處理,也可以在合適的時間再處理(1-31號普通信號可以不被立即處理) 信號不是被立即處理,信號就要被保存下來,讓進程在合適的時間再去處理。 相關概念 在了解進程是如何保存…

【Bluedroid】藍牙協議棧enable流程深度解析

本文詳細剖析 Bluedroid 藍牙功能啟用的核心流程,從enable()函數觸發開始,深入解析藍牙協議棧的異步啟動機制、核心協議模塊初始化、硬件控制器綁定及狀態同步全流程。重點闡述接口就緒性檢查、異步線程管理、配置文件回調機制等關鍵環節,揭示…

各種開發語言主要語法對比

各類主流編程語言的語法有著顯著差異,這些差異源于語言設計哲學(簡潔性 vs 顯式性)、應用領域(系統級、Web、數據科學)、運行方式(編譯 vs 解釋)以及支持的范式(面向對象、函數式、過…

小鵬汽車6月交付車輛34,611輛,同比增長224%

小鵬汽車-W(09868)發布公告,2025年6月,小鵬汽車共交付智能電動汽車34,611輛,同比增長224%,這標志著小鵬汽車已連續第八個月交付量超過了30,000輛。2025年第二季度,小鵬汽車共交付103,181 輛智能電動車,創下…

深入理解觀察者模式:構建松耦合的交互系統

在軟件開發中,我們經常遇到這樣的場景:一個對象的狀態變化需要通知其他多個對象,并且這些對象需要根據變化做出相應的反應。比如,用戶界面中的數據變化需要實時反映到多個圖表上,或者電商系統中的庫存變化需要通知訂單…

React強大且靈活hooks庫——ahooks入門實踐之常用場景hook

什么是 ahooks? ahooks 是一個 React Hooks 庫,提供了大量實用的自定義 hooks,幫助開發者更高效地構建 React 應用。其中場景類 hooks 是 ahooks 的一個重要分類,專門針對特定業務場景提供解決方案。 安裝 ahooks npm install …

Qt常用控件之QWidget(一)

Qt常用控件之QWidget(一)1.QWidget2.enabled屬性2.geometry🌟🌟hello,各位讀者大大們你們好呀🌟🌟 🚀🚀系列專欄:【Qt的學習】 📝📝本…

AIOT開發選型:行空板 K10 與 M10 適用場景與選型深度解析

前言 隨著人工智能和物聯網技術的飛速發展,越來越多的開發者、學生和愛好者投身于創意項目的構建。 在眾多的開發板中,行空板 K10 和 M10 以其獨特的優勢脫穎而出。 本文旨在為讀者提供一份詳盡的行空板 K10 和 M10 對比分析,從適用場景、…

redis匯總筆記

語雀完整版: https://www.yuque.com/g/mingrun/embiys/calwqx/collaborator/join?tokensLcLnqz5Rv8hOKEB&sourcedoc_collaborator# 《Redis筆記》 Redis 一般問題 Redis內存模型(I/O多路模型)多路復用IO如何解釋 為什么Redis要使用單線…

STM32用PWM驅動步進電機

硬件介紹:連線:注意這里stp連的是pwm脈沖,dir連的是方向到時候代碼pwm波形就是從這里來的,具體接線根據你的代碼來注意要點:步進電機和舵機驅動是不一樣的,它是根據步長來移動的,所以要開一個中…

力扣25.7.10每日一題——重新安排會議得到最多空余時間 II

Description 今天這道題和昨天類似,只是允許順序變化。 Solution 把會議區間視作桌子,空余時間視作空位,我們要把一個桌子移到別的空位中。 初步想法是枚舉桌子,找一個長度大于等于桌子長度的空位移過去。看上去,找…

IP報文分片與重組原理及實現分析

IP報文分片與重組原理及實現分析 引用: ppp/net/packet/IPFragment.hppp/net/packet/IPFragment.cpp 1. IP分片原理 當IP數據包大小超過MTU(最大傳輸單元)時,路由器/主機將其分割為多個片段傳輸,每個片段包含&…

[python]在drf中使用drf_spectacular

安裝drf_spectacular 文檔 pypi鏈接:https://pypi.org/project/drf-spectacular/ 文檔鏈接:https://drf-spectacular.readthedocs.io/en/latest/readme.html 安裝步驟 在環境中添加 pip install drf-spectacular在setting的INSTALLED_APPS中添加 INSTALLED_APPS [# ALL…

【Datawhale AI 夏令營】 用AI做帶貨視頻評論分析(二)

5.預訓練模型跑分 回顧賽題 回顧賽題任務 挑戰與難點: 標注數據少 ——> 半監督學習 or 數據增強 聚類分析噪點影響嚴重 回顧Baseline 問題: TF-IDF無法捕捉以下語義。聚類分析粗糙,未評估聚類質量。 提升方案: 分類任務…

SPSSPRO:數據分析市場SaaS挑戰者的戰略分析

目錄 第一部分:執行摘要 第二部分:平臺解構:產品、架構與用戶體驗 2.1 SaaS范式轉移:架構與起源 2.2 功能能力:分析師的工具箱 2.3 “智能分析”的價值主張 第三部分:市場滲透與受眾細分 3.1 目標用戶…

低版本hive(1.2.1)UDF實現清除歷史分區數據

目標&#xff1a;通過UDF實現對表歷史數據清除 入參&#xff1a;表名、保留天數N 一、pom文件 <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.…

C++中頂層const與底層const

在C中&#xff0c;const關鍵字用于定義常量&#xff0c;但它在指針和引用上下文中會產生兩種不同的常量性&#xff1a;頂層const&#xff08;top-level const&#xff09;和底層const&#xff08;low-level const&#xff09;。理解它們的區別是避免編譯錯誤和提高代碼質量的關…