ES6学习笔记(二)——函数的扩展

这篇博客介绍了ES6中函数的扩展特性,包括参数默认值的设置及其与解构赋值的结合,强调了默认参数的位置与length属性的变化。此外,讲解了rest参数的使用,函数的严格模式,name属性,以及箭头函数的特性和应用场景,特别指出箭头函数的this指向和不能作为构造函数等问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

预备知识


ES6函数的扩展

1.函数参数的默认值

ES6之前不能直接对函数的参数指定默认值。对参数y赋值:

y = y || expression

但是如果expression的结果为false,该赋值不起作用。为了避免这个问题,可以先判断参数y是否赋值了

if (typeof y === 'undefined') {
  y = 'World';
}

ES6允许直接在参数定义时,给参数赋默认值

function fun(x, y = 'hello'){
...
}

[Note]

  • 参数变量是默认声明的,所以不能用let或const再次声明。
  • 使用参数默认值时,函数不能有同名参数。
  • 参数默认值不是传值的,而是每次都重新计算默认值表达式的值。也就是说,参数默认值是惰性求值的。
function foo(x = 5) {
  let x = 1; // error
  const x = 2; // error
}

// 不报错
function foo(x, x, y) {
  // ...
}

// 报错
function foo(x, x, y = 1) {
  // ...
}
// SyntaxError: Duplicate parameter name not allowed in this context

let x = 99;
function foo(p = x + 1) {
  console.log(p);
}

foo() // 100

x = 100;
foo() // 101

与解构赋值默认值结合使用(待补充)

默认参数的位置

一般有默认值的参数放在参数中的尾部。如果不在尾部,要传入该参数的默认值,需要在此位置显示传入undefined

function f(x, y = 5, z) {
  return [x, y, z];
}

f() // [undefined, 5, undefined]
f(1) // [1, 5, undefined]
f(1, ,2) // 报错
f(1, undefined, 2) // [1, 5, 2]
函数的length属性

指定了默认值以后,函数的length属性,将返回没有指定默认值的参数个数。也就是说,指定了默认值后,length属性将失真。
这是因为length属性的含义是,该函数预期传入的参数个数。某个参数指定默认值以后,预期传入的参数个数就不包括这个参数了。同理,后文的 rest 参数也不会计入length属性。

(function(...args) {}).length // 0

如果设置了默认值的参数不是尾参数,那么length属性也不再计入后面的参数了。

(function (a = 0, b, c) {}).length // 0
(function (a, b = 1, c) {}).length // 1

作用域

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

var x = 1;

function f(x, y = x) {
  console.log(y);
}

f(2) // 2

这里写图片描述

let x = 1;

function f(y = x) {
  let x = 2;
  console.log(y);
}

f() // 1

这里写图片描述
如果参数的默认值是一个函数,该函数的作用域也遵守这个规则。

let foo = 'outer';

function bar(func = () => foo) {
  let foo = 'inner';
  console.log(func());
}

bar(); // outer

这里写图片描述

var x = 1;
function foo(x, y = function() { x = 2; }) {
  var x = 3;
  y();
  console.log(x);
}

foo() // 3
x // 1

这里写图片描述

var x = 1;
function foo(x, y = function() { x = 2; }) {
  x = 3;
  y();
  console.log(x);
}

foo() // 2
x // 1

这里写图片描述


2.rest参数

syntax:
…variableName
e.g.

function add(...values) {
  let sum = 0;

  for (var val of values) {
    sum += val;
  }

  return sum;
}

add(2, 5, 3) // 10

[Note]

  • rest参数之后不能再有其他参数。
  • 函数的length属性不包括rest参数。

3.严格模式

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


4.name属性

返回该函数的实际函数名。

function foo() {}
foo.name // "foo"

var f = function () {};
// f是一个匿名函数
// ES5
f.name // ""

// ES6
f.name // "f"

Function构造函数返回的函数实例,name属性值为anonymous。

(new Function).name // "anonymous"

bind返回的函数,name属性值会加上bound前缀。

function foo() {};
foo.bind({}).name // "bound foo"

(function(){}).bind({}).name // "bound "

5.箭头函数

使用箭头(=>)定义函数,var f = v => v;等价于

var f = function(v){
  return v;
}

箭头函数可以与变量解构结合使用

 const full = ({ first, last }) => first + ' ' + last;

// 等同于
function full(person) {
  return person.first + ' ' + person.last;
}

简化回调函数

// 正常函数写法
[1,2,3].map(function (x) {
  return x * x;
});

// 箭头函数写法
[1,2,3].map(x => x * x);

[Note]箭头函数

  • 函数体内this对象指向定义时所在的对象
  • 不可以当做构造函数(不能使用new命令)
  • 不可以使用arguments对象
  • 不可以使用yield命令
function foo() {
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
}

var id = 21;

foo.call({ id: 42 });
// id: 42

上面例子中,setTimeout的参数是一个箭头函数,这个箭头函数定义生效是在foo函数生成时,所以箭头函数里面的this指向foo对象。如果是setTimeout的参数是普通函数,真正执行的时候应该在100毫秒之后,this指向全局对象window。
箭头函数可以让setTimeout里面的this,绑定定义时所在的作用域。

function Timer() {
  this.s1 = 0;
  this.s2 = 0;
  // 箭头函数 this绑定Timer函数
  setInterval(() => this.s1++, 1000);
  // 普通函数 this指向运行时的作用域(全局对象)
  setInterval(function () {
    this.s2++;
  }, 1000);
}

var timer = new Timer();

setTimeout(() => console.log('s1: ', timer.s1), 4100);
setTimeout(() => console.log('s2: ', timer.s2), 3100);
// 注意s2会比s1先被打印出来
// s2: 0
// s1: 4

为什么箭头函数的this会绑定定义时所在的对象呢?因为它根本没有自己的this,而是引用外层的this o( ̄︶ ̄)o

// ES6
function foo() {
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
}

// ES5
function foo() {
  var _this = this;

  setTimeout(function () {
    console.log('id:', _this.id);
  }, 100);
}

除了this,箭头函数中也不存在arguments、super、new.target,使用的时候,指向的是外层函数对应变量。
因为没有自己的this,不能用call()、apply()、bind()这些方法去改变this指向。

未完待续。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值