函数默认值是一个很提高鲁棒性的东西(就是让程序更健壮)
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. 经过一段的努力,终于成为CSDN博客专家,感谢大家支持

    感谢CSDN提供这么好的一个技术学习平台,通过各路大神的博客我成长了许多,同时也感谢支持我的朋友们,我会继续努力,用心去写好博客.还请继续关注我~ 谢谢!

  2. python3.4 + Django1.7.7 表单的一些问题

    上面是没有调用cleaned_data的提交结果,可见模版直接把form里面的整个标签都接收过来了 下面是调用cleaned_data 的结果 django 的表单,提交上来之后是这样的: #codi ...

  3. Dynamics CRM2013/2015 禁止欢迎界面(Disable the Welcome Screen)

    首次打开Dynamic CRM  2013会出现一个欢迎界面如下图,要想它不出现勾选图中的复选框就行,OK下回再打开就没有了. 但是当我们打开F12开发人员工具,清除域的缓存后再次打开CRM,这个欢迎 ...

  4. UML之活动图

    活动图,她的英文名字叫Activity Diagram,是一种说明业务用例实现的工作流程,活动图是UML大家族中用于对系统的动态方面建模的无中图之一. 举个简单的例子,以建房的工作流为例,首先,我们要 ...

  5. cocos2d-x 读写 xml 文件

    cocos2d-x 读写 xml 文件 A product of cheungmine使用cocos2d-x开发2d游戏确实方便,但是对于一般的小游戏,经常需要的工作是UI布局设计和调整,代码改来改去 ...

  6. OAF中的TableLayout 高级表格

    我们经常会遇到这种情况,我们要把显示界面分成几块区域来分别显示不同的内容.比如在同一行左边显示messageComponentLayout,右边显示table,这时,我们就要用到tableLayout ...

  7. windows的服务中的登录身份本地系统账户、本地服务账户和网络服务账户修改

    以一个redis服务为例: 一个redis注册服务后一般是网络服务账户,但是当系统不存在网络服务账户时,就会导致redis服务无法正常启动.接下来修改redis服务的登录身份. cmd下输入如下命令: ...

  8. 写一个python的服务监控程序

    写一个python的服务监控程序 前言: Redhat下安装Python2.7 rhel6.4自带的是2.6, 发现有的机器是python2.4. 到python网站下载源代码,解压到Redhat上, ...

  9. iOS下如何获取一个类的所有子类

    因为项目中,不同用户切换时,用的是不同数据库,路径不同,而JKDBModel,数据库创建和字段检测,在app一次生命周期里,只会执行一次,所以得考虑账号切换时,创建数据库,需要获取所有JKDBMode ...

  10. Android+struts2+json方式模拟手机登录功能

    涉及到的知识点: 1.Struts2框架的搭建(包括Struts2的jSON插件) 2.Android前台访问Web采用HttpClient方式. 3.Android采用JSON的解析. 服务端主要包 ...