深入理解 JavaScript 函数:提升编程技能的必备知识(中)

在这里插入图片描述

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6
🍨 阿珊和她的猫_CSDN个人主页
🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》
🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入门到实战全面掌握 uni-app》

文章目录

  • 四、函数的参数传递
    • 按值传递和按引用传递
    • 可选参数和默认值
    • 剩余参数和展开运算符
  • 五、函数的递归
    • 递归函数的定义和示例
    • 递归的注意事项和优化
  • 六、函数作为对象
    • 函数的属性和方法
    • 函数的调用和构造
    • 函数的原型和原型链

四、函数的参数传递

按值传递和按引用传递

在 JavaScript 中,函数参数的传递方式有两种:按值传递和按引用传递。

按值传递是指将实参的值复制一份传递给函数,函数内部对参数的修改不会影响到实参。示例如下:

function changeValue(num) {
  num = 100;
}

let num = 50;
changeValue(num);
console.log(num); 

在上述代码中,定义了一个 changeValue 函数,它接收一个参数 num。在函数内部,将 num 的值修改为 100。然后,在函数外部定义了一个变量 num,并将其初始化为 50。最后,调用 changeValue 函数并传递 num 作为参数。输出结果仍然是 50,而不是 100

按引用传递是指将实参的引用传递给函数,函数内部对参数的修改会影响到实参。在 JavaScript 中,基本数据类型(如字符串、数字、布尔值等)是按值传递的,而对象(包括数组、对象等)是按引用传递的。示例如下:

function changeObj(obj) {
  obj.name = "张三";
}

let person = { name: "李四" };
changeObj(person);
console.log(person.name); 

在上述代码中,定义了一个 changeObj 函数,它接收一个参数 obj,并将其作为对象进行修改。在函数外部定义了一个对象 person,并将其初始化为 { name: "李四" }。最后,调用 changeObj 函数并传递 person 作为参数。输出结果为 张三,说明函数内部对对象的修改会影响到实参。

需要注意的是,在 JavaScript 中,按引用传递只针对对象,而不是基本数据类型。对于基本数据类型,无论函数内部如何修改参数,都不会影响到实参。

可选参数和默认值

在 JavaScript 中,函数的可选参数允许在调用函数时省略一些参数,而默认值则是为可选参数提供的预定义值。当没有传递可选参数时,将使用默认值。

以下是一个示例,展示了如何定义和使用带有可选参数和默认值的函数:

function calculateSum(num1, num2, num3 = 0) {
  return num1 + num2 + num3;
}

console.log(calculateSum(10, 20)); 
console.log(calculateSum(10, 20, 30)); 

在上述示例中,定义了一个名为 calculateSum 的函数,它接受三个参数:num1num2num3。其中,num3 是可选参数,并设置了默认值为 0

在调用 calculateSum 函数时,可以根据需要传递任意数量的参数。如果没有传递 num3 参数,它将使用默认值 0。这样可以使函数更加灵活和易用。

你可以根据实际需求,在函数定义中设置可选参数及其默认值,以便在调用函数时提供更方便的参数传递方式。

剩余参数和展开运算符

剩余参数是指在函数定义中,在参数列表的最后一个参数之后使用三个点 ... 表示剩余参数。在函数调用时,剩余参数将收集所有未被命名的参数,并将它们作为一个数组传递给函数。

例如,以下代码定义了一个带有剩余参数的函数 add

const add = (x, y, z, ...args) => {};

在这个例子中,xyz 是已命名的参数,而 args 是剩余参数。在函数体内,可以使用 args 来访问传递给函数的所有剩余参数。

展开运算符与剩余参数关联密切,它允许将一个数组分割,并将各个项作为分离的参数传给函数。当用在字符串或数组前面时称为扩展运算符。

例如,以下代码使用展开运算符将数组分割成多个参数传递给函数:

const arr = [1, 2, 3];
const result = Math.min(...arr);

在这个例子中,Math.min(...arr) 将数组 arr 展开为三个参数 123,并将它们传递给 Math.min 函数。

五、函数的递归

递归函数的定义和示例

递归函数是一种在函数定义中使用函数自身的函数。它通过反复调用自身来解决问题,直到达到某个终止条件。

递归函数的定义通常包括两个部分:递归步骤和终止条件。

以下是一个使用递归函数计算斐波那契数列的前 n 项的示例:

function fibonacci(n) {
  if (n <= 1) {
    return n;
  } else {
    return fibonacci(n - 1) + fibonacci(n - 2);
  }
}

