当前位置: 首页 > news >正文

深入理解函数【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 时设为默认值 1b = (typeof b !== 'undefined') ? b : 1;return a * b;}console.log(multiply(5)); // 输出:5console.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" }

相关文章:

  • WPF项目中使用Caliburn.Micro框架实现日志和主题切换
  • ubuntu20.04系统安装zookeeper简单教程
  • 【PostgreSQL】PostgreSQL数据库允许其他IP连接到数据库(Windows Linux)
  • MATLAB案例 | Copula的密度函数和分布函数图
  • vue echarts tooltip动态绑定模板,并且处理vue事件绑定
  • 将ai模型部署在服务器,会比本地离线更快吗
  • Proteus-7.8sp2安装
  • 论文阅读 | 一种基于潜在向量优化的可证明安全的图像隐写方法(TMM 2023)
  • Apache Cordova和PhoneGap
  • Redis支持数据类型,它们各自的应用场景是
  • 基于深度学习的文本情感原因提取研究综述——论文阅读
  • Spring Boot 2.x基础教程:实现文件上传
  • 理解:基础地理实体相关概述
  • 局域网中实现一对一视频聊天(附源码)
  • Shp2pb:Shapefile转Protocol Buffers的高效工具
  • 【翻译】babel对TC39装饰器草案的实现
  • Android Studio:GIT提交项目到远程仓库
  • Mac 鼠须管 Rime 输入法 安装五笔输入法 教程
  • Making An Indicator With Pure CSS
  • mongo索引构建
  • Netty 4.1 源代码学习:线程模型
  • Next.js之基础概念(二)
  • Node项目之评分系统(二)- 数据库设计
  • python 装饰器(一)
  • Redis 懒删除(lazy free)简史
  • Selenium实战教程系列(二)---元素定位
  • 阿里云Kubernetes容器服务上体验Knative
  • -- 查询加强-- 使用如何where子句进行筛选,% _ like的使用
  • 彻底搞懂浏览器Event-loop
  • 从0实现一个tiny react(三)生命周期
  • 等保2.0 | 几维安全发布等保检测、等保加固专版 加速企业等保合规
  • 聊聊directory traversal attack
  • 马上搞懂 GeoJSON
  • 买一台 iPhone X,还是创建一家未来的独角兽?
  • 算法-插入排序
  • 推荐一个React的管理后台框架
  • 一个普通的 5 年iOS开发者的自我总结,以及5年开发经历和感想!
  • 再次简单明了总结flex布局,一看就懂...
  • Oracle Portal 11g Diagnostics using Remote Diagnostic Agent (RDA) [ID 1059805.
  • ​LeetCode解法汇总518. 零钱兑换 II
  • ​如何使用ArcGIS Pro制作渐变河流效果
  • ‌Excel VBA进行间比法设计
  • # 20155222 2016-2017-2 《Java程序设计》第5周学习总结
  • # 移动硬盘误操作制作为启动盘数据恢复问题
  • #Js篇:单线程模式同步任务异步任务任务队列事件循环setTimeout() setInterval()
  • #我与Java虚拟机的故事#连载14:挑战高薪面试必看
  • #我与Java虚拟机的故事#连载17:我的Java技术水平有了一个本质的提升
  • (160)时序收敛--->(10)时序收敛十
  • (2009.11版)《网络管理员考试 考前冲刺预测卷及考点解析》复习重点
  • (9)YOLO-Pose:使用对象关键点相似性损失增强多人姿态估计的增强版YOLO
  • (CPU/GPU)粒子继承贴图颜色发射
  • (PyTorch)TCN和RNN/LSTM/GRU结合实现时间序列预测
  • (创新)基于VMD-CNN-BiLSTM的电力负荷预测—代码+数据
  • (第61天)多租户架构(CDB/PDB)
  • (附源码)spring boot儿童教育管理系统 毕业设计 281442