【ES6】4.函数的扩展

1.函数参数的默认值

  • 函数的参数允许带有默认值,参数变量是默认声明的,无需使用let或const再次声明。
// 无需使用let或const声明
function f(x = 1, y = 2) { ... }

// 参数使用默认值时,函数不能有同名参数
function f(x, x, y) { ... } // 没有默认值,不报错
function f(x, x, y = 1) { ... } // 有默认值,有同名参数,报错

(1)函数默认值与解构赋值结合使用

function f({ x, y = 5}) { ... }
f({X: 1}) // 1  5
f({}) // undeifned 5
f() // 报错

// 解构赋值指定默认值
function({ x, y = 5 } = {}) // 等号右边严格等于(===)undeifned时,左边的默认值生效
f() // 不报错 undefined 5

(2)默认参数的位置

  • 默认参数应该放在尾部,这样可以被省略。
function f(x = 1, y) { ... } // 默认参数不放后面
f() // [1, undefined] 传入的参数为undeifned时,才取用默认参数
f(2) // [2, undefined]
f(,2) // 报错

function f(x, y = 1) { ... } // 默认参数放后面,这样调用的时候可以只传一个参数
f(1) // [1, 1]

(3)函数的length属性

  • 函数的length属性可以返回参数的个数,但是参数指定了默认值之后,length会失真,只返回指定默认值参数之前的个数。rest参数也是同理。
(function f(x, y, z) { ... }).length // 3
(function f(x, y = 1, z) { ... }).length // 1
(function f(x = 1, y = 2, z = 3) { ... }).length // 0
(function(...args) {}).length // 0

(4)严格模式问题

  • 只要函数参数使用了默认值、解构赋值、rest等就不能在函数内部显式的设定为严格模式,否则会报错。
  • 解决办法一个是在全局设定严格模式;另一个是在函数外面包一个立即执行的无参数函数 ,并且把严格模式设定在外层函数。
// 报错
function doSomething(a, b = a) {
  'use strict';
 	...
}

// 报错
const doSomething = function ({a, b}) {
  'use strict';
  ...
};

// 报错
const doSomething = (...a) => {
  'use strict';
 	...
};

const obj = {
  // 报错
  doSomething({a, b}) {
    'use strict';
    ...
  }
};

// 1.全局设定严格模式
'use strict';

function doSomething(a, b = a) {
  // code
}
// 2.把函数包在立即执行的无参数函数里
const doSomething = (function () {
  'use strict';
  return function(value = 42) {
    return value;
  };
}());

2.rest参数

  • 形式为(…变量名),如...arr,如果有多个参数,reset只能作为最后一个参数,否则会报错
function add(...values) {
  let sum = 0;
  for (var val of values) {
    sum += val;
  }
  return sum;
}
add(2, 5, 3) // 10  可以向函数传入任意数目的参数

function f(x, ...y, z) { ... } // 报错

3.name属性

  • 函数的name属性返回该函数的函数名。
function fn() {}
const res = fn.name // fn
  • 将匿名函数赋值给一个变量,ES5返回的是空字符串,而ES6返回实际的函数名
const fun = function() {} // 将匿名函数赋值给fun
const res = fun.name // ES6打印出fun,ES5则打印出空字符串
  • 将具名函数赋值给一个变量,返回的是函数原本的函数名
const foo = function fn() {}
const res = foo.name // fn 打印出具名函数fn()原本的函数名

4.箭头函数

  • 使用箭头(()=>)定义函数,括号代表参数部分,参数可以零个或多个,箭头后面代表返回值
const res = n => n * 2 
// 等价于 
const res = function(n) { return n * 2 }
  • 如果返回值超过一行,需要用花括号{}包起来,并且加上return,没写的话默认return:undefined
const mul = (n, m) => {
  const count = n + m
  return count
}
console.log(mul(3, 6)); // 9
  • 若要返回对象,必须在对象外面加上括号,否则报错。
