在 JavaScript 中,函数作为一种重要的基本结构,承载着编程中的许多关键概念。下面是与函数相关的内容介绍:
1. 函数定义
JavaScript 中有多种方式定义函数:
1.1 函数声明(Function Declaration)
function add(a, b) {
return a + b;
}
console.log(add(2, 3)); // 输出: 5
1.2 函数表达式(Function Expression)
const multiply = function(a, b) {
return a * b;
};
console.log(multiply(4, 5)); // 输出: 20
1.3 箭头函数(Arrow Function)
const subtract = (a, b) => {
return a - b;
};
console.log(subtract(10, 7)); // 输出: 3
// 简写形式(若只有一条语句和一个参数)
const square = x => x * x;
console.log(square(6)); // 输出: 36
1.4 命名函数表达式(Named Function Expression)
const divide = function division(a, b) {
if (b === 0) {
return '不能除以零';
}
return a / b;
};
console.log(divide(10, 2)); // 输出: 5
console.log(divide(10, 0)); // 输出: '不能除以零'
1.5 立即调用函数表达式(IIFE, Immediately Invoked Function Expression)
(function() {
const message = 'Hello, World!';
console.log(message);
})(); // 输出: 'Hello, World!'
1.6 使用参数默认值的箭头函数
const greet = (name = '陌生人') => {
return `你好, ${name}!`;
};
console.log(greet('小明')); // 输出: '你好, 小明!'
console.log(greet()); // 输出: '你好, 陌生人!'
1.7 具名的IIFE
(function greet() {
console.log('Hello, IIFE!');
})(); // 输出: 'Hello, IIFE!'
1.8 Function 构造函数
const myFunction = new Function(arg1, arg2, ..., "functionBody");
arg1, arg2, ...
是参数的名称(作为字符串)。"functionBody"
是一个字符串,包含了函数的主体。
以下是一个使用 Function
构造函数的示例:
// 创建一个简单的加法函数
const add = new Function('a', 'b', 'return a + b;');
console.log(add(2, 3)); // 输出: 5
2. 函数属性
2.1 内置属性
- length: 表示函数定义时的参数个数。
function example(a, b) {}
console.log(example.length); // 输出: 2
- name: 返回函数的名称。
function example() {}
console.log(example.name); // 输出: "example"
2.2 自定义属性
你可以为函数添加自定义属性,就像对待普通对象一样。例如:
function myFunction() {
return "Hello";
}
myFunction.description = "这是一个简单的函数";
console.log(myFunction.description); // 输出: "这是一个简单的函数"
2.3 prototype
属性(重要!!!)
在 JavaScript 中,每个函数都有一个 prototype
属性。这个属性是一个对象,用以存放可以被该函数的实例共享的属性和方法。
下面是一个简单的示例,展示如何利用 prototype
属性来为构造函数添加方法:
function Person(name, age) {
this.name = name;
this.age = age;
}
// 添加方法到 Person 的原型
Person.prototype.introduce = function() {
console.log(`大家好,我是 ${this.name},我 ${this.age} 岁。`); // 输出: "大家好,我是 LuQian,我 18 岁。"
};
const alice = new Person("LuQian", 18);
alice.introduce();
示例代码解析:
2.3.1 构造函数定义
function Person(name, age) {
this.name = name;
this.age = age;
}
- 这是一个构造函数
Person
,用于创建Person
类型的对象。 name
和age
是参数,用于初始化对象的属性。- 在函数体内,使用
this.name
和this.age
将参数值赋给当前对象的name
和age
属性。
2.3.2 添加方法到原型
Person.prototype.introduce = function() {
console.log(`大家好,我是 ${this.name},我 ${this.age} 岁。`);
};
- 通过
Person.prototype
为Person
类型的对象添加一个方法introduce
。 - 这个方法使用模板字符串(反引号)来格式化消息,打印出当前对象的名称和年龄。
- 在这个方法中,
this
关键字指向调用该方法的实例对象。
2.3.3 创建实例
const alice = new Person("LuQian", 18);
- 使用
new
操作符调用Person
构造函数,创建一个名为alice
的新实例。 - 传入参数
"LuQian"
和18
,因此LuQian.name
将被赋值为"LuQian"
,LuQian.age
将被赋值为30
。
2.3.4 调用 introduce
方法
alice.introduce(); // 输出: "大家好,我是 LuQian,我 18 岁。"
- 在
alice
对象上调用introduce
方法。 - 该方法打印出一个消息,内容包括
alice
的名字和年龄,输出结果为"大家好,我是 LuQian,我 18 岁。"
3. 函数的调用方法
3.1 直接调用
直接通过函数名调用函数:
function sayHello() {
console.log("Hello!");
}
sayHello(); // 输出: Hello!
3.2 方法调用
如果函数是对象的方法,则通过对象来调用:
const person = {
name: "LuQian",
greet: function() {
console.log("Hello, " + this.name);
}
};
person.greet(); // 输出: Hello, LuQian
3.3 构造函数调用
使用 new
关键字调用函数,通常用于创建对象:
function Person(name) {
this.name = name;
}
const LuQian= new Person("LuQian");
console.log(LuQian.name); // 输出: LuQian
3.4 使用 call
和 apply
通过 call
和 apply
方法可以改变函数的上下文(this
):
function greet() {
console.log("Hello, " + this.name);
}
const person = {
name: "LuQian"
};
greet.call(person); // 输出: Hello, LuQian
greet.apply(person); // 输出: Hello, LuQian
3.5 使用 bind
bind
方法创建一个函数,该函数在调用时会将 this
关键字指定为特定值:
function greet() {
console.log("Hello, " + this.name);
}
const person = {
name: "LuQian"
};
const greetLuQian = greet.bind(person);
greetLuQian(); // 输出: Hello, LuQian
3.6 箭头函数
箭头函数也是一种定义函数的方式,但它的 this
值在定义时决定,不会发生变化:
const person = {
name: "LuQian",
greet: () => {
console.log("Hello, " + this.name); // this 指向外部上下文
}
};
person.greet(); // 输出: Hello, undefined
箭头函数不绑定自己的 this
,而是继承外部上下文的 this
。在这个例子中,this
指向的是 greet
方法被调用时的上下文,而不是 person
对象,因此 this.name
返回 undefined
。
要解决这个问题,可以使用普通函数来定义 greet
方法,这样 this
就会指向调用该方法的对象 person
。您可以将代码修改如下:
const person = {
name: "LuQian",
greet: function() { // 使用普通函数
console.log("Hello, " + this.name); // this 指向 person 对象
}
};
person.greet(); // 输出: Hello, LuQian
3.7 IIFE(立即调用的函数表达式)
一种在定义时立即执行函数的方法:
(function() {
console.log("This function runs immediately!");
})(); // 输出: This function runs immediately!
4. 函数的返回值
在 JavaScript 中,函数的返回值是通过 return
语句返回的。一个函数可以返回任意类型的值,包括基本类型(如数字、字符串、布尔值等)和复杂类型(如对象、数组、函数等)。如果没有使用 return
语句,或者在函数执行完时未遇到 return
,则函数默认返回 undefined
。
4.1 返回数字
function add(a, b) {
return a + b;
}
const sum = add(2, 3); // sum 的值是 5
4.2 返回字符串
function greet(name) {
return "Hello, " + name + "!";
}
const message = greet("Alice"); // message 的值是 "Hello, Alice!"
4.3 返回布尔值
function isEven(num) {
return num % 2 === 0;
}
const result = isEven(4); // result 的值是 true
4.4 返回对象
function createPerson(name, age) {
return {
name: name,
age: age
};
}
const person = createPerson("Bob", 25); // person 的值是 { name: "Bob", age: 25 }
4.5 没有返回值
function logMessage(message) {
console.log(message);
// 没有 return 语句,默认返回 undefined
}
const result = logMessage("Hello!"); // result 的值是 undefined
函数返回值总结 |
---|
使用 return 关键字来返回值。 |
函数可以返回任何类型的值,包括对象和数组。 |
如果没有 return 语句,函数会返回 undefined 。 |
5 函数参数
5.1 形参和实参
-
形参(Formal Parameters):在函数定义中声明的变量,起到占位符的作用。函数在调用时,用实参给这些形参赋值。
function foo(x, y) { return x + y; }
-
实参(Actual Parameters):在函数调用时传递给函数的值。可以是字面量、变量、表达式、对象等。
let result = foo(5, 10); // 5 和 10 是实参
5.2 默认参数
默认参数允许为函数参数提供默认值。可以在函数参数中直接指定默认值,如果调用时没有传递该参数,则使用默认值。
function greet(name = "Guest") {
console.log(`Hello, ${name}!`);
}
greet(); // 输出:Hello, Guest!
greet("LuQian"); // 输出:Hello, LuQian!
5.3 剩余参数
剩余参数 (...args
) 可以收集函数调用时传入的多余参数,并将这些参数作为数组处理。这在处理不定数量的参数时非常有效。
function sum(...numbers) {
return numbers.reduce((acc, curr) => acc + curr, 0);
}
console.log(sum(1, 2, 3, 4)); // 输出:10
console.log(sum(5, 10)); // 输出:15
5.4 参数解构
解构赋值允许我们从数组或对象中提取值,并将其赋值给变量,在函数参数中也可以使用这种语法。
5.4.1 对象解构
function displayUser({ name, age }) {
console.log(`Name: ${name}, Age: ${age}`);
}
const user = { name: "Bob", age: 30 };
displayUser(user); // 输出:Name: Bob, Age: 30
5.4.2 数组解构
function printCoordinates([x, y]) {
console.log(`X: ${x}, Y: ${y}`);
}
const coordinates = [10, 20];
printCoordinates(coordinates); // 输出:X: 10, Y: 20
5.5 参数顺序和数量
JavaScript 函数可以接受比定义的形参数量更多或更少的实参:
- 多余的实参会被忽略,只会使用形参列表中定义的前几个参数。
- 缺少的实参将被赋值为
undefined
。
例子:
function multiply(a, b) {
return a * b;
}
console.log(multiply(2, 3)); // 输出:6
console.log(multiply(2)); // 输出:NaN,因为 b 是 undefined
console.log(multiply(2, 3, 4)); // 输出:6, 4 被忽略
5.6 参数类型检查
JavaScript 是动态类型语言,参数类型是在运行时确定的。如果需要在函数中确保参数是特定类型,可以手动检查类型:
function addNumbers(x, y) {
if (typeof x !== "number" || typeof y !== "number") {
throw new Error("Both arguments must be numbers");
}
return x + y;
}
console.log(addNumbers(5, 10)); // 输出:15
// console.log(addNumbers(5, "10")); // 抛出错误
5.7 回调函数
在某些情况下,函数参数可以是另一个函数,即回调函数。这种方式让函数具有更好的灵活性和可扩展性。
function processUserInput(callback) {
const userInput = "Hello, World!";
callback(userInput);
}
//函数调用
processUserInput(function(input) {
console.log(input);
}); // 输出:Hello, World!
5.8 箭头函数与常规函数的参数
箭头函数与常规函数相同,也可以接受参数,但其语法更为简洁。例如:
const add = (a, b) => a + b;
console.log(add(5, 3)); // 输出:8
5.9 最优参数待补充
在某些情况下,我们可能需要为参数设置最优值,这可以通过逻辑运算符实现:
function multiply(a, b) {
// 只在 b 为 undefined 时设为默认值 1
b = (typeof b !== 'undefined') ? b : 1;
return a * b;
}
console.log(multiply(5)); // 输出:5
console.log(multiply(5, 0)); // 输出:0
6. 函数参数的传递
在 JavaScript 中,函数参数的传递是通过“值传递”或“引用传递”进行的,这取决于参数的类型。
原始数据类型按值传递,函数内修改不会影响外部变量。 |
对象类型按引用传递,函数内修改会影响外部对象。 |
6.1 值传递
对于原始数据类型(如 number
、string
、boolean
、null
、undefined
和 symbol
),参数是按值传递的。这意味着在函数内部对参数的修改不会影响函数外部的变量。
示例:
function modifyValue(x) {
x = 10;
console.log("函数内部的值:", x); // 输出: 函数内部的值: 10
}
let a = 5;
modifyValue(a);
console.log("函数外部的值:", a); // 输出: 函数外部的值: 5
6.2 引用传递
对于对象类型(如数组、对象和函数),参数是按引用传递的。这意味着在函数内部对参数的修改会影响函数外部引用的对象。
示例:
function modifyObject(obj) {
obj.name = "LuQian";
console.log("函数内部的对象:", obj); // 输出: 函数内部的对象: { name: "LuQian" }
}
let person = { name: "Bob" };
modifyObject(person);
console.log("函数外部的对象:", person); // 输出: 函数外部的对象: { name: "LuQian" }