JavaScript函数核心知识详解

更新日期: 2025-10-21 阅读: 314 标签: 函数

JavaScript中的函数不仅仅是用来封装代码的,它们在语言中有着特殊的地位。理解函数的工作原理,是学好JavaScript的关键。


函数的定义方式

JavaScript提供了几种不同的函数定义方法:

第一种是函数声明:

function sayHello(name) {
  return `你好,${name}`;
}

这种方式的特点是存在提升效果,你可以在函数声明之前调用它。

第二种是函数表达式:

const sayHello = function(name) {
  return `你好,${name}`;
};

这种方式不会提升,必须在赋值之后才能使用。

第三种是箭头函数:

const sayHello = (name) => `你好,${name}`;

箭头函数写法简洁,没有自己的this值,也不能用作构造函数。

在实际开发中,函数声明适合用在模块的顶层,函数表达式和箭头函数适合在需要的时候直接使用。


函数参数的处理

JavaScript函数对参数个数要求很宽松,传入的参数可以和定义的参数个数不同。

function showInfo(name, age) {
  console.log(`${name},${age}岁`);
}

showInfo("张三");           // "张三,undefined岁"
showInfo("李四", 25, "额外参数"); // "李四,25岁"

如果参数不够,缺少的参数就是undefined。如果参数多了,多出来的会被忽略。

要处理不确定数量的参数,有两种方法:

传统的方式是使用arguments:

function addNumbers() {
  let sum = 0;
  for (let i = 0; i < arguments.length; i++) {
    sum += arguments[i];
  }
  return sum;
}

现在更推荐使用rest参数:

function addNumbers(...numbers) {
  return numbers.reduce((a, b) => a + b, 0);
}

rest参数会得到一个真正的数组,而且必须放在参数列表的最后。


作用域规则

作用域决定了变量在哪里可以被访问。

全局变量在任何地方都可以访问,局部变量只能在函数内部访问:

let globalVar = "全局变量";

function testScope() {
  let localVar = "局部变量";
  console.log(globalVar); // 可以访问
  console.log(localVar);  // 可以访问
}

testScope();
// console.log(localVar); // 这里会报错

关于块级作用域,var和let的表现不同:

if (true) {
  var a = 1;
  let b = 2;
}
console.log(a); // 1,var声明的变量会提升
// console.log(b); // 报错,let声明的变量只在块内有效

现在建议使用let和const来代替var,这样可以避免很多意想不到的问题。


闭包的理解和使用

闭包是指函数能够记住并访问它定义时的作用域,即使函数在其他地方执行。

function createCounter() {
  let count = 0;
  return function() {
    count++;
    return count;
  };
}

const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2

count变量被内部函数引用,所以不会被清除,形成了私有状态。

闭包在实际开发中很有用,比如用来封装数据

function createBankAccount(initialBalance) {
  let balance = initialBalance;
  return {
    deposit(amount) {
      balance += amount;
    },
    withdraw(amount) {
      if (amount <= balance) balance -= amount;
    },
    getBalance() {
      return balance;
    }
  };
}

const account = createBankAccount(1000);
account.deposit(500);
console.log(account.getBalance()); // 1500

外部代码无法直接修改balance,保证了数据安全。


this的关键知识点

this的值取决于函数如何被调用,而不是在哪里定义。

const obj = {
  name: "示例对象",
  normalMethod() {
    console.log(this.name);
  },
  arrowMethod: () => {
    console.log(this.name);
  }
};

obj.normalMethod(); // "示例对象"
obj.arrowMethod();   // undefined

普通函数的this指向调用它的对象,箭头函数的this继承自外层作用域。因此,对象的方法应该使用普通函数。


立即执行函数

立即执行函数可以创建独立的作用域,避免污染全局环境。

(function() {
  const privateVar = "私有变量";
  console.log("立即执行");
})();

(() => {
  console.log("箭头函数立即执行");
})();

在模块化规范普及之前,这是组织代码的常用方法。


高阶函数

函数可以作为参数传递,也可以作为返回值,这是函数作为"一等公民"的特性。

function processArray(arr, processor) {
  const result = [];
  for (const item of arr) {
    result.push(processor(item));
  }
  return result;
}

const numbers = [1, 2, 3];
const doubled = processArray(numbers, x => x * 2);
console.log(doubled); // [2, 4, 6]

数组的map、filter、reduce等方法都是基于这个原理。


实际应用:事件系统

结合闭包和高阶函数,我们可以实现一个简单的事件系统:

