写作不易,Star是最大鼓励,感觉写的不错的可以给个Star⭐,请多多指教。本博客的Github地址

[TOC] 箭头函数,就是函数的简写。如果只有一个参数,()可以省,如果只有一个return,{}可以省。 箭头函数作用:定义匿名函数(多数情况下用来定义回调函数)。

特点:

  • 语法简洁;
  • 没有自己的this,箭头函数定义时所处的作用域的this指向就是其this指向;
  • 箭头函数外层有函数,则当前箭头函数的this同外层函数的this指向相同,否则箭头函数的this指向window。

语法:

  • 没有参数: () => console.log('xxxx')
  • 一个参数: a => a + 2
  • 大于一个参数: (a, b) => a + b
  • 函数体不用大括号,默认返回结果
  • 函数体如果有多条语句,需要用{}包围,若有需要返回的内容,需要手动返回(即return 'xxx'😉。
// 普通函数
function name() {}

// 箭头函数,去掉function,加上=>
// 箭头函数是匿名函数
() => {}
1
2
3
4
5
6
let show1 = function () {
    console.log('abc')
}

let show2 = () => {
    console.log('abc')
}

show1(); // 调用函数
show2();

let show4 = function (a) {
    return a * 2
}

let show5 = a => a * 2 // 简洁,类似python lambda 函数

console.log(show4(10));
console.log(show5(10));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

箭头函数this指向

const person = {
    name: 'lisi',
    hobbies: ['Coding', 'Sleeping', 'Reading'],
    sayHobbies() {
        // console.log(this); // person
        // 而forEach中的回调函数既没有通过对象调用,也没有通过call/apply来特意指定this指向,那么this默认是指向window的,严格模式下指向是undefined。
        this.hobbies.forEach(function(hobby) {
            // console.log(this); // Window
            console.log(`${this.name} loves ${hobby}`);
        });
    }
}
// ES5中函数的this指向调用函数时的对象
// 这里sayHobbies函数是person对象调用的,因此sayHobbies函数中的this指向person
person.sayHobbies();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

在ES6之前,我们一般通过保存this指向的方式来解决回调函数中this指向问题。

const person = {
    name: 'lisi',
    hobbies: ['Coding', 'Sleeping', 'Reading'],
    sayHobbies() {
        // console.log(this); // person
        const self = this;
        this.hobbies.forEach(function(hobby) {
            // console.log(this); // Window
            console.log(`${self.name} loves ${hobby}`);
        });
    }
}

person.sayHobbies();
1
2
3
4
5
6
7
8
9
10
11
12
13
14

在ES6中,可以通过箭头函数来解决这个问题。

const person = {
    name: 'lisi',
    hobbies: ['Coding', 'Sleeping', 'Reading'],
    sayHobbies() {
        // console.log(this); // person
        this.hobbies.forEach(hobby => {
            // 改用箭头函数,箭头函数中没有this,其this指向是继承自其父作用域的this。
            // console.log(this); // person
            console.log(`${this.name} loves ${hobby}`);
        });
    }
}
person.sayHobbies();
1
2
3
4
5
6
7
8
9
10
11
12
13
// 箭头函数 this
var name = 'windowName';
const obj = {
    name: 'lisi',
    say() {
        setTimeout(function() {
            console.log(this); // setTimeout中this默认指向window
            console.log('name:', this.name);
        }, 100);
    },
    sayWithThis() { // sayWithThis这里this指向obj
        let that = this; // setTimeout回调取的是sayWithThis里的this指向
        setTimeout(function() {
            console.log('this id:', that.name);
        }, 1000);
    },
    sayWithArrow() { // sayWithArrow这里this指向obj
        setTimeout(() => { // setTimeout箭头函数回调的this取最近一层非箭头函数的this指向
            console.log('array:', this.name);
        }, 1500);
    },
    sayWithGlobalArrow: () => { // 第一层箭头函数的this指向window
        setTimeout(() => {
            console.log('global array:', this.name);
        }, 2000);
    }
};
obj.say(); // name: windowName
obj.sayWithThis(); // this id: lisi
obj.sayWithArrow(); // array: lisi
obj.sayWithGlobalArrow(); // global array: windowName
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

需要注意:箭头函数中的this指向是在函数定义时就确定好的,跟普通函数中this指向需要在函数调用的时候才能确定不一样。 箭头函数应用场景:希望函数绑定其父级作用域的this指向,并且不希望箭头函数在调用时其this指向发生改变。

函数形参默认值

function add(a, b) {
    a = a || 5;
    b = b || 6;
    return a + b;
}

console.log(add()); // 11
console.log(add(1, 2)); // 3
1
2
3
4
5
6
7
8

采用默认参数写法:

function add(a = 5, b = 6) {
    return a + b;
}

console.log(add()); // 11
console.log(add(1, 2)); // 3
1
2
3
4
5
6

第二个参数使用默认值:

function add(a = 5, b = 6) {
    return a + b;
}

console.log(add(1)); // 7
1
2
3
4
5

第一个参数使用默认值:

function add(a = 5, b = 6) {
    return a + b;
}

console.log(add(undefined, 3)); // 8
1
2
3
4
5

这里需要显示指定第一个实参为undefined,才能使第一个参数默认值生效。因此,可以得出ES6中默认参数的实现原理也是运用了typeof a === undefined来判断是否采用默认参数的。

箭头函数不适用场景

  1. 作为构造函数或者一个方法需要绑定到对象。
const Person = (name, age) => {
    this.name = name;
    this.age = age;
}

const person = new Person('lisi', 12); // Uncaught TypeError: Person is not a constructor
1
2
3
4
5
6
const Person = function(name, age) {
    this.name = name;
    this.age = age;
}

const person = new Person('lisi', 12);
// console.log(person); // Person { name: 'lisi', age: 12 }
Person.prototype.sayName = () => {
    // 这里之所以是undefined的原因:箭头函数的this指向是其父作用域的this,在这里是window。
    console.log(this.name); // undefined
};

person.sayName();
1
2
3
4
5
6
7
8
9
10
11
12
13
const Person = function(name, age) {
    this.name = name;
    this.age = age;
}

const person = new Person('lisi', 12);
Person.prototype.sayName = function() {
    console.log(this.name); // lisi
};

person.sayName();
1
2
3
4
5
6
7
8
9
10
11
  1. 需要使用this的时候
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .box {
            width: 100px;
            height: 100px;
            background-color: aquamarine;
        }
        .in {
            transform: scale(2);
        }
    </style>
</head>
<body>
    <div class="box"></div>
    <script>
        const box = document.querySelector('.box');
        box.addEventListener('click', function() { // 这里不能使用箭头函数,会导致this指向window而不是当前点击的box
            this.classList.add('in');
            setTimeout(() => { // 这里需要使用箭头函数,使得this指向其父作用域的this指向即box。不使用箭头函数则指向window。
                this.classList.remove('in');
            }, 2000);
        });
    </script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  1. 需要使用arguments对象
const sum = () => {
    // 箭头函数中没有arguments对象
    return [...arguments].reduce((pre, cur) => {
        return pre + cur;
    }, 0);
}

const res = sum(1, 2, 3); // Uncaught ReferenceError: arguments is not defined
console.log(res);
1
2
3
4
5
6
7
8
9
const sum = function() { // 改成普通函数
    return [...arguments].reduce((pre, cur) => {
        return pre + cur;
    }, 0);
}

const res = sum(1, 2, 3); // Uncaught ReferenceError: arguments is not defined
console.log(res); // 6
1
2
3
4
5
6
7
8

如果你就是想使用箭头函数的话,可以采用rest(...)来接收参数:

const sum = (...args) => {
    // console.log(args); // [1, 2, 3]
    return args.reduce((pre, cur) => {
        return pre + cur;
    }, 0);
}

const res = sum(1, 2, 3);
console.log(res);
1
2
3
4
5
6
7
8
9

剩余参数

应用场景:

  • 函数参数的接收
  • 解构赋值
const converCurrency = (rate, ...amounts) => {
    return amounts.map(item => item * rate);
}

const res = converCurrency(1.2, 100, 200, 300);
console.log(res); // [ 120, 240, 360 ]
1
2
3
4
5
6
const person = ['lisi', 23, '🏀', '⚽️'];
const [name, age, ...hobbies] = person;
console.log(name, age, hobbies); // lisi 23 [ '🏀', '⚽️' ]
1
2
3