let foo = () => { a: 1 } // 返回undefined,若要返回对象,需要将返回值用括号包起来
let foo = () => ({ a: 1 }) // 返回{a: 1}
  • 箭头函数与解构赋值结合使用
const foo = ({ firstName, lastName }) => `${firstName}-${lastName}`
const res = foo({firstName: 'Vincent', lastName: 'William'}) // Vincent-William
  • 箭头函数与rest参数结合使用
const numbers = (...nums) => nums
const res = numbers(1, 2, 3, 4, 5) // [1, 2, 3, 4, 5]

const fn = (first, ...other) => [first, other]
const res = fn(1, 2, 2, 4, 5, 6) // [1, [2, 2, 4, 5, 6]]
  • *箭头函数的注意点:
    1、箭头函数没有自己的this,函数体内的this对象是定义时所在的对象(它在声明的时候可以捕获其所在上下文的this供自己使用),也就是说箭头函数的this指向的是函数声明时所在的上下文。
    2、在普通函数中this的指向是可变的,但是在箭头函数中它是固定的,call()、apply()、bind()对于箭头函数没有效果。
    3、箭头函数不能用于构造函数,不能使用new命令,否则会抛出一个错误,因为new内部有改变this指向的操作。
    4、不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用rest参数代替。
    5、不可以使用yield命令,因此箭头函数不能用作Generator函数。
    6、箭头函数不具有prototype原型对象,也因此不能被new,因为new内部需要调用函数的prototype属性。

5.尾调用优化

  • 目前只有Safari浏览器支持尾调用优化,所以先了解一下就好了。
  • 尾调用(Tail Call)是指在函数的最后一步调用另一个函数。
  • 关于尾调用优化参考:尾调用优化
function fn() {
    return g()
}
以下情况不属于尾调用:
// 1.调用函数g之后,还有赋值操作
function f(x){
  let y = g(x);
  return y;
}

// 2.也是调用函数g之后,还有其他操作
function f(x){
  return g(x) + 1;
}

// 3.调用g之后,还有一个return undefined的操作,所以调用g不是最后一步
function f(x){
  g(x);
}
// 4.内层函数inner还有用到外层函数的one变量,因此外层函数无法被释放,无法进行“尾调用优化”
function addOne(a){
  var one = 1;
  function inner(b){
    return b + one;
  }
  return inner(a);
}

6.尾递归

  • 递归:函数调用自身;尾递归:尾调用自身。
// 普通的递归
function factorial(n) {
   if (n === 1) return 1;
   return n * factorial(n - 1);
 }
const res = factorial(5) // 120

// 改写为尾递归
function factorial(n, total = 1) {
  if (n === 1) return total
  return factorial(n - 1, total * n)
}
const res = factorial(5)
console.log(res); // 120

7.函数参数的尾逗号

  • 如下例子,函数每个参数独占一行,之后要添加参数的话,势必要在原来的最后一个参数后面加一个逗号,这样对于版本管理系统来说,会显示添加逗号的那行也发生了变化,看上去有点冗余。因此,新的语法允许定义和调用的时候,尾部直接有一个逗号。
// ES2017前
function fn(
    param1,
    param2
)

// ES2017后
function fn(
    param1,
    param2,
)

8.Function.prototype.toString()

  • 函数的toString()方法返回函数代码本身。ES2019以前,会忽略空格和注释;ES2019后会返回所有的原始代码。
// ES2019前
function /* foo comment */ foo () {}
foo.toString() // function foo() {}

// ES2019后
function /* foo comment */ foo () {}
foo.toString() // "function /* foo comment */ foo () {}"

9.catch参数可省略

  • ES2019之后可以省略catch后面的参数
// ES2019前
try {
  // ...
} catch (err) {
  // 处理错误
}

// ES2019后
try {
  // ...
} catch {
  // 处理错误
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值