自学内容网 自学内容网

深入理解函数【JavaScript】

在 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 值传递

对于原始数据类型(如 numberstringbooleannullundefined 和 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" }

原文地址:https://blog.csdn.net/2302_77228054/article/details/142554402

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!