最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript ES5 函數從基礎到高級應用全解析

 更新時間:2025年11月07日 09:50:09   作者:愛吃甜品的糯米團子  
本文系統(tǒng)解析了ES5中函數的核心概念與應用,重點剖析了IIFE(作用域隔離)和閉包(狀態(tài)保存)的實現原理及典型應用場景,本文給大家介紹的非常詳細,感興趣的朋友跟隨小編一起看看吧

函數是 JavaScript(ES5)的核心語法單元,不僅承擔代碼復用功能,更是實現作用域隔離異步編程模塊化的基礎。

一、函數核心概念與專有名詞解析

專有名詞定義與說明
函數聲明(Function Declaration)通過 function 關鍵字顯式定義函數名的方式,支持 “函數提升”,可在聲明前調用。
函數表達式(Function Expression)將匿名 / 命名函數賦值給變量的方式,不支持函數提升,需賦值后調用。
arguments 對象函數內部的類數組對象(具有 length 屬性但無數組方法),存儲所有傳入的實參。
this 綁定函數執(zhí)行時的 “上下文對象”,指向由調用方式決定(非定義位置),ES5 無箭頭函數綁定規(guī)則。
IIFE(立即執(zhí)行函數)全稱 Immediately Invoked Function Expression,聲明后立即執(zhí)行,用于創(chuàng)建獨立作用域。
作用域鏈(Scope Chain)函數嵌套時形成的變量查找鏈,從當前函數作用域向上遍歷至全局作用域。
閉包(Closure)有權訪問另一個函數作用域中變量的函數,本質是作用域鏈的 “延長保留”。
回調函數(Callback)作為參數傳遞給另一個函數的函數,在特定時機(如異步操作完成)被調用。

二、函數定義與聲明:兩種方式的細節(jié)對比

函數有 “函數聲明” 和 “函數表達式” 兩種定義方式,二者在提升特性、作用域表現上存在關鍵差異,需結合實例理解。

2.1 函數聲明(支持函數提升)

語法與實例

// 函數聲明:function 關鍵字 + 函數名 + 參數列表 + 函數體
function calculateSum(a, b) {
  // 函數體:實現求和邏輯
  return a + b;
}
// 關鍵特性:函數提升(聲明前調用仍可執(zhí)行)
console.log(calculateSum(3, 5)); // 輸出:8(正常執(zhí)行,無報錯)

專有名詞補充:函數提升(Function Hoisting)

ES5 解析代碼時,會將函數聲明的 “函數名 + 函數體” 整體提升至當前作用域頂部,因此可在聲明前調用。但需注意:僅函數聲明支持提升,函數表達式不支持。

2.2 函數表達式(不支持函數提升)

匿名函數表達式即 “無函數名的函數”,賦值后通過變量名調用,是回調函數、一次性邏輯封裝的常用形式。

// 1. 聲明變量 fn,賦值為一個匿名函數(函數表達式的核心語法)
// 右側 function(){} 是匿名函數,無函數名,作為值賦值給 fn
var fn = function(a, b) {
  // 函數內部邏輯:計算兩數之和
  // 內部可訪問參數 a、b,以及外部作用域的變量(后續(xù)詳解)
  var sum = a + b;
  console.log("匿名函數內部:a + b =", sum); // 輸出計算結果
  return sum; // 返回結果給外部調用者
};
// 2. 調用函數表達式:通過變量名 fn 調用,傳入實參
// 外部通過變量名觸發(fā)函數執(zhí)行,獲取返回值
var result = fn(3, 5);
console.log("外部訪問函數返回值:", result); // 輸出:外部訪問函數返回值:8
// 關鍵注意:匿名函數本身無名字,無法在內部通過函數名遞歸(需用 arguments.callee)
var factorial = function(n) {
  if (n === 1) return 1;
  // 匿名函數內部無法通過“函數名”遞歸,需用 arguments.callee 指向當前函數
  return n * arguments.callee(n - 1);
};
console.log("匿名函數遞歸(階乘):", factorial(5)); // 輸出:120

