ES6学习笔记(五)-- 函数的扩展

前言

ES6为我们在函数的使用上也提供了许多的便捷的东西,这里只阐述一部分,详情请参考官方文档。
1.函数参数的默认值
2.rest 参数
3.箭头函数(重点:this的指向问题)


一、函数参数的默认值

ES6 之前,不能直接为函数的参数指定默认值。而 ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面。

function log(x = 'Hello', y = 'World') {
  console.log(x, y);
}
log() // Hello World
log('Hello', 'China') // Hello China
log('Hi', '') // Hi 

length属性(直接获取所需传递的参数(是必须传递的参数),如果参数有默认值,则不会被计算)

function add(a,b = 1){
    return a+b
}
console.log(add.length); // 1 , b有默认值,所以必须传递的只有a一个参数

二、rest 参数

ES6 引入 rest 参数(形式为…变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。
注意:rest 参数之后不能再有其他参数(即只能是最后一个参数,否则会报错。

function add(a, ...values) {
    let sum = 0;
    console.log(a); // 2
    console.log(values); // [5, 3] , 剩余的参数会被放到数组之中
    sum += a
    for (var val of values) {
        sum += val;
    }
    return sum;
}
console.log(add(2, 5, 3)); // 10

三、箭头函数

1.基本用法
(1)简化定义函数
var f = v => v;
// 等同于
var f = function (v) { return v; };
-----------------------------------------
var f = () => 5; // 如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分。
// 等同于
var f = function () { return 5 };
------------------------------------------
var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
  return num1 + num2;
};

由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错。

// 报错
let getTempItem = id => { id: id, name: "Temp" };
// 不报错
let getTempItem = id => ({ id: id, name: "Temp" });
(2) 可以和变量解构结合使用
const fullName = ({ firstName, lastName }) => firstName + ' ' + lastName ;
// 等同于
function fullName (person) {
  return person.firstName + ' ' + person.lastName ;
}
(3) 简化回调函数
// 正常函数写法
[1,2,3].map(function (x) {
  return x * x;
});
// 箭头函数写法
[1,2,3].map(x => x * x);

// 正常函数写法
var result = values.sort(function (a, b) {
  return a - b;
});
// 箭头函数写法
var result = values.sort((a, b) => a - b);
2.使用注意点

箭头函数有几个使用注意点。

(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
( 简单点说就是:
————> 如果箭头函数被一个函数或类包裹着,那他的this就是其包裹着它的函数或类的this;
————> 如果箭头函数外部没有函数包裹,则this指向window。 )

(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。

(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。

(4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数。

上面四点中,第一点尤其值得注意。this对象的指向是可变的,但是在箭头函数中,它是固定的

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

上面代码中,setTimeout的参数是一个箭头函数,这个箭头函数的定义生效是在foo函数生成时,而它的真正执行要等到 100 毫秒后。如果是普通函数,执行时this应该指向全局对象window,这时应该输出21。但是,箭头函数导致this总是指向函数定义生效时所在的对象(本例是{id: 42}),所以输出的是42。

箭头函数可以让函数里面的this,绑定定义时所在的作用域,而不是指向运行时所在的作用域。下面是另一个例子:

function Timer() {
  this.s1 = 0;
  this.s2 = 0;
  // 箭头函数
  setInterval(() => this.s1++, 1000);
  
  // 普通函数 , 没绑定 this,所以s2++ 不生效
  setInterval(function () {
    this.s2++;
  }, 1000);
  // 绑定this之后
  // setInterval((function () {
  //   this.s2++;
  // }).bind(this), 1000);
}
var timer = new Timer();
setTimeout(() => console.log('s1: ', timer.s1), 3100);
setTimeout(() => console.log('s2: ', timer.s2), 3100);
// s1: 3
// s2: 0
// 绑定this之后
// s2: 3

箭头函数可以让this指向固定化,这种特性很有利于封装回调函数。下面是一个例子,DOM 事件的回调函数封装在一个对象里面。

var handler = {
  id: '123456',
  init: function() {
    document.addEventListener('click',
      // this指向handler
      event => this.doSomething(event.type), false);
  },
  doSomething: function(type) {
    console.log('Handling ' + type  + ' for ' + this.id);
  }
};

上面代码的init方法中,使用了箭头函数,这导致这个箭头函数里面的this,总是指向handler对象。否则,回调函数运行时,this.doSomething这一行会报错,因为此时this指向document对象。

3. 箭头函数不适用的场合

由于箭头函数使得this从“动态”变成“静态”,下面两个场合不应该使用箭头函数。

(1)第一个场合是定义对象的方法,且该方法内部包括this。
const cat = {
  lives: 9,
  jumps: () => {
    this.lives--;
  }
}

上面代码中,cat.jumps()方法是一个箭头函数,这是错误的。调用cat.jumps()时,如果是普通函数,该方法内部的this指向cat;如果写成上面那样的箭头函数,使得this指向全局对象,因此不会得到预期结果。这是因为对象不构成单独的作用域,导致jumps箭头函数定义时的作用域就是全局作用域。

(2)第二个场合是需要动态this的时候,也不应使用箭头函数。
var button = document.getElementById('press');
button.addEventListener('click', () => {
  this.classList.toggle('on');
});

上面代码运行时,点击按钮会报错,因为button的监听函数是一个箭头函数,导致里面的this就是全局对象。如果改成普通函数,this就会动态指向被点击的按钮对象。

(3)另外,如果函数体很复杂,有许多行,或者函数内部有大量的读写操作,不单纯是为了计算值,这时也不应该使用箭头函数,而是要使用普通函数,这样可以提高代码可读性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值