1 函数参数的默认值
ES6函数允许将函数参数默认值写在参数定义后面。
1.1 优点:
1)在不看文档和函数体的情况,开发人员知道哪些参数是可以省略的;
2)方便以后代码优化,去掉这个参数也不影响代码运行;
1.2 基本用法
1)参数变量是默认声明的,不需要使用const或let声明参数变量;
var fn = function(x, y = 0) {
const x = 2;
console.log(x + y);
}
fn(1); // Uncaught SyntaxError: Identifier 'x' has already been declared
2) 具有默认值参数的函数,该函数不能有同名参数
function fn(x, x, y) {
console.log(x + x + y);
}
// 报错:Uncaught SyntaxError: Duplicate parameter name not allowed in this context
function fn(x, x, y = 0) {
console.log(x + y);
}
fn(1, 2, 3);
fn(1, 2);
3)只有传入的参数值为undefined,该参数的默认值(如果有)才能生效
var fn = function(x, y = 'world') {
console.log(x + y);
}
fn(); // undefined 'world'
fn('Hello'); // Hello world,第二个参数不传,默认传入undefined
fn('Hello', undefined); // Hello world
fn('Hello', 'China'); // Hello China
fn('Hello', ''); // Hello
fn('Hello', null); // Hello null
4)函数参数默认值不是传值,而是每次调用时重新计算,即惰性求值
let a = 1;
function fn(x = a + 1) {
console.log(x + x);
}
fn(); // 4
a = 2;
fn(); // 6
1.3 与解构赋值一起使用
1)只有当函数fn的参数是一个对象时,变量x和y才会通过解构赋值生成。如果函数fn调用时没提供参数,变量x和y就不会生成,从而报错。
在这种情况下,如果不传入一个对象参数,解构赋值失败,报错。
function fn({x, y = 2}) {
console.log(x + y);
}
fn(); // example-1.html:12 Uncaught TypeError: Cannot destructure property `x` of 'undefined' or 'null'.
fn({x: 1}); // 3
fn({x: 1, y: 3}); // 4
2)通过提供函数参数的默认值,就可以避免上面的情况。
该情况下,参数解构赋值成功,不会报错。
function fn({x, y = 2} = {}) {
console.log(x, y);
}
fn(); // undefined 2
// 1
function fetch(url, {type, header, data}) {
console.log(url);
}
fetch('http://api.com/getUserInfo'); // 报错:Uncaught TypeError: Cannot destructure property `type` of 'undefined' or 'null'.
fetch('http://api.com/getUserInfo', {}); // http://api.com/getUserInfo
// 2
function fetch(url, {type, header, data} = {}) {
console.log(url);
}
fetch('http://api.com/getUserInfo'); // http://api.com/getUserInfo
// 3
function fetch(url, {type, header, data} = {type: 'post'}) {
console.log(url, type);
}
fetch('http://api.com/getUserInfo'); // http://api.com/getUserInfo post
fetch('http://api.com/getUserInfo', {}); // http://api.com/getUserInfo undefined
// 4
function fetch(url, {type = 'post', header, data} = {}) {
console.log(url, type);
}
fetch('http://api.com/getUserInfo'); // http://api.com/getUserInfo post
fetch('http://api.com/getUserInfo', {}); // http://api.com/getUserInfo post
1.4 参数默认值的位置
1)函数的尾参数有默认值-该参数可以省略
function fn(x, y = 1) {
console.log(x, y);
}
fn(); // undefined 1
fn(10); // 10 1
fn(10, 20); // 10 20
2)函数的非尾参数有默认值-该参数不能省略
function fn(x = 1, y) {
console.log(x, y);
}
fn(10); // 10 undefined
fn(10, 20); // 10 20
fn(, 20); // 报错:Uncaught SyntaxError: Unexpected token ,
function fn(x, y = 1, z) {
console.log(x, y, z);
}
fn(); // undefined 1 undefined
fn(1, 10); // 1 10 undefined
fn(10, , 20); // 报错:Uncaught SyntaxError: Unexpected token ,
fn(10, undefined, 20); // 10 1 20
1.5 函数的length属性
函数的length属性主要记录函数的参数个数,其中不包含有默认值的参数。
function fn1(x, y) {}
function fn2(x, y = 1) {}
console.log(fn1.length); // 2
console.log(fn2.length); // 1
1.6 函数参数的作用域
一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域(context)。等到初始化结束,这个作用域就会消失。这种语法行为,在不设置参数默认值时,是不会出现的。
let x = 1;
function fn(x, y = x) {
console.log(x, y);
}
fn(2); // 2 2
在函数初始化时,参数形成一个作用域,参数变量y使用的是第一个参数x进行赋值,而不是全局变量x进行赋值。
let x = 1;
function fn(y = x) {
console.log(y);
}
fn(); // 1
参数作用域没有x,则从全局变量中找x变量进行赋值。如果全局变量x不存则会报错。
1.7 应用
1)不可省略参数
function missingErr() {
throw new Error('missing parameter');
}
function fn(arg1 = missingErr()) {
console.log(arg1);
}
fn(123); // 123
fn(); // error: missing parameter
2) 可省略参数
function fn(arg1 = undefined) {
console.log(arg1);
}
fn();
2 rest参数
用来获取函数的剩余参数,是一个数组,可以用来替代arguments。
语法:...变量名
function fn(x, ...rest) {
let b = 0;
for(var i = 0; i < rest.length; i++) {
b = b + rest[i];
}
console.log(x, b);
}
fn('剩余变量:', 1, 2, 3, 4); // 剩余变量:10
剩余参数变量和arguments的却别:
- rest是真正的数组,而arguments是伪数组,不能调用某些数组的方法;
- rest参数变量后面不能再有其他的参数变量,否则报错;
- rest参数变量不包含在函数的length属性里;
// arguments变量的写法:使用数组的slice方法将arguments转为真正数组,才能调用数组的sort方法
function sortNumbers() {
return Array.prototype.slice.call(arguments).sort();
}
// rest参数的写法:简洁
const sortNumbers = (...numbers) => numbers.sort();
3 箭头函数-Arrow Function
3.1 检测浏览器是否支持箭头函数
'use strict';
var test => console.log('您的浏览器支持箭头函数;');
3.2 函数形式
1)简略模式
只有一个表达式,没有{...}和return语句,默认返回表达式的结果。
var fn = x => x*x;
fn(2); // 4
2)多语句
不能省略{...},且必须有return语句。
var fn = flag => {
if (flag) {
return true;
} else {
return false;
}
}
3)简略模式:返回一个对象
这种情况下应用圆括号包住,以区别函数体。
var fn = x => ({foo: x})
var fn = x => {foo: x} // 当成一条执行语句执行,没有返回
3.3 函数参数
// 1、无参数:用圆括号表示
var fn1 = () => {
console.log('您的浏览器支持箭头函数!');
};
// 2、一个参数:可以省去圆括号
var fn2 = (x) => x*x;
// 或
var fn2 = x => x*x;
// 3、多个参数:必须用圆括号
var fn3 = (x, y) => x*y;
3.4 箭头函数和匿名函数的区别
箭头函数的this总是指向词法作用域,即指向外层调用对象。
var person = {
birth: 1991,
getAge: function() {
var age = () => new Date().getFullYear() - this.birth;
return age();
}
}
console.log(person.getAge()); // 27
因此,call和apply调用箭头函数时,无法绑定this,传入的第一个参数会被忽略。
var person = {
birth: 1991,
getAge: function() {
var age = () => new Date().getFullYear() - this.birth;
// 使用call或apply改变this作用域
return age.call({birth: 1990}, 1);
}
}
console.log(person.getAge()); // 27
var arr = [32, 3, 10, 13];
arr.sort((x, y) => {
return x - y;
});
console.log(arr) // 3, 10, 13, 32
3.5 注意事项
- 箭头函数的this对象是定义时所在的对象,而不是使用时所在的对象;
- 箭头函数不能当构造函数使用;
- 箭头函数没有arguments对象,使用rest变量代替;
- 箭头函数的this对象的指向是固定的;
参考
1、阮一峰-ES6-函数的扩展;
2、廖雪峰-箭头函数;