当前位置: 首页 > news >正文

JavaScript 函数详解:从基础概念到实战应用

在 JavaScript 的世界里,函数扮演着至关重要的角色。它就像是一个 “瑞士军刀”,无论是实现复杂的业务逻辑,还是优化代码结构,都离不开函数的强大功能。接下来,让我们深入了解 JavaScript 函数的方方面面。

一、函数的概念​

函数,本质上是一段可重复调用的代码块,就像是一个精心打造的工具箱,随时准备为我们处理各种编程任务。它可以接收输入参数,并根据这些参数进行处理,最终返回输出结果。​

在 JavaScript 中,函数享有 “一等公民” 的特殊地位。这意味着函数可以像普通数据类型(如数字、字符串)一样,自由地进行传递、返回和赋值操作。例如,我们可以将一个函数作为参数传递给另一个函数,或者将函数赋值给一个变量,这种灵活性为编程带来了无限可能。

// 将函数赋值给变量
const sayHello = function() {console.log("Hello!");
};
sayHello(); // 输出:Hello!// 函数作为参数传递
function executeFunction(func) {func();
}
executeFunction(sayHello); // 输出:Hello!

二、函数的声明与调用

在 JavaScript 中,函数有多种声明方式,每种方式都有其独特的特点和适用场景。

函数的三种声明方式的语法和示例:

①普通函数:function 函数名(参数) { 代码段}

这是最常见的函数声明方式,使用function关键字,语法如下:

// ①普通函数:function 函数名(参数) { 代码段}
function add(num1,num2){return num1+num2;
}
let result = add(1,2);
console.log(result);

函数声明具有 “函数提升”(先调用,再声明) 的特性,即函数声明会被提升到其所在作用域的顶部,因此可以在声明之前调用函数。
②匿名函数:const 函数名 = function(参数) { 代码段}

函数表达式是将函数赋值给一个变量,语法如下:

// ②匿名函数:const 函数名 = function(参数) { 代码段}
const subtract = function(num1,num2){return num1-num2;
}
let result1 = subtract(10,2);
console.log(result1);

 

与函数声明不同,函数表达式不存在函数提升,必须先声明变量再调用函数。

③箭头函数:const 函数名 = (参数) => 代码段;

箭头函数是 ES6 引入的新特性,它提供了一种更简洁的函数定义方式,语法如下:

// ③箭头函数:const 函数名 = (参数) => 代码段;
const multiply = (num1,num2) => num1*num2;
const result2 = multiply(10,2);
console.log(result2);

三、函数的参数与返回值

1. 参数:函数的 “输入接口”

  • 形参与实参:

①形参(Formal Parameters):定义函数时声明的变量,用于接收调用时传入的值。 作用是作为函数内部的局部变量,用于处理逻辑。

