JavaScript中箭头函数和普通函数的区别

本文详细探讨了JavaScript ES6中的箭头函数,包括其简洁的书写形式、this指向问题(箭头函数不创建自己的this,而是继承自父级作用域)、不能作为构造函数的原因、缺失arguments对象以及不支持yield关键字。通过实例分析,阐述了箭头函数与普通函数的主要区别,特别强调了this的静态绑定特性,这对于理解箭头函数的核心至关重要。
摘要由CSDN通过智能技术生成

一、前言

我写的基本所有文章都是面试题引发的,这篇也不例外哈哈

关于ES6中的箭头函数相信很多人在项目中都用过,但是确实没有深入研究过和普通函数有什么区别,被面试毒打过的我慢慢养成了喜欢深究的习惯,然而不在像在学校一样,“凡事多问几个为什么”,现在变成了,“凡是多查为什么”

对JavaScript的了解越深入,越发现这门语言的魅力

二、 箭头函数

箭头函数(Arrow Function),最早接触这个还是在大四实习的时候,那时候学了一点vue语法边开始做公司vue的项目,项目用的 vue-element-admin 这套继承方案,才了解到ES6新特性,箭头函数 ()=>{} 、对象展开运算符 ... 然而因为项目进度催得紧,就没有仔细看,那时候对箭头函数的理解仅仅停留在方便定义函数。

当时埋下的雷,在面试时都踩了,泪奔。。

本文主要围绕箭头函数几个特点展开,分别是 书写格式 , this问题 , 不可作为构造函数 , yield , arguments对象

1. 书写形式

首先是我最粗浅的理解,也就是为了书写方便

首先箭头函数就是函数的缩写,如


   
   
var f = function(num) { return num }

这是普通函数写法,换成ES6中箭头函数的写法就是

三种写法是等效的


   
   
var f = (num) => { return num } // 参数只有一个,因此可以省略括号 var f = num => { return num } // 如果语句只包含一个return语句,可以省略大括号 var f = num => num;

2. this指向问题(最核心)

首先上结论!!!重点理解这句,理解了这句,箭头函数也就掌握了70%

箭头函数是个寄生虫,他不会创建自己的 this,它只会从自己的 作用域链 上找父级 执行上下文 的 this

箭头函数的this是创建时确定的,普通函数的this是执行时确定的

引用阮一峰在箭头函数的文章中的一个例子

下面是 Babel 转箭头函数产生的 ES5 代码,就能清楚地说明this的指向。


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

经过Babel编译后,变为这样


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

能充分说明箭头函数this指向,这里还能说明一个问题,如果foo函数作用域中的this发生了改变,箭头函数的this也会发生改变,看下面这个例子


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

这个例子中通过call方法显式的改变了foo的this,箭头函数的this也就会随之发生改变,也指向obj对象, 再看一个我觉得没啥意义的例子,不过刚开始没仔细看,被绕进去了


   
   
function foo() { return () => { return () => { return () => { console.log('id:', this.id); }; }; }; } var f = foo.call({id: 1}); var t1 = f.call({id: 2})()(); // id: 1 var t2 = f().call({id: 3})(); // id: 1 var t3 = f()().call({id: 4}); // id: 1

首先通过call改变foo的this指向,使之指向一个匿名对象{id:1},然后将foo函数返回的箭头函数赋值给一个变量f,在通过call改变这个函数变量f的this

写的有点绕,我觉得可以从两个方面理解这个问题

第一种:其实f的本质是箭头函数,f保存的是箭头函数的引用,箭头函数不能通过call和apply改变this作用域,所以失败

第二种:箭头函数的作用域其实是指向foo函数执行上下文的this,只有改变foo函数this,箭头函数的this才会改变,而最后三行都在改变这个箭头函数的this,显然达不到目的,this也就没发生改变

看一个反例:


   
   
const cat = { lives: 9, jumps: () => { this.lives--; } } cat.jumps(); cat.jumps(); cat.jumps(); console.log(cat.lives); // 9

解释一下为什么?

3. 不可当作构造函数

其实这个和第一个点一样,都是和this有关,因为在通过new构造一个对象的时候,要改变this作用域,将this指向新创建的对象,然而构造函数没有自己的this,因此不可以,而且这么写代码会报错


   
   
var Person = () => { this.name = "111"; } var person = new Person(); // Uncaught TypeError: Person is not a constructor

还有一个需要注意的点,有人也把这个当成箭头函数和普通函数的区别,不过我认为和这个其实说的是一个意思,因为不能作为构造函数,也就不具有prototype,因为原型链的绑定就是通过new关键字(没深究过,觉得这句话应该没问题)

除了不能作为构造函数,在箭头函数中还不能使用super以及new.target

new.target是用来检测构造函数是否通过new关键字调用的,例:


   
   
function fun() { if (new.target) { console.log("是通过new构造的") } else { throw new Error("fun必须通过new调用") } } var e = new fun(); // 是通过new构造的 var f = fun(); // Uncaught Error: fun必须通过new调用

super在class部分用的比较多,和java中的super关键字差不多,都是调用父类的方法,直接通过super()代表调用父类构造方法(java继承思想),super.test() 代表调用父类的test方法

4. 没有arguments

阮一峰在ES6系列文章中曾说不可以使用arguments对象,有些人认为使用会报错,其实不是,在箭头函数中可以使用arguments对象,只是arguments对象也指向外层的arguments

作为替代,可以使用rest参数,如下例:


   
   
function fun() { return (...rest) => { console.log(rest); } } fun()(1, 2, 3, 4);

上述箭头函数中通过…rest接受了外界传递的参数,和arguments效果差不多,

5. yield问题

箭头函数中不能使用yield关键字,因此不能作为Generate函数

后续在补充

三、总结

虽然总结了五条不同点,但是最核心的应该还是this的问题,通过this问题可以抓出构造函数以及arguments的问题,yield目前用的还不太多,大概做个了解,后边在补充,在就是书写形式上比普通函数简化了很多

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值