在这个示例中,定义了一个名为 fibonacci 的递归函数,它接受一个整数参数 n。如果 n 小于等于 1,则直接返回 n,因为斐波那契数列的前两项都是 1。否则,通过调用自身来计算前两项的和,即 fibonacci(n - 1) + fibonacci(n - 2),然后返回这个和。

在使用递归函数时需要注意,由于递归函数会反复调用自身,可能会导致栈溢出。为了避免这种情况,可以使用迭代或其他更高效的算法来解决问题。

递归的注意事项和优化

在使用递归时,需要注意以下几点:

  1. 递归深度:递归函数可能会产生大量的调用,导致栈溢出。为了避免这种情况,需要限制递归的深度。
  2. 终止条件:递归函数必须有明确的终止条件,否则程序将无限循环并导致栈溢出。
  3. 递归效率:递归函数的效率可能较低,因为它需要重复执行相同的操作。在可能的情况下,尽量使用迭代或其他更高效的算法来替代递归。
  4. 内存消耗:递归函数可能会消耗大量的内存,因为每次调用都会创建新的栈帧。在处理大数据量时,需要注意内存使用情况。

在这里插入图片描述

为了优化递归函数,可以考虑以下几点:

  1. 尾递归优化:如果递归函数的最后一个操作是调用自身,可以使用尾递归优化来避免重复创建栈帧。许多编程语言(如 JavaScript)都支持尾递归优化。
  2. 记忆化搜索:对于一些递归问题,可以使用记忆化搜索来避免重复计算。记忆化搜索将已经计算过的结果存储起来,以便在下次遇到相同的情况时直接返回结果,而不必再次递归计算。
  3. 迭代替代:如果可能的话,尽量使用迭代来替代递归。迭代通常比递归更高效,并且可以避免栈溢出的问题。

总之,在使用递归时需要谨慎考虑,并根据具体情况进行优化。如果递归导致性能问题或栈溢出,可以考虑使用其他更高效的算法来解决问题。

六、函数作为对象

函数的属性和方法

在 JavaScript 中,函数作为一种对象,也具有一些属性和方法。以下是一些常见的函数属性和方法:

  1. length 属性:返回函数的形参数量。
  2. name 属性:返回函数的名称。
  3. apply() 方法:调用一个函数,并将其参数作为一个数组进行传递。它可以改变函数的执行上下文。
  4. call() 方法:与 apply() 方法类似,但它还可以指定函数的执行上下文。
  5. bind() 方法:创建一个新的函数,该函数的 this 对象被绑定到指定的值,并将原始函数的参数作为新函数的参数。

在这里插入图片描述

以下是一个示例,展示了如何使用这些属性和方法:

function sum(num1, num2) {
  return num1 + num2;
}

// 使用 length 属性
console.log(sum.length); 

// 使用 name 属性
console.log(sum.name); 

// 使用 apply() 方法
const result = sum.apply(null, [10, 20]);
console.log(result); 

// 使用 call() 方法
const result = sum.call(null, 10, 20);
console.log(result); 

// 使用 bind() 方法
const boundSum = sum.bind(null, 10);
const result = boundSum(20);
console.log(result); 

在上述示例中,我们定义了一个名为 sum 的函数,它接受两个参数并返回它们的和。然后,我们使用 length 属性和 name 属性来获取函数的参数数量和名称。接下来,我们使用 apply() 方法和 call() 方法来调用函数,并将参数作为数组传递。最后,我们使用 bind() 方法创建了一个新的函数 boundSum,它的 this 对象被绑定到 null,并将第一个参数固定为 10。然后,我们调用 boundSum 函数并传递 20 作为第二个参数。

函数的调用和构造

在 JavaScript 中,函数的调用和构造是两个不同的概念。

函数的调用是指执行函数的代码,传递所需的参数,并获取函数的返回值。调用函数的方式有以下几种:

  1. 直接调用:使用函数名后面跟着括号,传递所需的参数。
function sum(num1, num2) {
  return num1 + num2;
}

const result = sum(10, 20);
console.log(result); 
  1. 作为方法调用:如果函数是对象的方法,可以通过对象的点运算符调用。
const obj = {
  sum: function(num1, num2) {
    return num1 + num2;
  }
};

const result = obj.sum(10, 20);
console.log(result); 
  1. 作为构造函数调用:当使用 new 关键字调用函数时,它将创建一个新的对象。
function Person(name, age) {
  this.name = name;
  this.age = age;
}

const person = new Person("张三", 24);
console.log(person.name); 
console.log(person.age); 

函数的构造是指创建一个新的函数对象。在 JavaScript 中,可以使用 Function 构造函数或函数表达式来创建函数对象。

  1. 使用 Function 构造函数:
