ECMAScript6之函数的扩展
作者:互联网
ECMAScript6之函数的扩展
1. 函数参数的默认值
ES6之前为函数参数设置默认值,需要使用变通的方法才能实现。
function add(x, y) {
x = x || 1;
y = y || 2;
return x+y;
}
// 使用参数默认值参与运算
add(); // 3
add(2); // 4
ES6 允许为函数的参数设置默认值,可以直接写在参数定义的后面。
function add(x=1, y =2) {
return x + y;
}
add(); // 3
给函数参数设置默认值时,函数不能有同名参数。
// 给函数参数设置默认值时,不能包含同名参数
function add (x = 1, x = 3, y = 1) {} // SyntaxError: Duplicate parameter name not allowed in this context
function add (x, x, y = 2) {} // SyntaxError: Duplicate parameter name not allowed in this context
函数参数默认值可以是表达式,也可以调用对象属性。但是参数默认值是惰性求值的,只有使用的时候才会求值。
let person = {
name: 'jidi',
age: 22,
sex: 1
}
let x = 12;
function printStr(y = x + 1, z = person) {
console.log(y + z.age);
}
// 函数参数默认值时惰性求值的
printStr(); // 35
printStr(1); // 23
1.1 函数参数默认值与解构赋值结合使用
函数参数可以进行解构赋值,解构赋值默认值与函数参数默认值可以结合使用。
// 单独使用解构赋值默认值
function printStr ({x, y = 5}) {
console.info(x, y);
}
// 不提供参数,参数x和y不会通过解构赋值产生,从而报错
printStr(); // TypeError: Cannot destructure property 'x' of 'undefined' as it is undefined.
printStr({x:1}); // 1 5
printStr({}); // undefined 5
printStr({X:1, y:2}); // 1 2
在上面代码中,只使用了对象的解构赋值默认值,只有当函数printStr
的参数是一个对象时,变量x
和y
才会通过解构赋值生成。如果函数printStr
调用时没提供参数,变量x
和y
就不会生成,从而报错。
// 解构赋值默认值与函数参数默认值结合使用
function printStr({x = 1 , y = 2 } = {}) {
console.info(x, y);
}
// 不添加参数,正常使用
printStr(); // 1 2
上面代码中,给函数参数设置了默认值,函数调用时不添加参数,会调用默认值进行解构赋值。
下面是一个更明显的例子。
// 解构赋值设置默认值,函数参数默认值为{}
function m1 ({x = 0, y = 0} = {}) {
return [x, y];
}
// 解构赋值没有设置默认值,函数参数设置默认值为一个对象
function m2 ({ x, y } = { x:1, y: 2 }) {
return [x, y];
}
// 参数都为空
m1(); // [0, 0]
m2(); // [1, 2]
// x 和 y 都有值的情况
m1({x: 2, y: 4}) // [2, 4]
m2({x: 2, y: 4}) // [2, 4]
// x 有值,y 无值的情况
m1({x: 8}) // [8, 0]
m2({x: 3}) // [3, undefined]
// x 和 y 都无值的情况
m1({}) // [0, 0];
m2({}) // [undefined, undefined]
在上面例子中,m1
设置了对象解构赋值默认值,函数参数默认值为空对象,不管函数调用时是否设置了参数,解构赋值都会发生,且会根据实际情况取到值,如果解构失败会使用解构赋值默认值;m2
只设置了函数参数默认值,没有设置对象解构赋值默认值,当函数调用时,如果函数有参数,则会根据实际情况进行解构,由于解构没有设置默认值,解构不成功,变量值会变为undefined
。
1.2 函数参数默认值的位置
一般来说定义了默认值的参数是函数的尾参数。如果非尾部的参数设置默认值,实际上这个参数是没法省略的,除非用undefined
占位。
function f(x = 1, y) {
return [x, y];
}
f(); // [1, undefined]
f(2); // [2, undefined])
// 省略设置了默认值的参数,报错
f(, 1); // Uncaught SyntaxError: Unexpected token ','
// 要能正确调用,必须显示的用undefined占位
f(undefined, 1) // [1, 1]
1.3 函数的 length 属性
函数参数指定了默认值后,函数的length
属性,将返回没有指定默认值的参数个数。这是因为length
属性的含义是,该函数预期传入的参数个数。
// 设置默认值后,预期传入的参数个数会与实际参数个数不一致
(function (x) {}).length; // 1
(function (x = 5) {}).length; // 0
(function (x, y, z = 5) {}).length; // 2
1.4 作用域
一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域。等到初始化结束,这个作用域就会消失。
var x = 1;
function test(x, y = x) {
console.log(y);
}
test(2); // 2
上面代码,函数test
调用时,参数形成一个单独的作用域,在此作用域里面,默认值变量x
指向第一个参数x
,并不会指向全局变量x
,所以输出结果为2
。
var x = 1;
function test(y = x) {
let x = 2;
console.log(y);
}
test(); // 1
上面代码,函数test
调用时,参数形成一个单独的作用域,在此作用域里面,默认值变量x
没有被定义,此时指向全局变量x
,而函数内部的局部变量x
不会影响默认值变量x
,所以输出结果为1
。
2. rest 参数
ES6 引入 rest
参数(形式为...
),用于获取函数的多余参数。
function add(...values) {
let total= 0;
for (let value of values) {
total+= value;
}
return total;
}
add(1, 2, 3); // 6
rest 参数是一个真正的数组,数组特有的方法都可以使用。
function printStr(...items) {
items.forEach((item) => {
console.log(item);
});
}
printStr(1, 2, 3); // 1 2 3
rest 参数之后只能是最后一个参数,否则会报错。
function f(x, ...y, z) { } // Uncaught SyntaxError: Rest parameter must be last formal parameter
函数的length
属性,不包括 rest 参数。
(function(...x) {}).length; // 0
3. 严格模式
从 ES5 开始,函数内部就可以设定严格模式。但是ES2016 做了一点修改,规定只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。
// 函数参数使用默认值,内部再使用严格模式会报错 Uncaught SyntaxError: Illegal 'use strict' directive in function with non-simple parameter list
function test(x, y = x) {
'use strict';
}
// 函数参数使用默认值,内部再使用严格模式会报错
function test ({x, y}) {
'use strict';
};
// 函数参数使用扩展运算符,内部再使用严格模式会报错
function test (...a) => {
'use strict';
};
4. 箭头函数
ES6 允许使用“箭头”(=>
)定义函数。
var f = function(x) {
return x;
}
// 上面例子用箭头函数可以改写成下面样子
var f = x => x;
如果函数没有参数或者有多个参数,需要使用圆括号。
// 没有参数
var f = () => "jidi";
// 等价于
var f = function() {
return "jidi";
}
// 有多个参数
var f = (x, y) => x + y;
// 等价于
var f = function (x, y) {
return x + y;
}
如果箭头函数的代码块部分多于一条语句,就要使用大括号({}
)将它们括起来,并且使用return
语句返回。
var sum = (x, y) => { return x + y; }
如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错。
// 返回的如果是对象,需要在对象外面加括号,否则报错。
let getPerson = id => { id: id, name: "jidi" }; // Uncaught SyntaxError: Unexpected token ':'
// 加括号,不报错
let getPerson = id => ({ id: id, name: "jidi" });
getPerson(1); // {id: 1, name: "jidi"}
箭头函数可以与变量解构结合使用。
// 使用解构赋值的箭头函数
const getStr= ({ name = "jidi", age = 22 } = {}) => name+ ' ' + age;
// 等同于
function getStr({ name = "jidi", age = 22 } = {}) {
return name+ ' ' + age;
}
getStr(); // "jidi 22"
getStr({name: "java", age: 20}); // "java 20"
箭头函数可以与rest 参数结合使用。
const numbers = (...number) => number;
// rest参数是数组,结果返回数组
numbers(1, 2, 3, 4, 5); // [1,2,3,4,5]
// 使用箭头函数和rest参数计算n个数之和
const add = (...items) => {
let total = 0;
items.forEach(item => total += item)
return total;
}
add(1, 2, 3); // 6
4.1 箭头函数使用注意点
箭头函数虽然使用起来更加方便,但是也有一些需要值的注意的地方。
- 函数体内的
this
对象,就是函数定义时所在的对象,而不是使用时所在对象。 - 不可以当做构造函数使用,即不能使用
new
命令。 - 不可以使用
arguments
对象,因为在箭头函数内部,该对象是不存在的,可以用rest
参数进行替代。 - 不可以使用
yield
命令,则箭头函数不能用作 Generator 函数。
this
对象的指向是可变的,但是在箭头函数中,它是固定的。
var id = 21;
// 箭头函数形式
function f1() {
setTimeout(() => {
console.log('id:', this.id);
}, 100);
}
f1(); // id: 21
f1.call({ id: 42 }); // id: 42
// 普通函数形式
function f2() {
setTimeout(function() {
console.log('id:', this.id);
}, 100);
}
f2(); // id: 21
f2.call({ id: 42 }); // id: 21
上面代码中,setTimeout的
参数是一个箭头函数,这个箭头函数的定义生效是在f1
函数生成时,箭头函数导致this
总是指向函数定义生效时所在的对象,所以输出的是42。而普通函数,执行时this
指向全局对象,这时应该输出21。
this
指向的固定,实际是箭头函数没有自己的this
,导致内部的this
就是外层代码块的this
。所以上面的例子中的代码如果转换成ES5代码,就是下面形式。
// ES6
function f1() {
setTimeout(() => {
console.log('id:', this.id);
}, 100);
}
// ES5
function f1() {
var _this = this;
setTimeout(() => {
console.log('id:', _this.id);
}, 100);
}
除了this
,arguments
、super
、new.target
三个变量在箭头函数之中也是不存在的,也指向外层函数的对应变量。
function f() {
setTimeout(() => {
console.log('arguments:', arguments);
}, 100);
}
f(2, 4, 6, 8); // arguments: [2, 4, 6, 8]
上面的例子中,箭头函数内部的srguments
变量指向的是外层函数f
的变量arguments
。
由于箭头函数没有自己的this
,所以也不能用call()
、apply()
、bind()
这些方法去改变this的指向。
4.2 箭头函数不适用场合
箭头函数能够固定this
,所有有两个地方不能用箭头函数。
- 定义对象的方法,且对象方法内部包含
this
。 - 需要动态使用
this
的时候,也不能使用箭头函数。
5. 函数参数的尾逗号
ES2017 允许函数的最后一个参数有尾逗号。
// ES2017允许函数参数后面跟逗号
function add(x, y,) {
return x + y;
}
6. Function.prototype.toString()
ES2019 对函数实例的toString()
方法做出了修改。之前toString()
方法会返回省略了注释和空格的函数代码,修改后的toStirng()
方法,规定返回一模一样的代码。
function add(...items) {
// 求和函数
let total = 0;
items.forEach(item => total += item);
return total;
}
add.toString(); // "function add(...items) {
// // 求和函数
// let total = 0;
// items.forEach(item => total += item);
// return total;
// }"
7. catch 命令的参数省略
try...catch
结构,以前要求catch
命令后面必须跟参数,接受try
代码块抛出的错误对象。ES2019 做出了改变,允许catch
语句省略参数。
8. 参考链接
本篇博文是我自己学习笔记,原文请参考:ECMAScript 6 入门
如有问题,请及时指出!
欢迎沟通交流,邮箱:jidi_jidi@163.com。
标签:ECMAScript6,function,函数,扩展,解构,函数参数,参数,默认值 来源: https://blog.csdn.net/qq_41863849/article/details/104517904