命名函數表達式(帶函數名)

命名函數表達式是 “給函數本身指定名字的表達式”,函數名僅在函數內部可用,外部仍通過變量名調用,適用于需要在函數內部遞歸、調試(函數名會顯示在調用棧中)的場景。

// 1. 聲明變量 calculate,賦值為一個“帶名字的函數”(函數名:multiply)
// 右側 function multiply(a, b){} 是命名函數,函數名 multiply 僅內部可用
var calculate = function multiply(a, b) {
  // 函數內部可通過函數名 multiply 訪問自身(用于遞歸)
  console.log("命名函數內部:函數名 =", multiply.name); // 輸出:命名函數內部:函數名 = multiply
  return a * b;
};
// 2. 外部調用:只能通過變量名 calculate 調用,無法直接用 multiply
console.log("外部調用命名函數表達式:", calculate(4, 6)); // 輸出:24
// console.log(multiply(4, 6)); // 報錯:multiply is not defined(外部無法訪問函數內部的名字)
// 3. 命名函數表達式的核心優(yōu)勢:內部遞歸更清晰(無需依賴 arguments.callee)
var fibonacci = function fib(n) {
  if (n <= 2) return 1;
  // 內部通過函數名 fib 遞歸,語義更清晰,避免 arguments.callee 的歧義
  return fib(n - 1) + fib(n - 2);
};
console.log("命名函數遞歸(斐波那契):", fibonacci(6)); // 輸出:8(1,1,2,3,5,8)

函數表達式的作用域訪問規(guī)則:內部與外部能否互相訪問?

函數表達式的 “內外訪問權限” 由 ES5 作用域規(guī)則決定:ES5 僅支持 “全局作用域” 和 “函數作用域”,無塊級作用域,訪問權限遵循 “內層可訪問外層,外層不可訪問內層” 的原則。

核心規(guī)則總結

訪問方向是否允許底層邏輯
函數內部訪問外部變量允許作用域鏈規(guī)則:內部作用域會向上遍歷外層作用域,直到找到變量或到達全局作用域。
函數外部訪問內部變量不允許函數作用域隔離:內部變量僅在函數內部生效,外部無訪問路徑。

語法與實例(匿名 / 命名兩種形式)

// 1. 匿名函數表達式:無函數名,賦值給變量
var calculateMultiply = function(a, b) {
  return a * b;
};
// 2. 命名函數表達式:函數名僅在內部可用(用于遞歸或調試)
var calculateDivide = function divide(a, b) {
  console.log(divide.name); // 輸出:divide(內部訪問函數名)
  if (b === 0) return "除數不能為0";
  return a / b;
};
// 關鍵特性:無函數提升(聲明前調用會報錯)
// console.log(calculateMultiply(4, 6)); // 報錯:calculateMultiply is not a function(若放在賦值前)
console.log(calculateMultiply(4, 6)); // 輸出:24(賦值后調用正常)
console.log(calculateDivide(10, 2)); // 輸出:5

兩種定義方式的核心差異

對比維度函數聲明函數表達式
提升支持支持(整體提升至作用域頂部)不支持(變量提升但值為 undefined)
函數名必須顯式定義可選(匿名 / 命名,命名僅內部可用)
適用場景獨立函數(如工具函數)賦值給變量、作為參數(如回調函數)

三、函數內部核心屬性:arguments 與 this

函數內部有兩個特殊屬性:arguments(處理參數)和 this(處理上下文),二者是實現靈活邏輯的關鍵。

3.1 arguments 對象:類數組的參數集合

定義與特性

arguments 是函數內部的類數組對象,存儲所有傳入的實參,支持:

  • 通過索引訪問參數(如 arguments[0] 獲取第一個實參);
  • length 屬性獲取實參個數;
  • callee 屬性指向當前函數(用于匿名函數遞歸)。

實踐實例

