4 种函数

1. 函数声明

function add(a, b) {
    return a + b;
}

特点:可以提升(hoisted)—— 声明之前就能调用。

2. 函数表达式

const add = function (a, b) {
    return a + b;
};

不提升,必须先声明再用

3. 箭头函数(最常用)

const add = (a, b) => a + b;
const square = x => x * x;
const greet = name => `Hello, ${name}`;

// 多行
const compute = (a, b) => {
    const sum = a + b;
    return sum * 2;
};

// 返回对象要包小括号
const make = name => ({ name, ts: Date.now() });

特点:

  • 没有自己的 this(继承外层)
  • 没有 arguments(用 ...args 替代)
  • 不能用作 constructor(new 它会报错)

4. 异步函数(async)

const fetchData = async (url) => {
    const r = await fetch(url);
    return r.json();
};

详见 15-async-await。

参数

默认值

function greet(name = 'World') {
    return `Hello, ${name}`;
}
greet();             // 'Hello, World'
greet('Alice');      // 'Hello, Alice'

Rest 参数

function sum(...nums) {
    return nums.reduce((a, b) => a + b, 0);
}
sum(1, 2, 3, 4);    // 10

解构参数

function makeUser({ name, age = 18, email }) {
    return { name, age, email };
}
makeUser({ name: 'alice', email: 'a@x.com' });

闭包:函数记住它的"出生环境"

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

const c = counter();
c();         // 1
c();         // 2
c();         // 3

每次调 counter() 返回的函数都独立保留自己的 count —— 这就是闭包。

实战:

// 私有计数器
const makeId = (() => {
    let id = 0;
    return () => ++id;
})();
makeId();    // 1
makeId();    // 2

// 防抖
function debounce(fn, ms) {
    let timer;
    return function (...args) {
        clearTimeout(timer);
        timer = setTimeout(() => fn(...args), ms);
    };
}

this 的麻烦

const obj = {
    name: 'Alice',
    sayHi() {
        console.log(`Hi, ${this.name}`);
    }
};

obj.sayHi();                              // Hi, Alice

const fn = obj.sayHi;
fn();                                      // Hi, undefined ❌(this 丢了)

// 绑定 this
const bound = obj.sayHi.bind(obj);
bound();                                   // Hi, Alice ✓

// 或用箭头函数避免 this 问题
const obj2 = {
    name: 'Bob',
    sayHi: () => console.log(`Hi, ${this.name}`)  // ❌ 箭头继承外层 this
};

几个绑定方法

fn.call(obj, arg1, arg2)                   // 立即调用,this = obj
fn.apply(obj, [arg1, arg2])                // 同上但参数数组
const bound = fn.bind(obj)                  // 返回新函数,永远 this = obj

箭头 vs 普通函数 this 速记

对象方法 → 用 method shorthand(function 风格)  ← 想要 this = 对象
回调函数 → 用箭头函数                            ← 继承外层 this

IIFE(立即执行)

(function () {
    // 内部代码立即跑
    const secret = 42;
})();

// 箭头版
(() => {
    // ...
})();

ES Module 时代用得少了——块级作用域 + 模块自然隔离。

函数也是值

const arr = [
    a => a * 2,
    a => a + 1,
    a => a ** 2,
];

arr.forEach(fn => console.log(fn(5)));
// 10
// 6
// 25

  • 箭头函数没有 this / arguments——用 ...args 替代 arguments
  • 闭包长期持有外层变量——大对象赋给闭包外层可能内存泄漏
  • this 在不同环境(class / 对象 / 普通函数 / 严格模式)规则不同——遇到问题先 console.log(this) 看一眼

下一篇:对象与类。