es6学习笔记9--函数的扩展
函数参数的默认值基本用法在ES6之前,不能直接为函数的参数指定默认值,为了避免这个问题,通常需要先判断一下参数 ES6允许为函数的参数设置默认值,即直接写在参数定义的后面。 function log(x,y = 'World') { console.log(x,y); } log('Hello') // Hello World log('Hello','China') Hello China log('Hello','') Hello 可以看到,ES6的写法比ES5简洁许多,而且非常自然。 ES6的写法还有两个好处:首先,阅读代码的人,可以立刻意识到哪些参数是可以省略的,不用查看函数体或文档;其次,有利于将来的代码优化,即使未来的版本在对外接口中,彻底拿掉这个参数,也不会导致以前的代码无法运行。 参数变量是默认声明的,所以不能用 function foo(x = 5) { let x = 1; error const x = 2; error } 上面代码中,参数变量 与解构赋值默认值结合使用参数默认值可以与解构赋值的默认值,结合起来使用。 function foo({x,y = 5}) { console.log(x,y); } foo({}) undefined,5 foo({x: 1}) 1,5 foo({x: 1,y: 2}) TypeError: Cannot read property 'x' of undefined 上面代码使用了对象的解构赋值默认值,而没有使用函数参数的默认值。只有当函数 参数默认值的位置通常情况下,定义了默认值的参数,应该是函数的尾参数。因为这样比较容易看出来,到底省略了哪些参数。如果非尾部的参数设置默认值,实际上这个参数是没法省略的。 例一 function f(x = 1,y) { return [x,y]; } f() [1,undefined] f(2) [2,undefined]) f(,1) 报错 f(undefined,1] 例二 function f(x,z) { [undefined,5,undefined] f(1) 报错 f(1,undefined,2] 上面代码中,有默认值的参数都不是尾参数。这时,无法只省略该参数,而不省略它后面的参数,除非显式输入 如果传入 function foo(x = 5,y = 6null) 5 null 上面代码中, 函数的length属性指定了默认值以后,函数的 (function (a) {}).length 1 (function (a = 5) {}).length 0 (function (a,b,c = 5) {}).length 2 上面代码中, 这是因为 (function(...args) {}).length 0 如果设置了默认值的参数不是尾参数,那么 (function (a = 0,c) {}).length 1 作用域一个需要注意的地方是,如果参数默认值是一个变量,则该变量所处的作用域,与其他变量的作用域规则是一样的,即先是当前函数的作用域,然后才是全局作用域。 var x = 1; x) { console.log(y); } f(2) 2 上面代码中,参数 如果调用时,函数作用域内部的变量 let x = 1function f(y = x) { let x = 2; console.log(y); } f() 1 上面代码中,函数调用时, 利用参数默认值,可以指定某一个参数不得省略,如果省略就抛出一个错误。 function throwIfMissing() { throw new Error('Missing parameter'); } function foo(mustBeProvided = throwIfMissing()) { mustBeProvided; } foo() Error: Missing parameter 上面代码的 从上面代码还可以看到,参数 另外,可以将参数默认值设为 function foo(optional = undefined) { ··· }
rest参数ES6引入rest参数(形式为“...变量名”),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest参数搭配的变量是一个数组,该变量将多余的参数放入数组中。 add(...values) { let sum = 0; for (var val of values) { sum += val; } sum; } add(2,3) 10 上面代码的add函数是一个求和函数,利用rest参数,可以向该函数传入任意数目的参数。 下面是一个rest参数代替arguments变量的例子。 arguments变量的写法 sortNumbers() { Array.prototype.slice.call(arguments).sort(); } rest参数的写法 const sortNumbers = (...numbers) => numbers.sort(); 上面代码的两种写法,比较后可以发现,rest参数的写法更自然也更简洁。 注意,rest参数之后不能再有其他参数(即只能是最后一个参数),否则会报错。 报错 f(a,...b,c) { ... } 函数的length属性,不包括rest参数。 (function(a) {}).length function(...a) {}).length function(a,...b) {}).length 1 扩展运算符含义扩展运算符(spread)是三个点( console.log(...[1,2,3]) 1 2 3 console.log(1,...[2,3,4],5 1 2 3 4 5 [...document.querySelectorAll('div')] [<div>,<div>,<div>] 该运算符主要用于函数调用。 替代数组的apply方法由于扩展运算符可以展开数组,所以不再需要 ES5的写法 f(x,1)"> ... } var args = [0,1,2]; f.apply( ES6的写法 ]; f(...args); 扩展运算符的应用(1)合并数组 ES5 [1,1)">].concat(more) ES6 [1,...more] (2)与解构赋值结合 扩展运算符可以与解构赋值结合起来,用于生成数组。 ES5 a = list[0],rest = list.slice(1 ES6 [a,...rest] = list 如果将扩展运算符用于数组赋值,只能放在参数的最后一位,否则会报错。 (3)函数的返回值 JavaScript的函数只能返回一个值,如果需要返回多个值,只能返回数组或对象。扩展运算符提供了解决这个问题的一种变通方法。 var dateFields = readDateFields(database); var d = new Date(...dateFields); 上面代码从数据库取出一行数据,通过扩展运算符,直接将其传入构造函数 4)字符串 扩展运算符还可以将字符串转为真正的数组。 [...'hello'] [ "h","e","l","o" ] 上面的写法,有一个重要的好处,那就是能够正确识别32位的Unicode字符。 'xuD83DuDE80y'.length 4 [...'xuD83DuDE80y'].length 3 (5)实现了Iterator接口的对象 任何Iterator接口的对象,都可以用扩展运算符转为真正的数组。 var nodeList = document.querySelectorAll('div'); var array = [...nodeList]; 上面代码中, name属性函数的 foo() {} foo.name "foo" 这个属性早就被浏览器广泛支持,但是直到ES6,才将其写入了标准。 需要注意的是,ES6对这个属性的行为做出了一些修改。如果将一个匿名函数赋值给一个变量,ES5的 var func1 = () {}; ES5 func1.name "" ES6 func1.name "func1" 上面代码中,变量
foo() {}; foo.bind({}).name "bound foo" (function(){}).bind({}).name "bound " ? ? (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |