ES6 函数参数默认值处理

ES6 新规范中可以给函数的参数指定默认值。
浏览器支持:

//ES5 的一种变通方法
function run(x){
  x = x === undefined ? 0 : x;
  console.log(x)
}
run();            //0
run(false);       //false
run(8);           //8

//ES6 新增
function run(x=0){
  console.log(x)
}
run();               //0
run(false);          //false
run(8);              //8

需要注意的几种情况:

//1.参数变量是默认声明的,所以不能用let或const再次声明。
function foo(x = 5) {
  let x = 1;                        // 报错!
  const x = 2;                      // 报错!
}

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

//3.参数默认值不是传值的,而是每次都重新计算默认值表达式的值。
let x = 99
function foo(p = x + 1) {
  console.log(p);
}
foo();               // 100
x = 100;
foo();               // 101

//4.undefined 会触发该参数取默认值,null 则没有这个效果,
//并且设置了默认值的形参不能传空字符串参数。
function f(x, y = 5, z) {
  return [x, y, z];
}
f();                       // [undefined, 5, undefined]
f(1);                      // [1, 5, undefined]
f(1,undefined,null);       // [1, 5, null]    
f(1,,);                    // 报错!
f(1, ,2);                  // 报错!

//5.指定了默认值以后,函数的length属性,将返回没有指定默认值的参数个数。
//也就是说,指定了默认值后,length属性将失真。
(function(...args) {}).length            // 0
(function (a) {}).length                 // 1
(function (a = 5) {}).length             // 0
(function (a, b, c = 5) {}).length       // 2
(function (a, b, c = 5, d) {}).length    // 2  设置默认值后面的参数不再计入length

与解构赋值默认值结合使用:

//只有当函数 foo 的参数是一个对象时,变量x和y才会通过解构赋值生成
function foo({x, y = 5}) {
  console.log(x, y);
}
foo({x: 1});             // 1 5
foo({x: 1, y: 2});       // 1 2
foo({});                 // undefined 5
foo();                   // 报错! 

//下面代码指定,如果没有提供参数,函数foo的参数默认为一个空对象
function foo({x, y = 5} = {}) {
  console.log(x, y);
}
foo();                   // undefined 5

//以下两种写法都对函数的参数设定了默认值
function m1({x = 0, y = 0} = {}) {            //函数参数的默认值是空对象
  return [x, y];
}
function m2({x, y} = { x: 0, y: 0 }) {        //函数参数的默认值是一个有具体属性的对象
  return [x, y];
}
// 函数没有参数的情况
m1()                  // [0, 0]
m2()                  // [0, 0]
// x 和 y 都有值的情况
m1({x: 3, y: 8})      // [3, 8]
m2({x: 3, y: 8})      // [3, 8]
// x 有值,y 无值的情况
m1({x: 3})            // [3, 0]
m2({x: 3})            // [3, undefined]
// x 和 y 都无值的情况
m1({})                // [0, 0];
m2({})                // [undefined, undefined]
m1({z: 3})            // [0, 0]
m2({z: 3})            // [undefined, undefined]

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

//下例中参数形成一个单独的作用域。y的值x指向第一个参数x,而不是全局变量x
var x = 1;
function f(x, y = x) {    //相当于 let x; let y = x;
  console.log(y);
}                         
f(2)                      // 2
---------------------------------------------------
let x = 1;
function f(y = x) {       //相当于 let y = x;
  let x = 2;
  console.log(y);
}
f();                      // 1
---------------------------------------------------
function f(y = a) {       //相当于 let y = a;    
  let a = 2;
  console.log(y);
}
f();                      //全局变量a不存在,就会报错!
---------------------------------------------------
var x = 1;
function foo(x = x) { } //相当于 let x = x;
foo();                //由于暂时性死区,报错"x 未定义" 
---------------------------------------------------
function bar(run = () => a) {  //相当于 let run = a; 
  let a = 'inner';
  console.log(run());
}
bar()                  // 报错: "a 未定义",参数中的a    
---------------------------------------------------
var x = 1;
function foo(x, y = function() { x = 2; }) {
  var x = 3;
  y();
  console.log(x);
}
foo()        // 3
x            // 1       
/*
以上代码的作用域关系如下, 每一层中变量 x 都是不同的变量
{
  var x = 3;
  {
    let x; let y = function(){ x = 2 }
    {
      var x = 3;    
      y();               //这里执行函数后,上级作用域中的 x 值为2       
      console.log(x);
    }
  }
}
如果将var x = 3的var去除,函数foo的内部变量x就指向匿名函数内部的 x,
那么做货输出就是2,而外层的全局变量x依然不受影响。
*/

应用:利用参数默认值,可以指定某一个参数不得省略,如果省略就抛出一个错误。

//下面代码的foo函数,如果调用的时候没有参数,就会调用默认值errMsg函数,从而抛出一个错误。
function errMsg() {
  throw new Error('Missing parameter');
}
function foo(option = errMsg()) {
  return option;
}
foo()       //Error: Missing parameter

//另外,可以将参数默认值设为undefined,表明这个参数是可以省略的。
function foo(option = undefined) { ··· }

rest 参数
ES6 引入 rest 参数(形式为...变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了。

// arguments变量的写法
function sortNumbers() {
  return Array.prototype.slice.call(arguments).sort();
}
// rest参数的写法
const sortNumbers = (...numbers) => numbers.sort(); 
/*
arguments 对象不是数组,而是一个类似数组的对象。使用Array.prototype.slice.call先将其转为数组。
rest 参数就不存在这个问题,它就是一个真正的数组,数组特有的方法都可以使用。
*/

//另一个 rest参数的写法 的例子
function add(...values) {
  let sum = 0;
  for (var val of values) {
    sum += val;
  }
  return sum;
}
add(2, 5, 3)    // 10

//下面是一个利用 rest 参数改写数组push方法的例子。
function push(array, ...items) {
  items.forEach(function(item) {
    array.push(item);
  });
}
var a = [];
push(a, 1, 2, 3)

//注意,rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错。
function f(a, ...b, c) { }       // 报错!!!

//函数的length属性,不包括 rest 参数。
(function(a) {}).length          // 1
(function(...a) {}).length       // 0
(function(a, ...b) {}).length    // 1

ES6对严格模式的修改,规定只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。

//从 ES5 开始,函数内部可以设定为严格模式。
function doSomething(a, b) {
  'use strict';
  // code
}
-----------------------------------------------------
//ES6 中会报错的几种情况
function doSomething(a, b = a) {              // 报错
  'use strict';
  // code
}

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

const doSomething = (...a) => {               // 报错
  'use strict';
  // code
};
-----------------------------------------------------
//两种方法可以规避这种限制
//1.第一种是设定全局性的严格模式,这是合法的。
'use strict';
function doSomething(a, b = a) {
  // code
}
//2.第二种是把函数包在一个无参数的立即执行函数里面。
const doSomething = (function () {
  'use strict';
  return function(value = 42) {
    return value;
  };
}());
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值