【05】ES6:函数的扩展

一、函数参数的默认值

ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面。

1、基本用法

默认值的生效条件

不传参数,或者明确的传递 undefined 作为参数,只有这两种情况下,默认值才会生效。

注意:null 就是 null,不会使用默认值。

// ES6 之前的默认值实现方式
const log = (x, y) => {// typeof类型检测:返回表示当前数据类型的字符串if (typeof y === 'undefined') {y = 'world'}console.log(x, y)
}log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello
// ES6 默认值实现方式
function log(x, y = 'World') {console.log(x, y)
}log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello

默认值的一些规则

参数变量是默认声明的,所以不能用let或const再次声明。

function foo(x = 5) {let x = 1 // errorconst x = 2 // error
}

使用参数默认值时,函数不能有同名参数。

// 不报错
function foo(x, x, y) {// ...
}// 报错 SyntaxError: Duplicate parameter name not allowed in this context
function foo(x, x, y = 1) {// ...
}

参数默认值是惰性求值的。参数默认值不是传值的,而是每次都重新计算默认值表达式的值。

let x = 99
function foo(p = x + 1) {console.log(p)
}foo() // 100x = 100
foo() // 101

2、与解构赋值默认值结合使用

函数参数默认值 可以与 解构赋值的默认值,结合起来使用。通过给函数参数设置默认值,可以避免在没有提供参数时出现错误。

// 只使用对象的解构赋值默认值
function foo({ x, y = 5 }) {console.log(x, y)
}foo({}) // undefined 5
foo({ x: 1 }) // 1 5
foo({ x: 1, y: 2 }) // 1 2
// 函数 foo()调用时没提供参数,变量 x 和 y 就不会生成,从而报错
foo() // TypeError: Cannot read property 'x' of undefined// -------------------------------------------// 使用对象的解构赋值默认值 + 函数参数的默认值
function foo({ x, y = 5 } = {}) {console.log(x, y)
}foo() // undefined 5
// 只使用对象的解构赋值默认值
function fetch(url, { body = '', method = 'GET', headers = {} }) {console.log(method)
}fetch('http://example.com', {}) // 'GET'
fetch('http://example.com') // 报错// --------------------------------------------------// 使用对象的解构赋值默认值 + 函数参数的默认值
function fetch(url, { body = '', method = 'GET', headers = {} } = {}) {console.log(method)
}fetch('http://example.com') // 'GET'

注意,函数参数的默认值生效以后,参数解构赋值依然会进行。

// 参数默认值 { a: 'hello' } 生效;进行解构赋值,从而触发参数变量 b 的默认值生效。
function f({ a, b = 'world' } = { a: 'hello' }) {console.log(b)
}f() // world// 解构赋值的默认值只在属性值为 undefined 时才会生效
function f({ a, b = 'world' } = { b: 'hello' }) {console.log(b)
}f() // hello

3、参数默认值的位置

通常情况下,定义了默认值的参数,应该是函数的尾参数。因为这样比较容易看出来,到底省略了哪些参数。如果非尾部的参数设置默认值,实际上这个参数是没法省略的。

// 例一
function f(x = 1, y) {return [x, y]
}f() // [1, undefined]
f(2) // [2, undefined]
f(, 1) // 报错
f(undefined, 1) // [1, 1]// 例二
function f(x, y = 5, z) {return [x, y, z]
}f() // [undefined, 5, undefined]
f(1) // [1, 5, undefined]
f(1, ,2) // 报错
f(1, undefined, 2) // [1, 5, 2]

上面代码中,有默认值的参数都不是尾参数。这时,无法只省略该参数,而不省略它后面的参数,除非显式输入 undefined。

如果传入 undefined,将触发该参数等于默认值,null 则没有这个效果。

function foo(x = 5, y = 6) {console.log(x, y)
}foo(undefined, null) // 5 null

4、函数的 length 属性

函数的 length 属性,等于该函数预期传入的参数个数。

当函数指定默认值后,length 属性将失真。将返回没有指定默认值的参数个数,如果设置了默认值的参数不是尾参数,那么 length 属性也不再计入后面的参数了。