// 實例1:處理不確定個數的參數(求和)
function sum() {
  var total = 0;
  // 遍歷 arguments(類數組,需用 for 循環(huán),無 forEach 方法)
  for (var i = 0; i < arguments.length; i++) {
    // 過濾非數字參數(增強魯棒性)
    if (typeof arguments[i] === "number") {
      total += arguments[i];
    }
  }
  return total;
}
console.log(sum(1, 2, 3)); // 輸出:6
console.log(sum(10, 20, "a", 30)); // 輸出:60(忽略非數字參數)
// 實例2:arguments.callee 實現匿名函數遞歸(計算階乘)
var factorial = function(n) {
  if (n === 1) return 1;
  // callee 指向當前函數,避免依賴外部變量名
  return n * arguments.callee(n - 1);
};
console.log(factorial(5)); // 輸出:120(5! = 5*4*3*2*1)

3.2 this 綁定:動態(tài)上下文對象

定義與核心規(guī)則

this 是函數執(zhí)行時的 “上下文對象”,其指向由調用方式決定,與函數定義位置無關,ES5 中常見綁定場景如下:

實踐實例(4 種核心綁定場景)

// 場景1:全局調用 -> this 指向全局對象(瀏覽器:window,Node:global)
function getGlobalContext() {
  console.log(this === window); // 瀏覽器環(huán)境輸出:true
  console.log(this === global); // Node 環(huán)境輸出:true
}
getGlobalContext();
// 場景2:對象方法調用 -> this 指向調用對象
var user = {
  name: "張三",
  age: 25,
  introduce: function() {
    return `我是${this.name},今年${this.age}歲`;
  }
};
console.log(user.introduce()); // 輸出:我是張三,今年25歲
// 場景3:call/apply 強制綁定 -> this 指向指定對象
var anotherUser = { name: "李四", age: 30 };
// call:參數列表傳遞(逗號分隔)
console.log(user.introduce.call(anotherUser)); // 輸出:我是李四,今年30歲
// apply:參數數組傳遞
console.log(user.introduce.apply(anotherUser)); // 輸出:我是李四,今年30歲
// 場景4:bind 延遲綁定 -> 返回 this 綁定后的新函數
var boundIntroduce = user.introduce.bind(anotherUser);
setTimeout(boundIntroduce, 1000); // 1秒后輸出:我是李四,今年30歲

關鍵提醒

  • 避免在全局作用域濫用 this(易導致變量污染);
  • 函數作為回調時(如定時器、數組 forEach),this 默認指向全局對象(需通過 bind 手動綁定)。

四、立即執(zhí)行函數(IIFE):作用域隔離的核心工具

IIFE 的核心作用是 “創(chuàng)建獨立作用域,避免變量污染全局”,尤其適用于模塊化開發(fā)和循環(huán)變量隔離。

4.1 IIFE 語法與原理

核心語法(兩種常用形式)

// 形式1:外層括號包裹函數體 + 執(zhí)行括號(推薦,語義清晰)
(function(a, b) {
  console.log("IIFE 形式1:" + (a + b)); // 輸出:IIFE 形式1:15
})(10, 5);
// 形式2:函數體括號 + 執(zhí)行括號(省略外層括號,利用運算符優(yōu)先級)
(function(a, b) {
  console.log("IIFE 形式2:" + (a * b)); // 輸出:IIFE 形式2:50
}(25, 2));
// 簡化形式(利用一元運算符,如 !、+、-,省略外層括號)
!function(a) {
  console.log("IIFE 簡化形式:" + a); // 輸出:IIFE 簡化形式:8
}(8);

原理:為什么需要括號?

ES5 解析器會將以 function 開頭的語句視為 “函數聲明”,而函數聲明不能直接調用(需通過函數名)。通過括號包裹,可將其轉為 “函數表達式”,從而支持立即執(zhí)行。

4.2 IIFE 核心應用:解決循環(huán)變量污染

問題場景(未用 IIFE 的缺陷)

