函数默认值是一个很提高鲁棒性的东西(就是让程序更健壮)
MDN关于函数默认参数的描述:函数默认参数允许在没有值或undefined被传入时使用默认形参。

ES5

使用逻辑或||来实现

众所周知,在ES5版本中,并没有提供的直接方法供我们我们处理函数默认值
所以只能够自己去增强函数的功能,一般会这么来做:

function doSomething (name, age) {
name = name || 'default name'
age = age || 18 console.log(name, age)
}

我们将函数的两个参数nameage进行默认值的处理,如果没有则使用默认值。
在执行一下函数后,好像并没有什么不对:

doSomething()       // default name, 18
doSomething('Niko') // Niko , 18
doSomething(, 12) // default name, 12

然而当我们执行这样的代码时,就会获得一些超出预期的结果:

doSomething('Niko', 0) // Niko, 18

能够发现,对于参数0,我们上边的默认参数实现方法是有问题的

就像下边的四个表达式,都会输出wrong,这很显然不能够满足上边MDN关于函数默认参数的定义:

console.log(0         || 'wrong')
console.log('' || 'wrong')
console.log(null || 'wrong')
console.log(false || 'wrong')

正确的姿势

所以,在ES5中正确的默认值处理应该是这样:

function doSomething (name, age) {
if (name === undefined) {
name = 'default name'
} if (age === undefined) {
age = 18
} console.log(name, age)
}

使用三元运算符简化操作

或者我们简写成三元运算符形式的:

function doSomething (name, age) {
name = name === undefined ? 'default name' : name
age = age === undefined ? 18 : age console.log(name, age)
}

使用函数进行封装

但是如果我们每写一个函数,都要重复的去做这些操作
未免太麻烦了,所以,我们对这个逻辑进行一个简单的封装:

function defaultValue (val, defaultVal) {
return val === undefined ? defaultVal : val
} function doSomething (name, age) {
name = defaultValue(name, 'default name')
age = defaultValue(age , 18) console.log(name, age)
}

这样就很简洁的在ES5实现了函数默认参数的逻辑

one momre things

关于上边的defaultValue函数实现方法,我们在合理的使用弱类型语言的优势后
可以使用这种方式来省去三元运算符的操作:

function defaultValue () {
return arguments[+(arguments[0] === undefined)]
}

我们知道,arguments表示函数所有的实参
我们使用arguments[0]获取第一个实参,然后与undefined进行全等比较
在外层将表达式的结果转换为Number,然后将这个值作为下标获取arguments中对应的参数。
因为是由Boolean值转变而来,所以只会存在01两种选项。
也就实现了上边三元运算符的功能。

ES6

ES6版本的函数默认值基本上就是我们上边实现的那种套路了
但是因为是原生的,所以会有相应的新语法,能够更简洁的使用:

function doSomething (name = 'default name', age = 18) {
console.log(name, age)
}

ES6中提供了新的语法,可以让我们在函数声明参数后边直接写= [defaultValue]的这种形式来设置某个参数的默认值。
直接使用这种方式,省去了在函数内部进行默认值的检查,能够让函数专注的做它应该做的事情。

如何针对某些必填参数抛出异常

ES6这种新语法能够让我们很好的针对某个必填参数进行错误提醒:

function requireParams () {
throw new Error('required params')
} function doSomething (name = requireParams(), age = 18) {
// do something
}

如果name参数为undefined,就会触发默认值规则
然后调用requireParams函数,而我们在函数中直接throw了一个Error

复杂结构参数的默认值处理

上边的处理都是针对简单的基本类型数据进行处理的,但如果我们有如下的一个函数:

function init ({id, value}) {}

init({
id: 'tagId',
value: 1
})

如果在ES5环境下,针对这种参数的默认值处理将会变得无比复杂
首先要判断这一个参数是否存在,然后在判断参数中的所有key是否存在
而在ES6中,可以这样来做:

function init ({
id = 'defaultId',
value = 1
} = {}) {
console.log(id, value)
} init()

首先在解构函数的后边添加默认值= {},然后针对每一项参数添加默认值,很简洁的就实现了我们的需求。

ES5版本的polyfill代码在仓库中的位置:defaultValue

参考资料

  1. MDN