(function (a) {}).length // 1
(function (a = 5) {}).length // 0
(function (a, b, c = 5) {}).length // 2(function(...args) {}).length // 0(function (a = 0, b, c) {}).length // 0
(function (a, b = 1, c) {}).length // 1

5、应用

利用参数默认值,可以指定某一个参数不得省略,如果省略就抛出一个错误。

function throwIfMissing() {throw new Error('Missing parameter')
}function foo(mustBeProvided = throwIfMissing()) {return mustBeProvided
}foo() // Error: Missing parameter

上面代码的 foo 函数,如果调用的时候没有参数,就会调用默认值 throwIfMissing 函数,从而抛出一个错误。

从上面代码还可以看到,参数 mustBeProvided 的默认值等于 throwIfMissing 函数的运行结果(注意函数名 throwIfMissing 之后有一对圆括号),这表明参数的默认值不是在定义时执行,而是在运行时执行。如果参数已经赋值,默认值中的函数就不会运行。

另外,可以将参数默认值设为 undefined,表明这个参数是可以省略的。

function foo(optional = undefined) { ··· }

二、reset 参数(…不定参数)

ES6 引入 rest 参数(形式为…变量名),用于获取函数的多余参数,这样就不需要使用 arguments 对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。

function add(...values) {let sum = 0for (var val of values) {sum += val}return sum
}add(2, 5, 3) // 10
// arguments 变量的写法
function sortNumbers() {// arguments 为类数组对象,需先使用 Array.from 转换为数组return Array.from(arguments).sort()
}// rest 参数的写法 (reset 参数为真正的数组)
const sortNumbers = (...numbers) => numbers.sort()

注意,rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错。

// 报错
function f(a, ...b, c) {// ...
}

函数的 length 属性,不包括 rest 参数。

(function(a) {}).length  // 1
(function(...a) {}).length  // 0
(function(a, ...b) {}).length  // 1

三、箭头函数

ES6 规定了可以使用 “箭头” => 来定义一个函数,语法更加简洁。它没有自己的 this、arguments、super 或 new.target,箭头函数表达式更适用于那些本来需要匿名函数的地方,但它不能用作构造函数。

1、基本使用

普通函数

function 函数名() {}const 变量名 = function () {}

箭头函数

(参数) => {函数体}const 变量名 = () => {}
// 基本语法
const add = (x, y) => {return x + y
}// 有且只有一个参数,()可以省略
const add = x => {return x + 1
}// 有且只有一条语句,且为 returen 语句,{} 和 return 可以省略
const add = (x, y) => x + y// return 为对象时,对象外需要加 ()
const add = (x, y) => {return {value: x + y}
}
const add = (x, y) => ({ value: x + y })

2、函数 this 指向

es5 中的 this 指向

函数 this 的取值,是在函数执行的过程中确定的,不是在函数定义时确定的。

(1) 作为普通函数被调用,this 指向 window

(2) 作为对象方法被调用时,this 指向当前对象

(3) 在构造函数中(es5, es6的class方法),this 指向通过构造函数创建的实例对象

(5) 定时器中函数的 this 指向 window,定时器中函数相当于普通函数被调用(setTimeout | setInterval)

es6 中箭头函数的 this 指向

箭头函数中的 this 是在定义的时候绑定的,this 取上级作用域的 this,箭头函数本身不会决定 this 的值。

call、 apply 、 bind

fn.call(this, …params) 和 fn.apply(this, [params]) 都是用来改变函数的this指向
区别是传参不同,call()接受的是列表,apply()接受的是数组

fn.bind(this, params) 方法也是用来改变函数this指向,但是不会立即执行,而是返回一个新函数

3、不适用箭头函数的场景

作为构造函数

因为箭头函数没有 this,而构造函数的核心就是 this。

需要 this 指向调用对象的时候

因为箭头函数没有 this,所以如果箭头函数中出现了 this,那么这个 this 就是外层的!

给事件绑定方法时,比如说通过 addEventListener 给某个事件绑定方法,如果使用箭头函数,此时 this,会指向父级的this window