// 問題:循環(huán)中 var 聲明的變量共享,導致定時器輸出異常
for (var i = 0; i < 3; i++) {
  setTimeout(function() {
    console.log("未用 IIFE:" + i); // 輸出:3 3 3(循環(huán)結束后 i 已變?yōu)?3)
  }, 100);
}

解決方案(IIFE 隔離作用域)

// 方案:通過 IIFE 將每次迭代的 i 傳入獨立作用域
for (var i = 0; i < 3; i++) {
  (function(j) {
    // j 是 IIFE 的參數,每次迭代獨立保存 i 的當前值
    setTimeout(function() {
      console.log("用 IIFE:" + j); // 輸出:0 1 2(正常輸出每次迭代的 i)
    }, 100);
  })(i); // 將當前 i 作為實參傳入
}

五、閉包(Closure):函數與作用域的進階融合

閉包定義為 “有權訪問另一個函數作用域中變量的函數”,其本質是作用域鏈的延長保留,是 ES5 中實現 “狀態(tài)保存” 和 “模塊化” 的核心手段。

5.1 閉包的創(chuàng)建與底層原理

核心條件(滿足以下 3 點即形成閉包)

  1. 函數嵌套(內層函數嵌套在外層函數中);
  2. 內層函數引用外層函數的變量 / 參數;
  3. 外層函數返回內層函數(或內層函數被外部引用)。

實踐實例(計數器:閉包保存狀態(tài))

// 外層函數:定義局部變量 count
function createCounter() {
  var count = 0; // 被閉包引用的外層變量,不會被垃圾回收
  var step = 1; // 額外參數,演示多變量保存
  // 內層函數:引用 count 和 step,形成閉包
  return {
    increment: function() {
      count += step;
      return count;
    },
    setStep: function(newStep) {
      step = newStep; // 可通過閉包修改外層變量
    }
  };
}
// 調用外層函數,獲取閉包對象(保存 count 和 step 的狀態(tài))
var counter1 = createCounter();
var counter2 = createCounter(); // 獨立閉包,狀態(tài)不共享
// 操作 counter1
console.log(counter1.increment()); // 輸出:1(count=1,step=1)
counter1.setStep(2); // 修改 step 為 2
console.log(counter1.increment()); // 輸出:3(count=1+2=3)
// 操作 counter2(與 counter1 狀態(tài)獨立)
console.log(counter2.increment()); // 輸出:1(count=1,step=1)

原理補充:垃圾回收機制

正常情況下,函數執(zhí)行完后,其局部變量會被垃圾回收(釋放內存)。但閉包中,由于內層函數引用外層變量,外層函數的作用域會被保留,變量不會被回收,從而實現 “狀態(tài)持久化”。

5.2 閉包的核心應用場景

場景 1:實現私有變量(模塊化基礎)

// 模塊:通過閉包隱藏內部變量,僅暴露指定方法
var userModule = (function() {
  // 私有變量:僅內部可訪問,外部無法直接修改
  var privateName = "張三";
  var privateAge = 25;
  // 暴露的公共方法(閉包,引用私有變量)
  return {
    getName: function() {
      return privateName;
    },
    setAge: function(newAge) {
      // 可在方法中添加校驗邏輯,保證數據安全
      if (typeof newAge === "number" && newAge > 0) {
        privateAge = newAge;
      }
      return privateAge;
    },
    getInfo: function() {
      return `姓名:${privateName},年齡:${privateAge}`;
    }
  };
})();
// 外部訪問:只能通過暴露的方法操作,無法直接修改私有變量
console.log(userModule.getName()); // 輸出:張三
console.log(userModule.setAge(28)); // 輸出:28
console.log(userModule.getInfo()); // 輸出:姓名:張三,年齡:28
console.log(userModule.privateName); // 輸出:undefined(私有變量不可直接訪問)

場景 2:異步操作中的變量綁定