function createEventSystem() {
  const eventListeners = {};

  return {
    on(eventName, callback) {
      if (!eventListeners[eventName]) {
        eventListeners[eventName] = [];
      }
      eventListeners[eventName].push(callback);
    },
    emit(eventName, data) {
      if (eventListeners[eventName]) {
        eventListeners[eventName].forEach(callback => callback(data));
      }
    },
    off(eventName, callback) {
      if (eventListeners[eventName]) {
        eventListeners[eventName] = eventListeners[eventName]
          .filter(cb => cb !== callback);
      }
    }
  };
}

const eventBus = createEventSystem();
eventBus.on("message", data => console.log("收到:", data));
eventBus.emit("message", "你好世界");


常见问题和解决方法

循环中的闭包是个常见陷阱:

错误写法:

for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100); // 输出 3, 3, 3
}

正确写法:

// 使用let
for (let i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100); // 输出 0, 1, 2
}

// 或者使用立即执行函数
for (var i = 0; i < 3; i++) {
  ((j) => setTimeout(() => console.log(j), 100))(i);
}


开发建议

  • 优先使用const,避免意外修改变量

  • 简单的函数逻辑可以使用箭头函数

  • 对象的方法使用普通函数来确保this正确

  • 合理使用闭包,注意避免内存泄漏

  • 一个函数只做一件事,保持函数简洁

  • 给函数起有意义的名称

  • 控制函数的参数数量,太多参数可以考虑使用对象


学习要点总结

概念重点内容
函数定义声明会提升,表达式不会,箭头函数没有this
参数处理参数个数灵活,推荐使用rest参数
作用域let/const有块级作用域,var没有
闭包函数可以记住定义时的作用域
this指向普通函数动态绑定,箭头函数静态继承
高阶函数函数可以作为参数或返回值

理解这些核心概念,能够帮助你写出更好的JavaScript代码。函数是JavaScript中最重要的一部分,花时间深入学习是值得的。在实际项目中多练习这些知识点,你会逐渐掌握它们的精髓。

本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!

链接: https://fly63.com/article/detial/13026

相关推荐

JavaScript push() 方法详解

push() 方法主要用于向数组的末尾添加一个或多个元素,其返回值为添加后新的长度,即push后的数组长度,该值为number类型。介绍:一个数组中添加新元素、把一个数组的值赋值到另一个数组上、在对象使用push

什么是纯函数_以及为什么要用纯函数?

当我第一次听到 “纯函数 (Pure Function)” 这个术语的时候我很疑惑。常规的函数做错了什么?为什么要变纯? 为什么我需要纯的函数?除非你已经知道什么是纯函数,否则你可能会问同样的疑惑

让我们来创建一个JavaScript Wait函数

Async/await以及它底层promises的应用正在猛烈地冲击着JS的世界。在大多数客户端和JS服务端平台的支持下,回调编程已经成为过去的事情。当然,基于回调的编程很丑陋的。

什么是函数的副作用——理解js编程中函数的副作用

函数副作用是指当调用函数时,除了返回函数值之外,还对主调用函数产生附加的影响。副作用的函数不仅仅只是返回了一个值,而且还做了其他的事情

js中sort函数用法总结_sort排序算法原理

js中sort方法用于对数组的元素进行排序,并返回数组。默认排序顺序是根据字符串Unicode码点。如果要得到自己想要的结果,不管是升序还是降序,就需要提供比较函数了。该函数比较两个值的大小,然后返回一个用于说明这两个值的相对顺序的数字

javascript封装函数

使用函数有两步:1、定义函数,又叫声明函数, 封装函数。2、调用函数var 变量 = 函数名(实参);对函数的参数和返回值的理解

js中reduce()方法

reduce() 方法接收一个函数作为累加器,reduce 为数组中的每一个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素,接受四个参数:初始值(上一次回调的返回值),当前元素值,当前索引,原数组。

javascript回调函数的理解和使用方法(callback)

在js开发中,程序代码是从上而下一条线执行的,但有时候我们需要等待一个操作结束后,再进行下一步操作,这个时候就需要用到回调函数。 在js中,函数也是对象,确切地说:函数是用Function()构造函数创建的Function对象。

js调用函数的几种方法_ES5/ES6的函数调用方式

这篇文章主要介绍ES5中函数的4种调用,在ES5中函数内容的this指向和调用方法有关。以及ES6中函数的调用,使用箭头函数,其中箭头函数的this是和定义时有关和调用无关。

js构造函数

JS中的函数即可以是构造函数又可以当作普通函数来调用,当使用new来创建对象时,对应的函数就是构造函数,通过对象来调用时就是普通函数。在我们平时工作中,经常会需要我们创建一个对象,而我们更多的是使用对像直接量,直接创建

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!