1.基本用法
1.1定义箭头函数
ES6允许了用“箭头”(=>)来定义函数
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;
};
当箭头函数的代码块多于一条语句时,就需要使用大括号括起来,并且用return返回。
var sum = (num1, num2) => { return num1 + num2; }
当箭头函数返回对象时,需要在对象外面加上一个括号,否则报错。
// 未加括号:报错
let getTempItem = id => { id: id, name: "Temp" };
// 加括号:不报错
let getTempItem = id => ({ id: id, name: "Temp" });
有些特殊情况不加括号也可以运行,但为了避免一些不必要的麻烦,建议大家还是在返回对象时加上括号。
2.箭头函数简化代码
2.1.在一些场景下,表达更加简洁
const isEven = n => n % 2 === 0;
const square = n => n * n;
显而易见,上面的两个函数用两行就可以定义,而且看起来更加简洁。若是不用工具函数则会占用多行,相对箭头函数来说,阅读起来也会没那么方便。
2.2.简化回调函数
[1,2,3].map(function (x) {
return x * x;
});
// 箭头函数写法
[1,2,3].map(x => x * x);
上面函数调用的map方法使用了箭头函数,更加简洁了
Array.map( function ( ) { } );
JS map方法 返回一个新Array1
Array使用了括号中的回调后返回Array1
上面的函数打印为 // [1,4,9]
另一个例子
// 正常函数写法
var result = values.sort(function (a, b) {
return a - b;
});
// 箭头函数写法
var result = values.sort((a, b) => a - b);
Array.sort(function)方法:排序(比较字母),可以插入函数比较
sort方法直接修改数组,不会返回新数组。
3.箭头函数this指向
3.1.内部不存在this
箭头函数内部其实并不存在this,每当在箭头函数中使用this时,因为箭头函数中没有this,所以会带着这个this向上找。
所以通俗的说箭头函数中的this等于是在函数外部var了一个变量缓存了this,并在函数中调用,这也是我们用普通函数经常会用到的方法,而箭头函数则更加方便。
注:由于箭头函数没有自己的this,所以当然也就不能用call()、apply()、bind()这些方法去改变this的指向。
3.2.this指向固定
在普通函数中,this的指向,是指向运行时的作用域,等于说在普通函数中this的指向可以随着函数运行时作用域的不同而可能产生不同的指向。
而箭头函数的this的指向,是在指向定义时的作用域,并且不会改变
下面来看几个例子
function foo() {
setTimeout(() => {
console.log('id:', this.id);
}, 100);
}
var id = 21;
foo.call({ id: 42 });
// id: 42
上面在定义函数时,用了call方法将foo函数的 this 指向 { id:2 },setTimeout中又是用的箭头函数,当使用this时,向上找到foo函数的this,于是输出id:42
若setTimeout使用的普通函数function,使用 this时将直接指向全局
注:call使用后会直接执行函数,所以才能打印出参数`
function Timer() {
this.s1 = 0;
this.s2 = 0;
// 箭头函数
setInterval(() => this.s1++, 1000); // 执行时,向上层寻找 this,上一层的this指向实例化Timer()函数的对象。
// 普通函数
setInterval(function () { // 此普通函数执行时的 this 指向全局。
this.s2++;
}, 1000);
}
var timer = new Timer();
setTimeout(() => console.log('s1: ', timer.s1), 3100); //s1: 3
setTimeout(() => console.log('s2: ', timer.s2), 3100); //s2:0
setTimeout(() => console.log('window.s2: ', s2), 3100); //window.s2:NaN
上面的代码与之前的例子同理,大家可以自己琢磨一下。
不过在此段代码最后发现了一个现象比较疑惑,使用普通函数 this.s2++
后,打印这个全局的s2并没有报错,而是NaN,后来请教了群里的大佬,了解到了为何不报错,因为普通函数中的,this指向了window,而window又是对象,所以打印出来为NaN或是undefind。 不懂得可以自己试一试
3.3.在函数中不存在的变量
刚刚重点描述了this在箭头函数中不存在,还有几个变量在箭头函数中也是不存在的
> arguments 、super 、new.target
如果在箭头函数中使用,同 this 一样,也会向上找所对应的变量。
function foo() {
setTimeout(() => {
console.log('args:', arguments);
}, 100);
}
foo(2, 4, 6, 8)
// args: [2, 4, 6, 8]
上面代码中,箭头函数内部的变量arguments,其实是函数foo的arguments变量。
4.箭头函数不适用的场合
4.1.当使用箭头函数定义对象的方法时,且该方法内部包括this。
var a=3;
var object = {
a:2,
run: () => {this.a} //a=3;
};
object.run();
为什么上面的 this.a 会输出3呢?
之前的知识点有提到过,箭头函数中是没有this的。JS执行时发现run()中没有this,于是它向上找,它的上一层为object,而object的this指向window,所以代码中的this.a 等同于 window.a
4.2.当需要动态this的时候,也不应使用箭头函数。
var button = document.getElementById('press');
button.addEventListener('click', () => {
this.classList.toggle('on');
});
上面代码运行时,点击按钮会报错,因为button的监听函数是一个箭头函数,导致里面的this就是全局对象。如果改成普通函数,this就会动态指向被点击的按钮对象。
4.3当函数体比较复杂时
当函数体比较复杂,或是函数内部代码中有很多读写操作,这时也不应该用箭头函数。这时选择使用普通函数可以提高代码可读性
5.箭头函数使用注意事项
- 箭头函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。因此函数的this是静态的(固定不变的)
- 箭头函数不可以被实例化,也是就是说,不可以使用new来构造函数实例化对象(主要原因是因为箭头函数中没有this)
- 不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
6.总结、
箭头函数是使用 ( ) => { } 来定义函数。括号中若是只有一个参数,则可以省略小括号。
箭头函数返回对象时,需要用小括号包裹代码块
箭头函数的优势:
1.在定义相对简单的方法功能以及回调时,用箭头函数更加简洁,并且增加了可读性
2.箭头函数可以让this固定化 ,非常有利于封装回调
3.函数本身更加简洁
箭头函数的缺点:
已在 4.箭头函数不适用的场合 中解释