函数拓展

es6对函数做了很友好的修改,使得函数的编写更加的方便。

1、函数默认值问题

在es5中我们要给一个函数参数设置默认值,一般都是使用||来完成。

function log(x, y) {
  y = y || 'World';
  console.log(x, y);
}

这样我们在调用的时候如果只传递参数x也可以打印出world,y参数被赋予了默认值。es6中,在函数定义的时候,允许在参数中直接赋予默认值。

function log(x, y = 'World') {
  console.log(x, y);
}

这样实现的效果是一样的,这样的语法解构,使得代码有了更强的可读性。后续开发和维护的人员可以很容易的看到哪些参数是有默认值的,而且也知道默认值是什么。

函数的参数是默认声明的,所以在函数体内不能使用let或者const来再次声明变量。

function foo(x = 5) {
  let x = 1; // error
  const x = 2; // error
  var x = 3; //right
}

而且在使用默认值的时候,参数是不可以重复的。

// 不报错
function foo(x, x, y) {
  // ...
}

// 报错
function foo(x, x, y = 1) {
  // ...
}

其实我们可以理解为在es6的默认值函数中,变量是通过let或者const声明过的,所以当我们再次声明的时候就会报错。

参数默认值并不是单纯的传递值,其实是每次调用都会重新计算默认值的值,也就是所谓的惰性求值。默认值可以设为一个表达式

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

foo() // 100
x = 101;
foo() // 102

上面的例子中调用p默认值的时候是先计算x+1,然后再传递给p,也只有在调用的时候才会执行x+1。你会发现默认值既然是一个计算过程,如果传递的是个对象,然后对改对象做相应的映射处理,是不是也可以?没错,这就是解构赋值相结合的默认值问题。我们传递对象的时候,在默认值的表达式中完成解构赋值,是完全可以的。

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() // TypeError: Cannot read property 'x' of undefined

上面的例子中,传递对象的时候,函数对传递的参数进行了解构,传递对象中的y默认值设为5,但是并没有对参数设默认值,所以单纯的使用函数foo()还是会报错。如果我们提供参数的默认值

function foo({x, y = 5} = {}) {
  console.log(x, y);
}

这样就算不传默认对象,也不会出错。

对于默认值的声明,一般在函数的定义中,有默认值的参数要写在函数的尾参数,如果默认值的位置不是尾参数,在调用函数的时候,如果想传递后面的参数,那么这个有默认值的中间参数是不可以省略的。

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]

2、函数长度问题

函数的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

3、函数的作用域问题

一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域。等到初始化结束,这个作用域就会消失。这种语法行为,在不设置参数默认值时,是不会出现的。

var x = 1;

function f(x, y = x) {
  console.log(y);
}

f(2) // 2

在调用函数的时候y=x中x是第一个参数x,

let x = 1;

function f(y = x) {
  let x = 2;
  console.log(y);
}

f() // 1

上面的例子中,y=x,x在函数作用域内是不存在的,所以指向外层x=1。但是如果像上面的例子那样,如果x不存在,就会报错。

var x = 1;

function foo(x = x) {
  // ...
}

foo() // ReferenceError: x is not defined

上面的例子中,因为单独作用于的问题,let x=x,因为暂时性死区的问题,会报错。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值