const sum = new Function("num1", "num2", "return num1 + num2");
console.log(sum(10, 20)); 
  1. 使用函数表达式:
const sum = function(num1, num2) {
  return num1 + num2;
};

console.log(sum(10, 20)); 

无论是通过调用还是构造函数创建的函数,它们都可以执行相同的任务,并且具有相同的特性和行为。选择哪种方式取决于你的需求和代码结构。

函数的原型和原型链

在 JavaScript 中,每个函数都有一个原型对象(prototype),它包含可以被特定类型的所有实例共享的属性和方法。当创建一个函数时,JavaScript 会自动为该函数创建一个原型对象,并将其赋值给函数的 prototype 属性。

原型对象上的属性和方法可以被实例继承。当调用实例的某个方法时,如果该方法在实例自身的属性上找不到,JavaScript 会自动沿着原型链向上查找,直到找到该方法为止。如果最终没有找到该方法,则会返回 undefined

以下是一个示例,展示了原型和原型链的工作原理:

function Person(name) {
  this.name = name;
}

// 在原型对象上添加方法
Person.prototype.sayHello = function() {
  console.log("Hello, my name is " + this.name);
}

const person1 = new Person("张三");
person1.sayHello(); 

// 修改原型对象上的方法
Person.prototype.sayHello = function() {
  console.log("Hello, my name is " + this.name + "! How are you today?");
}

person1.sayHello(); 

在这个示例中,首先创建了一个名为 Person 的函数,它接收一个参数 name,并在实例上创建了一个名为 name 的属性。然后,在原型对象上添加了一个名为 sayHello 的方法。接着,创建了一个 Person 实例 person1,并调用了 sayHello 方法。

当修改原型对象上的方法时,所有的实例都会自动获取到修改后的方法。因此,当再次调用 person1.sayHello() 时,它将输出修改后的问候语

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/264293.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

WPF组合控件TreeView+DataGrid之DataGrid封装

&#xff08;关注博主后&#xff0c;在“粉丝专栏”&#xff0c;可免费阅读此文&#xff09; wpf的功能非常强大&#xff0c;很多控件都是原生的&#xff0c;但是要使用TreeViewDataGrid的组合&#xff0c;就需要我们自己去封装实现。 我们需要的效果如图所示&#x…

【MAC、IOS】charles抓包配置教程,亲测有效

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

4.3【共享源】克隆实战开发之截屏(一)

一,Screen截屏介绍 Screen的截屏是指从源读取像素,然后复制到缓冲区。然后可以根据需要操纵缓冲区;它可以简单地写入文件,也可以在其他窗口或显示器中使用。 Screen API从源中读取像素,并将其复制到提供的缓冲区中以捕获截屏。缓冲区可以是pixmap或窗口缓冲区,但必须设…

UE5 Landscape 制作GIS卫星图地形

1. 总体想法&#xff1a; 制作GIS地形&#xff0c;使用Landscaping MapBox是一个好方法&#xff0c;但是区域过大&#xff0c;会占用很多内存 https://blog.csdn.net/qq_17523181/article/details/135029614 如果采用QGis&#xff0c;导出卫星图&#xff0c;在UE5里拼合出地形…

趁网站还在!用python把次元岛COS小姐姐图集批量下载~

嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 开发环境: Python 3.10 Pycharm 模块使用: requests >>> 数据请求模块 re >>> 匹配提取数据 os >>> 自动创建文件夹 如何安装python第三方模块: win R 输入 cmd 点击确定, 输入安装命令 p…

Codeforces Round 862 (Div. 2)

Problem - A - Codeforces AC代码: #include<bits/stdc.h> #define endl \n //#define int long long using namespace std; const int N1e310; int a[N]; int n; void solve() {cin>>n;int ans0;for(int i1;i<n;i) cin>>a[i],ans^a[i];if(n%21){for(in…

SQL布尔盲注 (Blind)基本原理及使用burpsuite进行暴力猜解

SQL布尔型盲注入是一种SQL注入攻击方式&#xff0c; 根据某个条件是否成立&#xff0c;来判断返回结果的真假&#xff0c;通过布尔型盲注&#xff0c;攻击者可以逐个字符地推断出数据库中存储的信息&#xff0c;如用户名、密码等&#xff0c;从而获取敏感信息或者执行非法操作。…

【EI会议征稿】第三届算法、微芯片与网络应用国际会议(AMNA 2024)

第三届算法、微芯片与网络应用国际会议&#xff08;AMNA 2024&#xff09; 2024 3rd International Conference on Algorithms, Microchips and Network Applications 第三届算法、微芯片与网络应用国际会议(AMNA 2024) 将于2024年3月8-10日在中国西安召开, AMNA 2024将围绕 …

