JavaScript中箭头函数和普通函数的区别
一、前言
我写的基本所有文章都是面试题引发的,这篇也不例外哈哈
关于ES6中的箭头函数相信很多人在项目中都用过,但是确实没有深入研究过和普通函数有什么区别,被面试毒打过的我慢慢养成了喜欢深究的习惯,然而不在像在学校一样,“凡事多问几个为什么”,现在变成了,“凡是多查为什么”
对JavaScript的了解越深入,越发现这门语言的魅力
二、 箭头函数
箭头函数(Arrow Function),最早接触这个还是在大四实习的时候,那时候学了一点vue语法边开始做公司vue的项目,项目用的 vue-element-admin
这套继承方案,才了解到ES6新特性,箭头函数 ()=>{}
、对象展开运算符 ...
然而因为项目进度催得紧,就没有仔细看,那时候对箭头函数的理解仅仅停留在方便定义函数。
当时埋下的雷,在面试时都踩了,泪奔。。
本文主要围绕箭头函数几个特点展开,分别是 书写格式
, this问题
, 不可作为构造函数
, yield
, arguments对象
1. 书写形式
首先是我最粗浅的理解,也就是为了书写方便
首先箭头函数就是函数的缩写,如
1 | var f = function(num) { |
这是普通函数写法,换成ES6中箭头函数的写法就是
三种写法是等效的
1 | var f = (num) => { return num } |
2. this指向问题(最核心)
首先上结论!!!重点理解这句,理解了这句,箭头函数也就掌握了70%
箭头函数是个寄生虫,他不会创建自己的 this,它只会从自己的
作用域链
上找父级执行上下文
的 this箭头函数的this是创建时确定的,普通函数的this是执行时确定的
引用阮一峰在箭头函数的文章中的一个例子
下面是 Babel 转箭头函数产生的 ES5 代码,就能清楚地说明this
的指向。
1 | function foo() { |
经过Babel编译后,变为这样
1 | function foo() { |
能充分说明箭头函数this指向,这里还能说明一个问题,如果foo函数作用域中的this发生了改变,箭头函数的this也会发生改变,看下面这个例子
1 | function foo() { |
这个例子中通过call方法显式的改变了foo的this,箭头函数的this也就会随之发生改变,也指向obj对象, 再看一个我觉得没啥意义的例子,不过刚开始没仔细看,被绕进去了
1 | function foo() { |
首先通过call改变foo的this指向,使之指向一个匿名对象{id:1},然后将foo函数返回的箭头函数赋值给一个变量f,在通过call改变这个函数变量f的this
写的有点绕,我觉得可以从两个方面理解这个问题
第一种:其实f的本质是箭头函数,f保存的是箭头函数的引用,箭头函数不能通过call和apply改变this作用域,所以失败
第二种:箭头函数的作用域其实是指向foo函数执行上下文的this,只有改变foo函数this,箭头函数的this才会改变,而最后三行都在改变这个箭头函数的this,显然达不到目的,this也就没发生改变
看一个反例:
1 | const cat = { |
解释一下为什么?
3. 不可当作构造函数
其实这个和第一个点一样,都是和this有关,因为在通过new构造一个对象的时候,要改变this作用域,将this指向新创建的对象,然而构造函数没有自己的this,因此不可以,而且这么写代码会报错
1 | var Person = () => { |
还有一个需要注意的点,有人也把这个当成箭头函数和普通函数的区别,不过我认为和这个其实说的是一个意思,因为不能作为构造函数,也就不具有prototype,因为原型链的绑定就是通过new关键字(没深究过,觉得这句话应该没问题)
除了不能作为构造函数,在箭头函数中还不能使用super以及new.target
new.target是用来检测构造函数是否通过new关键字调用的,例:
1 | function fun() { |
super在class部分用的比较多,和java中的super关键字差不多,都是调用父类的方法,直接通过super()代表调用父类构造方法(java继承思想),super.test() 代表调用父类的test方法
4. 没有arguments
阮一峰在ES6系列文章中曾说不可以使用arguments对象,有些人认为使用会报错,其实不是,在箭头函数中可以使用arguments对象,只是arguments对象也指向外层的arguments
作为替代,可以使用rest参数,如下例:
1 | function fun() { |
上述箭头函数中通过…rest接受了外界传递的参数,和arguments效果差不多,
5. yield问题
箭头函数中不能使用yield关键字,因此不能作为Generate函数
后续在补充
三、总结
虽然总结了五条不同点,但是最核心的应该还是this的问题,通过this问题可以抓出构造函数以及arguments的问题,yield目前用的还不太多,大概做个了解,后边在补充,在就是书写形式上比普通函数简化了很多