6.函数的扩展
2022年9月29日大约 4 分钟
6.函数的扩展
在ES6之前,不能直接为函数的参数指定默认值,只能采用变通的方法。
ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面
function log(x, y = 'World') {
console.log(x, y);
}
log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello
参数变量是默认声明的,所以不能用let或const再次声明。
function foo(x = 5) {
let x = 1; // error
const x = 2; // error
}
与解构赋值默认值结合使用
参数默认值可以与解构赋值的默认值,结合起来使用。
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
上面代码使用了对象的解构赋值默认值,而没有使用函数参数的默认值。只有当函数foo
的参数是一个对象时,变量x
和y
才会通过解构赋值而生成。如果函数foo
调用时参数不是对象,变量x
和y
就不会生成,从而报错。如果参数对象没有y
属性,y
的默认值5才会生效。
rest参数
ES6 引入 rest 参数(形式为“...变量名”),用于获取函数的多余参数,这样就不需要使用arguments
对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。
严格模式
从ES5开始,函数内部可以设定为严格模式。
《ECMAScript 2016标准》做了一点修改,规定只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。
箭头函数
ES6允许使用箭头=>定义函数
var f = v=>v;
等同于
var f=function(v){
return v
}
使用箭头函数需要注意的是
- 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象
- 不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误
- 不可以使用arguments对象,该对象在函数体内不存在,如果要用,可以用Rest参数代替
- 不可以使用yield命令,因此箭头函数不能用作Genrator函数
绑定 this
箭头函数可以绑定this
对象,大大减少了显式绑定this
对象的写法(call
、apply
、bind
)。但是,箭头函数并不适用于所有场合,所以ES7提出了“函数绑定”(function bind)运算符,用来取代call
、apply
、bind
调用。虽然该语法还是ES7的一个提案,但是Babel转码器已经支持。
// 函数参数的默认值
{
//es5
function log(x, y) {
y = y || 'World';
console.log(x, y);
}
//es6
function log(x, y='world') {
console.log(x, y);
}
log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello World
}
// 作用域
{
let x = 'test';
function test2(x, y = x) {
console.log('作用域', x, y);
}
test2('kill'); // kill kill
let x = 1;
function f(y = x) {
let x = 2;
console.log(y);
}
f() // 1
// 上面代码中,函数f调用时,参数y = x形成一个单独的作用域。这个作用域里面,
// 变量x本身没有定义,所以指向外层的全局变量x。函数调用时,函数体内部的局部变量x影响不到默认值变量x。
// 如果此时,全局变量x不存在,就会报错。
function f(y = x) {
let x = 2;
console.log(y);
}
f() // ReferenceError: x is not defined
var x = 1;
function foo(x = x) {
// ...
}
foo() // ReferenceError: x is not defined
}
// rest 参数(形式为...变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了
// arguments[0]执行method第一个参数:fn, 所以arguments[0]()的意思就是:fn() 。
// 此时, this执向arguments, 当前method调用传人了1个参数, arguments => [0:fn,callee: fn, length: 1]
{
function test3(...arg) {
for (let v of arg) {
console.log('rest', v);
}
}
test3(1, 2, 3, 4, 'a'); // 1 2 3 4 'a'
}
{
console.log(...[1, 2, 4]); // 1 2 4
console.log('a', ...[1, 2, 4]); // 'a' 1 2 4
}
// 箭头函数 this指向定义时的对象
//不能作为构造函数使用
// 没有arguments对象
{
// arrow函数名 v参数 v*2函数体 返回值
let arrow = v => v * 2;
let arrow2 = () => 5;
console.log('arrow', arrow(3));
console.log(arrow2());
// 由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错。
// 报错
let getTempItem = id => { id: id, name: "Temp" };
// 不报错
let getTempItem = id => ({ id: id, name: "Temp" });
}
//伪调用
{
function tail(x) {
console.log('tail', x);
}
function fx(x) {
return tail(x)
}
fx(123); //123
}