如何在ES5与ES6环境下处理函数默认参数的更多相关文章

  1. ES6新特性(函数默认参数,箭头函数)

    ES6新特性之 函数参数的默认值写法 和 箭头函数. 1.函数参数的默认值 ES5中不能直接为函数的参数指定默认值,只能通过以下的变通方式:   从上面的代码可以看出存在一个问题,当传入的参数为0或者 ...

  2. Windows环境下main()函数传入参数

    最近几天在写一个模仿windows自带的ping程序,也从网上找过一些源码,但大都需要向主函数main中传入参数,这里简单总结一下向主函数中传参的方法. 方法一:项目->属性->调试-&g ...

  3. 基于Gulp + Browserify构建es6环境下的自动化前端项目

    随着React.Angular2.Redux等前沿的前端框架越来越流行,使用webpack.gulp等工具构建前端自动化项目也随之变得越来越重要.鉴于目前业界普遍更流行使用webpack来构建es6( ...

  4. ES6教程-字符串,函数的参数,了解函数的arguments对象,js面向对象,设计模式-单例模式,解构赋值

    前言 主要讲解了ES6对字符串的拓展,包括includes,startsWith和endsWith,另外增加了字符串模板. Start includes()是否包含 startsWith()以什么开头 ...

  5. Centos环境下手动设置-网络参数配置-网络挨排错顺序-设置网卡为上网模式的设定

    Linux中网络参数大致包含以下内容: IP地址 子网掩码 网关 DNS服务器 主机名(默认 localhost) 历来Linux系统中修改这些参数的方式通常有:命令.文件两种.其中通过命令设置可以立 ...

  6. ES6新增语法(二)——函数和参数

    箭头函数 箭头函数:将原来函数的function关键字和函数名都删掉,并使用"=>"连接参数列表和函数体. 箭头函数语法: (参数1,参数2)=>{ 函数体 } 注意点 ...

  7. ES6函数默认参数(Default Parameters)

    语言更新时每一个新增的特性都是从千百万开发者需求里提取过来的,规范采用后能减少程序员的痛苦,带来便捷. 我们经常会这么写 function calc(x, y) { x = x || 0; y = y ...

  8. es6 初级之---const 和 默认参数

    1. const 的定义: 1.1 常量定义的时候要赋值,不赋值是会报错的: <!DOCTYPE html> <html lang="en"> <he ...

  9. 如何在Google Web Toolkit环境下Getshell

    出品|MS08067实验室(www.ms08067.com) 本文作者:大盗贼卡卡 Google Web Toolkit简称(GWT),是一款开源Java软件开发框架.今天这篇文章会介绍如何在这样的环 ...

随机推荐

  1. android官方技术文档翻译——Android Lint

    本文译自androd官方技术文档<Android Lint>,原文地址:http://tools.android.com/tips/lint. 本文地址:http://blog.csdn. ...

  2. Android Studio集成Genymotion

    Android Studio集成Genymotion比在Eclipse中集成简单多了.主要以下几个步骤: 1.官网先下载Genymotion:http://www.genymotion.com/,下载 ...

  3. Volley请求

    1. Volley简介 我们平时在开发Android应用的时候不可避免地都需要用到网络技术,而多数情况下应用程序都会使用HTTP协议来发送和接收网络数据.Android系统中主要提供了两种方式来进行H ...

  4. MySQL学习笔记_8_SQL语言基础复习

    SQL语言基础复习 一.概述 SQL语句注释方式 1)以"#"开头直到行尾的所有内容都是注释 2)以"--"(--后还有一个空格)开头直到行尾的所有内容都是注释 ...

  5. [WinForm]动态显示本地目录图片与悬浮窗

    加载显示: if (File.Exists(@"D:\产品图片\" + item + ".jpg")) { //需要判断是否存在图片 Image img = I ...

  6. 关于Android的https通讯安全

    原文链接:http://pingguohe.net/2016/02/26/Android-App-secure-ssl.html 起因 前段时间,同事拿着一个代码安全扫描出来的 bug 过来咨询,我一 ...

  7. Linux的常用命令(1) - 指定运行级别

    命令:init [0123456] 运行级别 0:关机 1:单用户 2:多用户状态没有网络服务 3:多用户状态有网络服务 4:系统未使用保留给用户 5:图形界面 6:系统重启 常用运行级别是3和5,要 ...

  8. jquery.query-*.js 操作url

     做的项目中需要用到通过JS获取GET参数,上网找了一下,找到如下插件: 例如 当前你的URL是: http://www.xxx.com/index.php?test=1&kk=2 如果想 ...

  9. C++之IO操作

    可参考自: C++之标准设备IO操作流 C++之预定义类型IO格式控制 C++之文件IO操作流

  10. redis持久化AOF与RDB配置

    AOF保存的数据方案时最完整的,如果同时开启了rdb和aof下,会采用aof方式. (1)设置数据保存到数据文件中的save规则 save 900 1     #900秒时间,至少有一条数据更新,则保 ...