文章目录
- 一.函数基础(定义与调用)
-
- [1.函数声明(Function Declaration)](#1.函数声明(Function Declaration))
- [2.函数表达式(Function Expression)](#2.函数表达式(Function Expression))
- [3.箭头函数(Arrow Function,ES6+)](#3.箭头函数(Arrow Function,ES6+))
- [4.构造函数(Function Constructor)](#4.构造函数(Function Constructor))
- 二.函数核心特性
-
- 1.参数与默认值
- [2.this 指向(关键!)](#2.this 指向(关键!))
- 3.闭包(Closure)
- 4.立即执行函数(IIFE)
- 三.高级用法
-
- [1.高阶函数(Higher-Order Function)](#1.高阶函数(Higher-Order Function))
- 2.函数柯里化(Currying)
- 3.函数防抖与节流(性能优化)
- 四.常见注意点
JavaScript 函数是代码复用、逻辑封装的核心机制,以下从 基础定义 、 调用方式 、 核心特性 、 高级用法 四个维度,系统讲解 JS 函数的核心知识点,附带实用示例:
一.函数基础(定义与调用)
函数的核心是「接收输入(参数)、执行逻辑、返回输出(返回值)」,JS 中定义函数有 4 种常用方式:
语法:
javascript
function name(params) {
return result;
}
1.函数声明(Function Declaration)
最传统的方式,存在变量提升(可在定义前调用).
javascript
// 语法:function 函数名(参数 1, 参数 2) { 函数体 }
function add(a, b) {
return a + b; // return 终止函数执行并返回结果(无 return 则返回 undefined)
}
// 调用:函数名(实参 1, 实参 2)
console.log(add(2, 3)); // 输出 5
console.log(add(1)); // 输出 NaN(b 未传值,默认为 undefined,1 + undefined = NaN)
2.函数表达式(Function Expression)
将函数赋值给变量,不存在变量提升(定义前调用会报错),可匿名或命名.
javascript
// 匿名函数表达式
const multiply = function(a, b) {
return a * b;
};
// 命名函数表达式(函数名仅在函数内部可用)
const divide = function calc(a, b) {
if (b === 0) throw new Error('除数不能为 0');
return a / b;
};
console.log(multiply(4, 5)); // 输出 20
console.log(divide(10, 2)); // 输出 5
// console.log(calc(10,2)); // 报错:calc is not defined(外部不可用)
3.箭头函数(Arrow Function,ES6+)
简洁语法,无自己的 this、arguments、prototype,不能作为构造函数.
javascript
// 语法:(参数 1, 参数 2) => { 函数体 } (单参数可省略括号,单语句返回可省略大括号和 return)
const subtract = (a, b) => a - b; // 简化写法(等价于 { return a - b; })
const double = (num) => num * 2; // 单参数省略括号
const greet = () => console.log('Hello!'); // 无参数需写空括号
console.log(subtract(10, 3)); // 输出 7
console.log(double(6)); // 输出 12
greet(); // 输出 Hello!
4.构造函数(Function Constructor)
不推荐日常使用(可读性差、易引发安全问题),了解即可:
javascript
const power = new Function('base', 'exponent', 'return base ** exponent');
console.log(power(2, 3)); // 输出 8
二.函数核心特性
1.参数与默认值
JS 函数参数灵活,支持 默认值、剩余参数、解构参数:
javascript
// 1.默认参数(ES6+):实参未传时使用默认值
function greet(name = 'Guest') {
return `Hello, ${name}!`;
}
console.log(greet()); // 输出 Hello, Guest!
console.log(greet('Alice')); // 输出 Hello, Alice!
// 2.剩余参数(...rest):接收多个实参并转为数组(必须在参数列表最后)
function sum(...nums) {
return nums.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3, 4)); // 输出 10
// 3.解构参数:直接解构对象/数组作为参数
function getUserInfo({ name, age }) {
return `姓名:${name},年龄:${age}`;
}
const user = { name: 'Bob', age: 25 };
console.log(getUserInfo(user)); // 输出 姓名:Bob,年龄:25
2.this 指向(关键!)
this 是函数执行时的「上下文对象」,指向由 调用方式 决定(箭头函数无独立 this):
| 调用方式 | this 指向 | 示例 |
|---|---|---|
普通函数调用(func ()) |
全局对象(浏览器:window,Node:global) |
function foo(){console.log(this); } foo(); // window |
对象方法调用(obj.func ()) |
调用该方法的对象 | const obj = { name: "A", say(){console.log(this.name); } }; obj.say(); // "A" |
构造函数调用(new Func ()) |
新创建的实例对象 | function Person(name) { this.name = name; } const p = new Person("C"); console.log(p.name); // "C" |
apply/call/bind 调用 |
手动指定的对象 | function bar() { console.log(this.x); } bar.call({ x: 10 }); // 10 |
箭头函数的 this:
继承自外层「非箭头函数」的 this,且永久绑定(无法通过 apply/call/bind 修改):
javascript
const obj = {
name: 'D',
normalFunc: function() {
const arrowFunc = () => console.log(this.name); // this 继承自 normalFunc 的 this(即 obj)
arrowFunc();
}
};
obj.normalFunc(); // 输出 "D"
3.闭包(Closure)
核心定义:函数嵌套时,内层函数引用外层函数的变量 / 参数,且内层函数被外部访问,导致外层函数的作用域不会被销毁.用途:封装私有变量、实现数据缓存、模块化.
示例: 实现计数器(私有变量 count 无法被外部直接修改):
javascript
function createCounter() {
let count = 0; // 外层函数变量,被内层函数引用
return function() {
count++; // 内层函数访问外层变量
return count;
};
}
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(count); // 报错:count is not defined(外部无法访问)
4.立即执行函数(IIFE)
定义后立即执行,用于隔离作用域(避免变量污染全局),ES6 后可被 let/const 块级作用域替代,但仍有兼容场景使用:
javascript
// 语法 1:(函数)()
(function(a, b) {
console.log(a + b); // 输出 5
})(2, 3);
// 语法 2:函数()()
(function(a, b) {
console.log(a * b); // 输出 12
})(4, 3);
三.高级用法
1.高阶函数(Higher-Order Function)
接收函数作为参数,或返回函数的函数(JS 数组方法如 map、filter、reduce 都是高阶函数):
javascript
// 示例 1:接收函数作为参数
function processArray(arr, handler) {
const result = [];
for (const item of arr) {
result.push(handler(item)); // 执行传入的处理函数
}
return result;
}
const numbers = [1, 2, 3];
const doubled = processArray(numbers, (num) => num * 2); // 传入箭头函数
console.log(doubled); // [2,4,6]
// 示例 2:返回函数
function makeMultiplier(factor) {
return function(num) {
// 返回函数
return num * factor;
};
}
const multiplyBy3 = makeMultiplier(3);
console.log(multiplyBy3(5)); // 15
2.函数柯里化(Currying)
将多参数函数转为「单参数函数链」,逐步接收参数并返回新函数,直到参数齐全后执行:
javascript
// 柯里化函数:sum(a, b, c) → sum(a)(b)(c)
function currySum(a) {
return function(b) {
return function(c) {
return a + b + c;
};
};
}
console.log(currySum(1)(2)(3)); // 6
// 箭头函数简化柯里化
const curryMultiply = (a) => (b) => (c) => a * b * c;
console.log(curryMultiply(2)(3)(4)); // 24
3.函数防抖与节流(性能优化)
- 防抖(Debounce): 触发后延迟 n 秒执行,若 n 秒内再次触发则重新计时(适用于输入框搜索、窗口 resize).
- 节流(Throttle): 触发后立即执行,然后 n 秒内不响应后续触发(适用于滚动事件、按钮点击防重复提交).
示例实现:
javascript
// 防抖
function debounce(fn, delay = 500) {
let timer = null;
return function(...args) {
clearTimeout(timer); // 清除之前的定时器
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
// 节流
function throttle(fn, interval = 500) {
let lastTime = 0;
return function(...args) {
const now = Date.now();
if (now - lastTime >= interval) {
// 间隔满足则执行
fn.apply(this, args);
lastTime = now;
}
};
}
// 用法:输入框搜索防抖
const searchInput = document.getElementById('search');
searchInput.addEventListener(
'input',
debounce(function(e) {
console.log('搜索:', e.target.value);
}, 300)
);
四.常见注意点
- 参数个数不匹配:实参多于形参时,多余参数可通过
arguments(类数组)或剩余参数获取;实参少于形参时,未传参数默认为undefined. - 箭头函数的限制:不能作为构造函数(
new会报错)、无prototype、无arguments对象(需用剩余参数替代). - 闭包内存泄漏:若闭包引用的变量过大且长期不释放,可能导致内存泄漏,需及时解除引用(如 counter = null).
- this 丢失问题:对象方法赋值给变量后调用,this 会指向全局(可通过 bind 或箭头函数解决):
javascript
const obj = {
name: 'E',
say() {
console.log(this.name);
}
};
const say = obj.say;
say(); // 输出 undefined(this 指向 window)
const boundSay = obj.say.bind(obj);
boundSay(); // 输出 "E"(bind 绑定 this)