// 場景:異步請求中保留請求參數(如 AJAX 回調)
function fetchData(url) {
  // 模擬 AJAX 異步請求
  setTimeout(function() {
    // 閉包引用外層變量 url,即使 fetchData 執(zhí)行完,url 仍被保留
    console.log(`請求地址:${url},模擬返回數據成功`);
  }, 1000);
}
fetchData("https://api.example.com/user"); // 1秒后輸出:請求地址:https://api.example.com/user,模擬返回數據成功
fetchData("https://api.example.com/order"); // 1秒后輸出:請求地址:https://api.example.com/order,模擬返回數據成功

5.3 閉包的注意事項

  1. 內存占用問題:閉包會保留外層作用域,濫用可能導致內存泄漏(如 DOM 事件綁定后未解綁),建議不用時手動解除引用(如 counter = null);
  2. 變量共享問題:若閉包引用循環(huán)變量,需通過 IIFE 隔離(參考前文循環(huán)變量示例);
  3. this 指向問題:閉包中的 this 默認指向全局對象,需通過 bind 或變量保存(如 var self = this)。

六、函數調用的進階:回調函數與異步編程

 “函數可作為返回值或參數”,其中 “作為參數” 即回調函數,是 ES5 中實現異步編程的核心方式(如定時器、AJAX、事件綁定)。

6.1 回調函數的定義與分類

核心定義

回調函數是 “作為參數傳遞給另一個函數的函數”,在被調用函數執(zhí)行到特定時機時觸發(fā),分為同步回調異步回調。

實踐實例

// 1. 同步回調(立即執(zhí)行,如數組遍歷)
var numbers = [1, 2, 3, 4];
// forEach 的參數是同步回調,遍歷完成后立即執(zhí)行
numbers.forEach(function(item, index) {
  console.log(`索引${index}:${item * 2}`); // 輸出:索引0:2 索引1:4 索引2:6 索引3:8
});
// 2. 異步回調(延遲執(zhí)行,如定時器)
function loadData(callback) {
  console.log("開始加載數據...");
  // 模擬異步操作(如 AJAX 請求)
  setTimeout(function() {
    var data = { name: "李四", age: 30 };
    callback(data); // 異步完成后調用回調,傳遞數據
  }, 1500);
}
// 調用函數并傳入回調
loadData(function(result) {
  console.log("加載完成,數據:", result); // 1.5秒后輸出:加載完成,數據:{ name: '李四', age: 30 }
});
console.log("加載請求已發(fā)送(不阻塞后續(xù)代碼)"); // 先輸出:加載請求已發(fā)送(不阻塞后續(xù)代碼)

6.2 回調函數的常見應用

  • DOM 事件綁定:如 button.onclick = function() {};
  • AJAX 請求:如 XMLHttpRequest 的 onreadystatechange 事件;
  • 定時器:如 setTimeout、setInterval;
  • 工具函數:如 Array.prototype.map、filter、reduce。

七、補充:函數的其他關鍵細節(jié)

7.1 函數的 length 屬性

 “function.length 表示函數希望接受的命名參數個數”,即形參個數(不包含剩余參數)。

function add(a, b) {
  return a + b;
}
function multiply(a, b, c) {
  return a * b * c;
}
console.log(add.length); // 輸出:2(形參個數為 2)
console.log(multiply.length); // 輸出:3(形參個數為 3)

7.2 函數作為對象(Function 類型)

ES5 中函數是 Function 類型的實例,因此具有屬性和方法(如 name、call、apply、bind)。

function greet(name) {
  return `Hello, ${name}`;
}
console.log(greet instanceof Function); // 輸出:true(函數是 Function 實例)
console.log(greet.name); // 輸出:greet(函數名屬性)
console.log(greet.toString()); // 輸出函數的源代碼:function greet(name) { return `Hello, ${name}`; }

總結

ES5 函數的核心知識點可歸納為 “三大基礎 + 兩大進階”:

  1. 三大基礎:函數定義(聲明 / 表達式)、內部屬性(arguments/this)、調用方式(普通 / 方法 /call/apply/bind);
  2. 兩大進階:IIFE(作用域隔離)、閉包(狀態(tài)保存與模塊化)。