在定义某个对象的方法时,不可以使用箭头函数

在 vue 的 methods 中的方法,也不可以使用箭头函数,会使 this 指向的不是当前的vm实例,发生错误

需要使用 arguments 的时候

箭头函数没有 arguments。(这个问题有替代解决方案:不定参数)

没有原型

由于箭头函数不能用作构造函数,它们也没有自己的原型。因此,不能使用 prototype 属性来添加新方法。

不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数

四、函数参数的尾逗号

ES2017 允许函数的最后一个参数有尾逗号(trailing comma)。

此前,函数定义和调用时,都不允许最后一个参数后面出现逗号。

function clownsEverywhere(param1,param2
) { /* ... */ }clownsEverywhere('foo','bar'
)

上面代码中,如果在 param2 或 bar 后面加一个逗号,就会报错。

如果像上面这样,将参数写成多行(即每个参数占据一行),以后修改代码的时候,想为函数 clownsEverywhere 添加第三个参数,或者调整参数的次序,就势必要在原来最后一个参数后面添加一个逗号。这对于版本管理系统来说,就会显示添加逗号的那一行也发生了变动。这看上去有点冗余,因此新的语法允许定义和调用时,尾部直接有一个逗号。

function clownsEverywhere(param1,param2,
) { /* ... */ }clownsEverywhere('foo','bar',
)

这样的规定也使得,函数参数与数组和对象的尾逗号规则,保持一致了。

五、catch 命令的参数省略

JavaScript 语言的 try…catch 结构,以前明确要求 catch 命令后面必须跟参数,接受 try 代码块抛出的错误对象。

try {// ...
} catch (err) {// 处理错误
}

上面代码中,catch命令后面带有参数err。

很多时候,catch代码块可能用不到这个参数。但是,为了保证语法正确,还是必须写。ES2019 做出了改变,允许catch语句省略参数。

