乐趣区

es6函数

函数形参的默认值

在 es5 中实现默认参数功能

function makeRequest(url,timeout,callback){
    timeout = timeout || 2000;
    callback = callback || function(){ ...}
    ...
}

这里有个问题,当 timeout 传入的值为 0 时,这个值是合法的,但也会被置位 2000,因为 0 代表 false。
继续优化我们上面的方法:

function makeRequest(url,timeout,callback){timeout = (typeof timeout !== 'undefined') ? timeout : 2000;
    callback = (typeof callback !== 'undefined') ? callback : function(){ ...}
    ...
}

尽管这种方法已经安全的实现了配置参数默认值,但是需要额外的代码来执行这种非常基础的操作。不够简洁!

es6 中的默认参数值

直接上代码:

function makeRequest(url,timeout = 2000,callback = function(){}){...}

只需在声明函数的形参名称后面通过 ”=” 赋予默认值即可。可以为任意参数指定默认值,在已指定默认值的参数后可以继续声明无默认值参数。
tips:null 是一个合法值,因此给带有默认值的参数传递 null 值,该参数的值会设置为 null,可简单理解为只有该参数为对应的值为 nundefined 时,参数的默认值才会生效

默认参数表达式

除了原始类型的值可以作为参数默认值外,非原始值也可以作为参数的默认值:

function getValue(){return 5;}
function add(first,second = getValue()){return first + second;}

console.log(add(1,1));  //2
console.log(add(1));    //6

tips:初次解析函数声明时不会调用 getValue()方法,只有当调用 add()函数且不传入第二个参数时才会调用。

正因为默认参数是在函数调用时求值,所以可以使用先定义的参数作为后定义参数的默认值(因为在声明函数时,先定义的参数已经被声明)

function add(first,second = first){return first + second;}

console.log(add(1,1)); //2
console.log(add(1));   //2

tips:在引用参数默认值的时候,只允许引用前面参数的值,即先定义的参数不能访问后定义的参数:function add(first=second,second) 这样是会报错误的

处理无命名参数

产生无命名参数的情况:js 函数语法规定,无论函数已定义的命名参数有多少,都不限制调用时传入的实际参数数量。

es5 中的无命名参数

通过 arguments 来操作:

function (arg1){for(let i=1,len=arguments.length;i<len;i++){// 第一个是命名参数,要获取未命名参数需要从 arguments[1]开始
        process(arguments[i])
    }
}

这样可以实现处理多个未命名参数的要求,但是存在几个缺点:

  1. 并不容易发现这个函数可以接受任意数量的参数
  2. 因为第一个参数为命名参数,所以获取未命名参数的索引位置应该从 1 开始。当遇到函数有 2 个,3 个,4 个 …. 命名参数时,再处理未命名参数就会疲于计算索引开始位置,显得不灵活

es6 的不定参数

es6 中,在函数的命名参数前添加三个点(…),就表明这是一个不定参数,改参数为一个数组,包含着自它之后传入的所有参数。

function (...arg){for(let i=0,len=arg.length;i<len;i++){process(arg[i]);
    }
}

不定参数的使用限制

  1. 每个函数最多只能声明一个不定参数,而且一定要放在所有参数的末尾
  2. 不定参数不能用于对象字面量 setter 中,会导致语法错误,例:
let obj={set name(...value){...}
}


之所以报错是因为 setter 的参数只能有一个

展开运算符

展开运算符与不定参数很相似。
不定参数可以让你指定多个各自独立的参数,并通过整合后的数组来访问;而展开运算符可以让你指定一个数组,将他们打散后作为各自独立的参数传入函数。

例如有一个需求需要你在一个数组中找出最大的那个数,es5 只能用如下方式实现

let values=[25,50,75,100];
console.log(Math.max.apply(Math,values));  // 因为 Math.max 方法不支持接收数组参数,所以只能通过 apply 的方式来变通解决这个问题

es6 解决办法:

let values=[25,50,75,100];
console.log(Math.max(...values));  // 简单明了

tips:可以将展开运算符与其它正常传入的参数混合使用:console.log(Math.max(…values,2,55,77));

箭头函数

箭头函数对比普通函数:

  • 没有 this,super,arguments 和 new.target 绑定,箭头函数中的这些值由外围最近一层非箭头函数决定
  • 不能通过 new 关键字调用。箭头函数没有 [[construct]] 方法,所以不能被用作构造函数,通过 new 关键字调用箭头函数,程序会抛出错误
  • 没有原型。因为不可以通过 new 调用箭头函数,因此没有构建原型的需求,所以箭头函数不存在 prototype 这个属性
  • 不可以改变 this 绑定
  • 不支持 arguments 对象,必须通过命名参数和不定参数这两种形式访问函数的参数
  • 不支持重复的命名参数

箭头函数语法

let reflect = value => value;   // 只有一个参数时可以直接写参数名
let reflect = (value1,value2) => value1 + value2; // 有两个参数时需要给参数加小括号
let reflect = () => 5;  // 没有参数时需要一对空的小括号
let reflect = () => {process1();
    process2();
    ...
    return 5; // 当函数体有多条语句时需要花括号包含,如果有返回值,需要显式地 return , 函数体只有一条语句时,该语句的执行结果就是默认的返回值
}
let reflect = () => ({name:'zj',age:18});  // 当需要 return 一个对象字面量时需要添加 (),已指明这是返回值,而不是函数体  {} 的原因
let reflect = ((name) => name;)('zj');   // 立即执行函数表达式 
退出移动版