函數是 JavaScript 編程的 “基石”,掌握以上內容不僅能應對 ES5 環(huán)境的開發(fā)需求,也能為理解 ES6+ 的箭頭函數、解構賦值等特性奠定基礎。建議結合實例反復調試,重點突破 this 綁定和閉包的細節(jié)~

到此這篇關于JavaScript ES5 函數從基礎到高級應用全解析的文章就介紹到這了,更多相關JavaScript ES5 函數內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • JS將unicode碼轉中文方法

    JS將unicode碼轉中文方法

    本篇文章主要介紹了JS將unicode碼轉中文方法的相關知識,具有很好的參考價值。下面跟著小編一起來看下吧
    2017-05-05
  • 使用JSX 建立組件 Parser(解析器)開發(fā)的示例

    使用JSX 建立組件 Parser(解析器)開發(fā)的示例

    這篇文章主要介紹了使用JSX 建立組件 Parser(解析器)開發(fā)的示例(前端組件化)本文重點講述我們如何從0開始搭建一個組件系統(tǒng),基于標記語言的Parser的一種風格
    2021-04-04
  • JSQL 批量圖片切換的實現代碼

    JSQL 批量圖片切換的實現代碼

    其實這個example也很簡單, 就是根據where后的條件批量修改element的屬性,此處為Img元素
    2010-05-05
  • JScript實現地址選擇功能

    JScript實現地址選擇功能

    這篇文章主要為大家詳細介紹了JScript實現地址選擇功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • 用js實現簡單算法的實例代碼

    用js實現簡單算法的實例代碼

    下面小編就為大家?guī)硪黄胘s實現簡單算法的實例代碼。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-09-09
  • Layui table field初始化加載時進行隱藏的方法

    Layui table field初始化加載時進行隱藏的方法

    今天小編就為大家分享一篇Layui table field初始化加載時進行隱藏的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-09-09
  • js日期對象兼容性的處理方法

    js日期對象兼容性的處理方法

    本篇文章主要是對js日期對象兼容性的處理方法進行了詳細的介紹,需要的朋友可以過來參考下,希望對大家有所幫助
    2014-01-01
  • TypeScript基礎類型完全指南(附示例代碼)

    TypeScript基礎類型完全指南(附示例代碼)

    TypeScript是JavaScript的一個超集,支持ES6的標準,它擴展了JavaScript的語法,這篇文章主要介紹了TypeScript基礎類型完全指南的相關資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2025-11-11
  • 微信小程序實現通過js操作wxml的wxss屬性示例

    微信小程序實現通過js操作wxml的wxss屬性示例

    這篇文章主要介紹了微信小程序實現通過js操作wxml的wxss屬性,結合實例形式分析了微信小程序使用js操作wxml的wxss屬性相關原理、實現技巧與操作注意事項,需要的朋友可以參考下
    2018-12-12
  • JavaScript實現搜索高亮功能詳解

    JavaScript實現搜索高亮功能詳解

    這篇文章主要介紹了JavaScript實現搜索高亮功能,搜索功能是常見的需求之一,為了提升用戶體驗,我們可以通過高亮顯示搜索結果中的關鍵詞來幫助用戶快速定位信息,需要的朋友可以參考下
    2025-05-05

最新評論

辽宁省| 河曲县| 繁昌县| 墨玉县| 浑源县| 日土县| 郴州市| 景洪市| 雷山县| 清原| 中卫市| 文成县| 东明县| 拉萨市| 运城市| 阿城市| 板桥市| 镶黄旗| 始兴县| 冷水江市| 泾源县| 滨州市| 海盐县| 十堰市| 洛阳市| 上饶市| 朝阳市| 元江| 永登县| 韩城市| 德江县| 靖州| 融水| 云阳县| 社会| 旌德县| 叙永县| 渭源县| 五大连池市| 郓城县| 巫溪县|