try {// ...
} catch {// ...
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

react的开发中关于图片的知识

React是一个流行的JavaScript库,用于构建用户界面。在React开发中,图片是一个非常重要的元素,可以用于美化界面和展示内容。本篇博客将详细讲解React中关于图片的知识。 1. React中使用图片 在React中使用图片非常简单,只需要使…

【Web题】狼追兔问题

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

解决Resolving Android Dependencies问题

无论是谷歌的Admob,还是Unity的Level play, 在windows(win10, win11)下,都出现了resolving android dependencies 报错并且卡住的问题,如图: 主要错误,是找不到这个gradlew.bat文件。 在指定位置…

什么是单元测试?

什么是单元测试 单元测试是软件开发中的一种测试方法,旨在验证各个软件组件或模块的功能正确性。在敏捷开发环境中,单元测试尤为重要,因为它有助于确保代码的质量和稳定性。下面是一些关于单元测试的关键点: 定义:单元…

力扣每日一题-统计和小于目标的下标对数目-2023.11.24

力扣每日一题:统计和小于目标的下标对数目 开篇 今天这道力扣打卡题写得我好狼狈,一开始思路有点问题,后面就是对自己的代码到处缝缝补补,最后蒙混过关。只能分享一下大佬的代码,然后我帮大家分享代码的思路。 题目链…

大模型能否生成搜索引擎的未来?

文|郝 鑫 编|刘雨琦 ChatGPT火爆之前,水面下,也有中国公司也在朝着智能助手的方向努力。夸克便是其中之一。在GPT风靡科技圈后,国内就开始陆续冒出一些大模型厂商。对当时夸克而言,做大模型毋庸置疑&am…

django(千锋教育)

创建一个django项目 官网下载python最新版本 配置到环境变量中 打开intlij编辑器 创建django项目 安装django:pip install django 创建django项目: django-admin startproject django01 创建djangoAPP:python manage.py startapp App 启动&#xff1a…

设置定时自动请求测试_自动定时循环发送http_post请求---postman工作笔记001

其实就是创建接口文件夹的时候,有个monitor collection 用来监听接口执行情况,这里就可以设置 可以看到多久执行一次对吧,这里可以设置每几分钟执行一次,一共执行多少次等等 但是这里要说明一下,如果需要使用monitor功能,必须需要登录, 所以如果这里点击monitor collection…

媒体增加日活量的有效策略

随着数字媒体的蓬勃发展,提高日活量成为媒体平台追求的重要目标之一。日活量的增加不仅意味着更广泛的影响力,还能为媒体平台带来更多的商业机会。以下是一些有效的策略,可帮助媒体提高日活量: admaoyan猫眼聚合 内容优质化&#…

**QT与目标板联合调试_断点仿真**

原文地址: https://blog.csdn.net/u012851408/article/details/86715626

仙女麻麻看过来~这是不是你们在找的外套?

分享女儿的秋冬穿搭 时尚与美观兼具的毛毛外套 洋气百搭不挑人穿 谁穿对都好看系列 经典宽松版型 不臃肿对身材包容性很强 小编墙裂推荐哦!!

NFT Insider115:The Sandbox开设元宇宙Diorama快闪店,​YGG Web3 游戏峰会已开幕

引言:NFT Insider由NFT收藏组织WHALE Members、BeepCrypto联合出品,浓缩每周NFT新闻,为大家带来关于NFT最全面、最新鲜、最有价值的讯息。每期周报将从NFT市场数据,艺术新闻类,游戏新闻类,虚拟世界类&#…

RevCol:可逆的柱状神经网络

文章目录 摘要1、简介2、方法2.1、Multi-LeVEl ReVERsible Unit2.2、可逆列架构2.2.1、MACRo设计2.2.2、MicRo 设计 2.3、中间监督 3、实验部分3.1、图像分类3.2、目标检测3.3、语义分割3.4、与SOTA基础模型的系统级比较3.5、更多分析实验3.5.1、可逆列架构的性能提升3.5.2、可…

贵金属交易指南:如何在市场中获利?

贵金属市场一直以来都是投资者追逐利润的热门选择,然而,贵金属市场波动较大,在市场中获利并非易事。想要成功,需要理解市场动态和采取适当的策略。万洲金业将为您提供一些实用的贵金属交易指南,帮助您在市场中获利。 …

PostgreSQL create or replace view和重建视图 有什么区别?

一、 replace vs 重建 遇到开发提了个问题,create or replace view和重建视图(dropcreate)有什么区别,查询资料整理了一下。 1. create or replace 当存在同名视图时,尝试将其替换新视图语句必须与现有视图查询具有相…

LeetCode算法题解(动态规划,背包问题)|LeetCode1049. 最后一块石头的重量 II、LeetCode494. 目标和

一、LeetCode1049. 最后一块石头的重量 II 题目链接:1049. 最后一块石头的重量 II 题目描述: 有一堆石头,用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。 每一回合,从中选出任意两块石头,然后将…

springboot2.1升级到2.7 actuator丢失部分metrics端点

项目场景: 项目需要升级springboot从2.1升级至2.7 问题描述 发现之前的metrics后面的jvm相关的端口丢了 原因分析: 找到这样一篇博文https://blog.csdn.net/CL_YD/article/details/120309094,这篇博文意思是对的,但是写的不太好…

Java基于springoot开发的企业招聘求职网站

演示视频: https://www.bilibili.com/video/BV1xw411n7Tu/?share_sourcecopy_web&vd_source11344bb73ef9b33550b8202d07ae139b 技术:springootmysqlvuejsbootstrappoi制作word模板 主要功能:求职者可以注册发布简历,选择简…

案例018:基于微信小程序的实习记录系统

文末获取源码 开发语言:Java 框架:SSM JDK版本:JDK1.8 数据库:mysql 5.7 开发软件:eclipse/myeclipse/idea Maven包:Maven3.5.4 小程序框架:uniapp 小程序开发软件:HBuilder X 小程序…

【python入门篇】函数(6)

这一节将详细介绍Python中函数的用法,包括函数的定义、调用、参数、返回值、作用域等。 函数的概述: Python函数是一种封装了特定任务的可重用代码块。通过将程序分解为更小、更具体的任务,函数提供了一种有效的方式来组织和管理代码&#xf…