文章目录
一、函数简介
1、函数的定义方式
JavaScript 提供了多种方式来定义函数:
1.1、函数声明
这是最常见的定义方式,使用
function
关键字,并给函数一个名字。
function sayHello(name) {
return "Hello, " + name;
}
函数声明具有函数提升特性,可以在定义之前调用。
1.2、函数表达式
函数可以作为表达式赋值给变量。
const sayHello = function(name) {
return `Hello, ${name}`;
};
这种方式不会被提前提升,只能在定义之后调用。
1.3、箭头函数(ES6 新增)
箭头函数提供了一种更加简洁的语法来编写函数表达式,并引入了不同的
this
绑定规则。箭头函数的基本语法相对简单,但根据是否只有一个参数、是否只有一行代码返回值等条件,其形式会有所变化:
- 单个参数:当函数仅接受一个参数时,可以省略圆括号。
const greet = name => `Hello, ${name}`; console.log(greet('Alice')); // 输出: Hello, Alice
- 多个参数:当有多个参数时,需要用圆括号包围它们。
const add = (a, b) => a + b; console.log(add(2, 3)); // 输出: 5
- 无参数:如果函数不需要任何参数,则使用一对空的圆括号。
const sayHello = () => "Hello!"; console.log(sayHello()); // 输出: Hello!
- 多行语句:如果函数体包含多条语句,则需要使用花括号
{}
包围,并且需要显式地使用return
来返回结果。const multiply = (x, y) => { let result = x * y; return result; }; console.log(multiply(4, 5)); // 输出: 20
2、函数参数
2.1、参数传递
JavaScript 函数可以接受任意数量的参数,即使定义时没有指定或传入的参数比定义多/少也没问题。
function add(a, b) {
return a + b;
}
console.log(add(2)); // 输出:NaN(b 是 undefined)
console.log(add(2, 3)); // 输出:5
console.log(add(1, 2, 3)); // 输出:3(忽略第三个参数)
2.2、默认参数
ES6 支持为参数设置默认值:
function greet(name = "Guest") {
console.log("Hello, " + name);
}
greet(); // Hello, Guest
greet("Alice"); // Hello, Alice
使用默认参数,要注意的问题
- 默认参数应该放在参数列表的最后。
- 如果非默认参数放在默认参数后面,调用时仍需传递值或使用
undefined
// 正确
function greet(name = 'Guest', message = 'Hello') {}
// 有问题 - 调用时必须提供第一个参数才能设置第二个
function problem(message = 'Hello', name) {}
2.3、剩余参数
剩余参数是 ES6 引入的语法,用于表示函数的不定数量参数,将多个参数收集到一个数组中。
-
基础语法:
function sum(...numbers) { // numbers 是一个真正的数组 return numbers.reduce((acc, num) => acc + num, 0); } console.log(sum(1, 2, 3)); // 6
-
核心特点:
- 必须是最后一个参数:
function(a, b, ...rest) {} // ✅ 正确 function(...rest, a) {} // ❌ 错误
- 获取剩余所有参数:
function logArgs(a, ...rest) { console.log(a); // 第一个参数 console.log(rest); // 剩余所有参数组成的数组 }
- 必须是最后一个参数:
-
与
arguments
的区别:特性 剩余参数 arguments
对象类型 真正的数组 类数组对象 包含所有参数? 只包含剩余参数 包含所有参数 箭头函数 可用 不可用 方法支持 可使用所有数组方法 需转换才能用数组方法
剩余参数让参数处理更直观、更符合现代 JavaScript 的数组操作习惯。
3、函数的作用域
3.1、作用域
JavaScript 使用词法作用域(Lexical Scope),函数内部可以访问外部作用域中的变量,但外部不能访问函数内部定义的变量。
let outerVar = "I'm outside";
function testScope() {
let innerVar = "I'm inside";
console.log(outerVar); // 可以访问
console.log(innerVar); // 正常输出
}
testScope();
console.log(outerVar); // 正常输出
console.log(innerVar); // 报错:innerVar is not defined
3.2、闭包
闭包是指能够访问其他函数内部变量的函数,或者说是一个函数和其周围状态(词法环境)的引用捆绑在一起形成的组合。简单说:当一个内部函数访问了外部函数的变量时,就形成了闭包。
function outer() {
let count = 0;
return function() {
count++;
console.log(count);
};
}
const counter = outer();
counter(); // 1
counter(); // 2
counter(); // 3
4、构造函数与类
JavaScript 支持通过函数创建对象实例,这类函数称为构造函数。
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayHi = function() {
console.log(`Hi, I'm ${this.name}`);
};
const p1 = new Person("Lucy", 25);
p1.sayHi(); // Hi, I'm Lucy
ES6 引入了
class
语法糖,使面向对象编程更加直观:
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayHi() {
console.log(`Hi, I'm ${this.name}`);
}
}
const p2 = new Person("Mike", 30);
p2.sayHi(); // Hi, I'm Mike
5、函数属性
JavaScript 函数除了是可执行代码块外,本身也是对象,因此可以拥有属性。以下是函数属性的核心要点:
5.1、内置函数属性
- name 属性:返回函数名
function foo() {} console.log(foo.name); // "foo"
- length 属性:返回函数声明的参数个数
function bar(a, b) {} console.log(bar.length); // 2
- prototype 属性:构造函数特有的属性,用于实现继承
function Person() {} Person.prototype.say = function() {}
5.2、自定义函数属性
函数可以像普通对象一样添加自定义属性:
function counter() {
counter.count = (counter.count || 0) + 1;
return counter.count;
}
console.log(counter()); // 1
console.log(counter()); // 2