表格实现合并单元格

实现的效果 一、列合并 此需求的列合并比较简单, 直接使用el-table-column包括即可 <el-table-column align"center" sortable label"目标"><el-table-column prop"target1" sortable label"预设目标" /><el-table-c…

设计模式-门面模式

设计模式专栏 模式介绍模式特点应用场景门面模式和代理模式的区别代码示例Java实现门面模式Python实现门面模式 门面模式在spring中的应用 模式介绍 门面模式是一种常用的软件设计模式&#xff0c;也称为外观模式。它提供了一个高层次的接口&#xff0c;将一个子系统的外部与内…

1. 行为模式 - 责任链模式

亦称&#xff1a; 职责链模式、命令链、CoR、Chain of Command、Chain of Responsibility 意图 责任链模式是一种行为设计模式&#xff0c; 允许你将请求沿着处理者链进行发送。 收到请求后&#xff0c; 每个处理者均可对请求进行处理&#xff0c; 或将其传递给链上的下个处理…

SaaS智慧校园云平台源码,智慧班牌系统,家校互联小程序源码

SaaS智慧校园云平台源码&#xff0c;智慧班牌系统&#xff0c;原生小程序 集智慧教学、智慧教务、智慧校务、智慧办公于一体的校园管理平台源码。集成智能硬件及第三方服务&#xff0c;面向学校、教师、家长、学生&#xff0c;将校内外管理、教学等信息资源进行整合&#xff0c…

vue微乾坤子应用开发及ele组件开发时问题记录

一. 微乾坤 1. 新增page页面路由,pmi权限中心配置正常&#xff0c;跳转链接正确&#xff0c;但路由未找到403. 解决&#xff1a; 新增的配置是page类型&#xff0c;transformQianKunRoute方法转换微前端路由数据 时&#xff0c;过滤未兼容page型的路由&#xff0c; 解决 [menu,…

Android开发——添加图片

1、首先选择一张需要的图片&#xff0c;通过左侧的Resource Manage选择“”并选择Import Drawables 选择一张图片 并调整以下两个内容 这两个内容的作用借用谷歌官方的Android开发教程的内容&#xff1a; *Android 设备具有不同的屏幕尺寸&#xff08;手机、平板电脑和电视等…

Histcite下载教程

这个安装就很简单了&#xff0c;可以通过百度网盘下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1WVkXnh3LiJJ08nKqmI5LQw?pwdug9c 提取码&#xff1a;ug9c 解压后&#xff0c;将savedress_for_test.txt放入TXT文件当中 双击main.exe文件&#xff0c;输入1或2…

Kubectl 部署简单应用

创建新服务 kubectl create deployment kubernetes-bootcamp --imagegcr.io/google-samples/kubernetes-bootcamp:v1查看 kubectl get deployments打开新的终端执行 kubectl proxy此时&#xff0c;切回上一个终端&#xff0c;通过 kubectl get pods可查看已部署好的pod。并通…

五种简单保护网站安全的方法看这里!

随着互联网的快速发展&#xff0c;随着品牌效应的加大&#xff0c;企业网站已经成为了企业对外展示的明信片&#xff0c;以及宣传获取私有流量的重要渠道。所以保护企业网站安全至关重要。这里我们就来一起了解一下五种简单保护网站安全的方法&#xff0c;仅供参考哦&#xff0…

【开源工程及源码】超级经典开源项目实景三维数字孪生智慧机场

智慧机场可视化平台通过可视化手段&#xff0c;将复杂的机场运营数据以图形、图表等形式展现&#xff0c;使管理者能够更直观、实时地了解机场的各个方面。飞渡科技通过整合物联网IOT、人工智能、大数据分析等技术&#xff0c;围绕机场管理、运控、安防、服务、监测等业务领域&…

Python模块导入的相关介绍

浅谈python模块的导入操作 1.什么是模块 在Python中有一个概念叫做模块(module)。所谓模块&#xff0c;就是将代码量较大的程序分割成多个有组织的&#xff0c;彼此独立但双能互相交互的代码片段&#xff0c;这些自我包含的有组织的代码段就是模块。 2.模块的特点 python中…

前端真的没有出路了嘛?不,当然不是!一定不是!绝对不是!

hello world&#xff01; 一、为什么会出现“前端已死”的言论 作为一个老前端的老公&#xff0c;我认为前端行业的就业前景非常广阔&#xff0c;而且未来也很有潜力。 我认为前端行业的就业前景非常广阔&#xff0c;而且未来也很有潜力。 有些人却唱衰前端这个行业。我觉得这…