②实参(Actual Parameters: 调用函数时传入的具体值,可以是常量、变量、表达式或函数返回值。 实参的值会被赋给对应的形参。

  • 默认参数(Default Parameters)

为形参提供默认值,若未传入实参,则使用默认值(建议放在参数的最后)。

// sex为默认参数,不传入参数默认为男,传入参数则为参数值
const person = (name,age,id,sex = "男")=>{console.log(`名字:${name},年龄:${age},学号:${id},性别:${sex}`)
}
person("小宁","21","123")
person("小妹","21","321","女")
  • 特殊参数对象(arguments)

arguments 是一个类数组对象(有数组的索引,但是没有数组的相关方法),包含函数调用时传入的所有实参。适用于不确定参数数量的场景。

function print(name, age , sex='男') {console.log(`name:${arguments[0]},age:${arguments[1]},sex:${arguments[3]}`)
}
print('张三',18,'女')

  • 剩余参数

使用...语法可以将多个实参收集为一个数组,方便处理不定数量的参数。

示例1:

// 剩余参数要放在最后function processUser(name, ...hobbies) {console.log(`Name: ${name}`);console.log(`Hobbies: ${hobbies.join(', ')}`);}processUser("Alice", "Reading", "Traveling");

 示例2:

function sumAll(...numbers){return numbers.reduce((acc,num)=>acc+num,0);
}
const total = sumAll(1,2,3,4,5,6,7,8,9,10);
console.log(total);

2. 返回值:函数的 “输出结果”

四、函数的作用域

作用域决定了变量和函数的可访问范围,在 JavaScript 中,主要有以下几种作用域:

1. 全局作用域

在函数外部定义的变量具有全局作用域,可以在整个程序中访问。但过度使用全局作用域可能导致命名冲突和代码难以维护,因此应尽量避免。

const globalVariable = "I'm global";
function printGlobal() {console.log(globalVariable);
}
printGlobal(); // 输出:I'm global

 

2. 函数作用域

在函数内部定义的变量具有函数作用域,只能在该函数内访问。使用var声明的变量存在 “变量提升” 现象,这可能会带来一些意外的结果。

function outerFunction() {var localVar = "I'm local";console.log(localVar);
}
outerFunction(); // 输出:I'm local
// console.log(localVar); // 报错,localVar在函数外部不可访问

3. 块级作用域

ES6 引入的let和const声明的变量具有块级作用域,只在{}内有效,常用于if、for、while等代码块中。

if (true) {let blockVariable = "I'm in block";console.log(blockVariable); // 输出:I'm in block
}
// console.log(bl

五、函数的高级应用

1. 闭包

闭包的概念:

当我们函数调用之后,每次函数调用之后,都会清除函数中的数据,但是如果我们闭包是指 一个函数能够访问并记住其词法作用域(lexical scope),即使该函数在其作用域外执行。换句话说:当内部函数被返回到外部作用域并被调用时,它仍然可以访问定义时所在作用域中的变量。

示例代码:

function outer(){var count = 0function inner(){count++console.log(count)}return inner
}
let acc = outer()
acc()  // 1
acc()  // 2
acc()  // 3

 

作用与优势:

作用描述
状态保持可以在函数外部保留函数内部的状态(如计数器、缓存等)
数据封装实现私有变量,避免全局污染
延迟执行在异步操作或事件处理中保持上下文

2.柯里化

柯里化概念:

柯里化是将一个多参数函数转换为一系列单参数函数的过程,它可以提高函数的复用性和灵活性。

案例:

// 普通的写法:
function add(a, b) {return a + b;
}// 柯里化后:
function curriedAdd(a) {return function(b) {return a + b;}
}console.log(curriedAdd(1)(2)); // 3

柯里化优点:

1.复用性:通过固定一部分参数,生成新的函数,提高代码的复用性。
2.可读性:使函数逻辑更清晰,便于理解和维护。
3.延迟执行:可以分步骤传递参数,直到所有参数都满足后才执行最终操作。

六、综合案例:打造一个简易的任务管理系统​

为了更好地展示 JavaScript 函数的实际应用,我们来实现一个简易的任务管理系统,具备添加任务、显示任务列表、标记任务为完成等功能。

// 存储任务的数组
const tasks = [];// 添加任务的函数
function addTask(task) {tasks.push({id:tasks.length+1,name:task,completed:false});
}// 显示任务列表的函数
function displayTasks(){tasks.forEach(task=>{const status = task.completed ? "已完成" : "未完成"console.log(`任务名:${task.name},任务id:${task.id},任务状态:${status}`)})
}// 标记任务为完成的函数
function completeTask(taskId){const task = tasks.find(task => task.id === taskId)  //找到就返回该对象;没找到返回 undefined,没有找到返回undefinedif(task){task.completed = true;}
}// 添加任务
addTask("学习JavaScript函数");
addTask("完成项目文档");
addTask("锻炼身体");
// 显示任务列表
displayTasks();// 标记任务为完成
completeTask(1);// 再次显示任务列表
displayTasks();

相关文章:

  • nginx配置中有无‘‘/’’的区别
  • antd-vue - - - - - a-table排序
  • 端到端自动驾驶研究:通过强化学习与世界模型的协同作用向VLA范式演进
  • Android OpenSL ES 音频播放完整实现指南
  • MySQL:InnoDB架构(内存架构篇)
  • 384_C++_unit是4字节大小,能存储32位(bit)bool操作,[7][48]这里用于计划表的时间节点内,二维数组中每一位代表一种AI功能的开关状态
  • 维度建模是什么意思?如何实现维度建模?
  • CPU Idle 状态与中断的关系
  • LocalDate类使用
  • 卷积神经网络参数量计算
  • Linux 阻塞非阻塞
  • Prometheus + Grafana 监控 RabbitMQ 实践指南
  • 【解决串口数据丢包问题】下位机环形缓冲区+上位机串口生产者-消费者不定长接收(基于keil5和Labview)
  • 【单片机期末】接口及应用
  • 中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
  • Linux简单的操作
  • 【51单片机】5. 矩阵键盘与矩阵键盘密码锁Demo
  • 驭码CodeRider 2.0深度测评:助力高效开发【探索化学奇妙世界】网站
  • K8s简述
  • 探秘鸿蒙 HarmonyOS NEXT:鸿蒙定时器,简单倒计时的场景应用
  • 有哪些做网站的/千锋教育北京校区
  • 百度快照网站/2019年 2022疫情爆发
  • 做网站标题头像/石家庄最新消息
  • 做商城网站在哪里注册营业执照/广州seo学徒
  • 网站关键词多长/衡阳seo排名
  • 网站图片延时加载/今天刚刚发生的重大新闻