JS中箭头函数与this的写法和理解


Posted in Javascript onJanuary 14, 2021

前言

JavaScript在ES6语法中新增了箭头函数,相较于传统函数,箭头函数不仅更加简洁,而且在this方面进行了改进。this作为JavaScript中比较诡异的存在,许多文章对于this的解释也不尽相同,本篇文章试图厘清JS中函数与this的关系。

一、JS中函数的写法

1.常规函数的写法

在ES6语法之前,JS中的函数由function关键字、params参数和被花括号包裹的函数体组成。为了与后面说到的箭头函数相区别,我们先把这样的函数叫做常规函数,常规函数既可以用声明式写法也可以用赋值式写法。例子:

function test(name) { //声明式写法
 console.log(name)
}
test('Jerry')

let test2 = function(name) { //赋值式写法
 console.log(name)
}
test2('Tom')

2. 箭头函数的写法

ES6箭头函数的引入,使函数的写法变的更加简洁,但在书写上要遵循一定的规则。

规则一:箭头函数只能用赋值式写法,不能用声明式写法

例子:

const test = (name) => {
 console.log(name)
}
test('Jerry')

规则二:如果参数只有一个,可以不加括号,如果没有参数或者参数多于一个就需要加括号

例子:

const test = name => {
 console.log(name)
}
test('Jerry')

const test2 = (name1, name2) => {
 console.log(name1 + ' and ' + name2)
}
test2('Tom', 'Jerry')

规则三:如果函数体只有一句话,可以不加花括号

例子:

const test = name => console.log(name)

规则四:如果函数体没有括号,可以不写return,箭头函数会帮你return

例子:

const add = (p1, p2) => p1 + p2
add(10, 25)

记住:函数体的花括号与return关键字同在。

从以上的例子我们可以看出,箭头函数对常规函数的圆括号和花括号都进行了简化。除了这些简化,箭头函数对于常规函数最大的优化之处在于this。

二、理解常规函数中this

在探讨箭头函数对于this的优化之前,我们先得明白this究竟是什么,以及它是如何使用的。this是使用call方法调用函数时传递的第一个参数,它可以在函数调用时修改,在函数没有调用的时候,this的值是无法确定。

如果没有使用过call方法来调用函数的话,上面的对于this的定义可能不太明白。那么我们需要先理解函数调用的两种方法。

1. 纯粹的函数调用

第一种方法最常见,例子如下:

function test(name) {
 console.log(name)
 console.log(this)
}
test('Jerry') //调用函数

这种方法我们使用最多,但是这种函数调用方法只是一种简写,它完整的写法是下面这样的:

function test(name) {
 console.log(name)
 console.log(this)
}
test.call(undefined, 'Tom')

注意到上面调用函数的call方法了吗?call方法接收的第一个参数就是this,这里我们传了一个undefined。那么,依据定义,函数执行了之后打出来的this会是undefined吗?也不是。

如果你传的 context 就 null 或者 undefined,那么 window 对象就是默认的 context(严格模式下默认 context 是 undefined)。

所以这里我们打出来的this是Window对象。

2. 对象中函数的调用

直接看例子:

const obj = {
 name: 'Jerry',
 greet: function() {
 console.log(this.name)
 }
}
obj.greet() //第一种调用方法
obj.greet.call(obj) //第二种调用方法

例子里第一种调用方法只是第二种调用方法的语法糖,第二种才是完整的调用方法,而且第二种方法厉害的地方在于它可以手动指定this。

手动指定this的例子:

const obj = {
 name: 'Jerry',
 greet: function() {
 console.log(this.name)
 }
}
obj.greet.call({name: 'Spike'}) //打出来的是 Spike

从上面的例子我们看到greet函数执行时this,已经被我们改过了。

3. 构造函数中this

构造函数里的this稍微有点特殊,每个构造函数在new之后都会返回一个对象,这个对象就是this,也就是context上下文。

例子:

function Test() {
 this.name = 'Tom'
}
let p = new Test()
console.log(typeof p) //object
console.log(p.name) // Tom

4. window.setTimeout()和window.setInterval()中函数的调用

window.setTimeout()和window.setInterval()的函数中的this有些特殊,里面的this默认是window对象。

简单总结一下:函数完整的调用方法是使用call方法,包括test.call(context, name)和obj.greet.call(context,name),这里的context就是函数调用时的上下文,也就是this,只不过这个this是可以通过call方法来修改的;构造函数稍微特殊一点,它的this直接指向new之后返回的对象;window.setTimeout()和window.setInterval()默认的是this是window对象。

三、理解箭头函数中的this

上面关于this讲了很多,this是函数用call方法调用时传递的第一个参数,而且它还可以手动更改,这样要确定this的值就太麻烦了。不过,箭头函数的出现给我们确定this帮了一些忙。

1. 箭头函数的特性一:默认绑定外层this

上面提到:this的值是可以用call方法修改的,而且只有在调用的时候我们才能确定this的值。而当我们使用箭头函数的时候,箭头函数会默认帮我们绑定外层this的值,所以在箭头函数中this的值和外层的this是一样的。

不使用箭头函数例子:

const obj = {
	a: function() { console.log(this) } 
}
obj.a() //打出的是obj对象

使用箭头函数的例子:

const obj = {
 a: () => {
 console.log(this)
 }
}
obj.a() //打出来的是window

在使用箭头函数的例子里,因为箭头函数默认不会使用自己的this,而是会和外层的this保持一致,最外层的this就是window对象。

2. 箭头函数的特性二:不能用call方法修改里面的this

这个也很好理解,我们之前一直在说,函数的this可以用call方法来手动指定,而为了减少this的复杂性,箭头函数无法用call方法来指定this。

例子:

const obj = {
 a: () => {
 console.log(this)
 }
}
obj.a.call('123') //打出来的结果依然是window对象

因为上文我们说到window.setTimeout()中函数里的this默认是window,我们也可以通过箭头函数使它的this和外层的this保持一致:

window.setTimeout()的例子:

const obj = {
 a: function() {
 console.log(this)
 window.setTimeout(() => { 
  console.log(this) 
 }, 1000)
 }
}
obj.a.call(obj) //第一个this是obj对象,第二个this还是obj对象

想必大家明白了,函数obj.a没有使用箭头函数,因为它的this还是obj,而setTimeout里的函数使用了箭头函数,所以它会和外层的this保持一致,也是obj;如果setTimeout里的函数没有使用箭头函数,那么它打出来的应该是window对象。

四、多层对象嵌套里函数的this

这里是笔者在学习时遇到的一点疑惑。箭头函数里的this是和外层保持一致的,但是如果这个外层有好多层,那它是和哪层保持一致呢?

直接上例子:

const obj = {
 a: function() { console.log(this) },
 b: {
 	c: function() {console.log(this)}
	}
}
obj.a() // 打出的是obj对象, 相当于obj.a.call(obj)
obj.b.c() //打出的是obj.b对象, 相当于obj.b.c.call(obj.b)

上面的代码都符合直觉,接下来把obj.b.c对应的函数换成箭头函数,结果如下:

const obj = {
 a: function() { console.log(this) },
 b: {
 	c: () => {console.log(this)}
	}
}
obj.a() //没有使用箭头函数打出的是obj
obj.b.c() //打出的是window对象!!

obj.a调用后打出来的是obj对象,而obj.b.c调用后打出的是window对象而非obj,这表示多层对象嵌套里箭头函数里this是和最最外层保持一致的。

上面的内容就是笔者学习箭头函数中梳理出来的知识点,如有错误,请批评指正!这是我在掘金上写的第三篇文章,感谢阅读!

本文参考:this 的值到底是什么?一次说清楚

总结

到此这篇关于JS中箭头函数与this的写法和理解的文章就介绍到这了,更多相关JS箭头函数与this内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
JQuery 学习技巧总结
May 21 Javascript
腾讯与新浪的通过IP地址获取当前地理位置(省份)的接口
Jul 26 Javascript
js实现的仿新浪微博完美的时间组件升级版
Dec 20 Javascript
JS实现判断碰撞的方法
Feb 11 Javascript
JQuery中层次选择器用法实例详解
May 18 Javascript
JavaScript实现级联菜单的方法
Jun 29 Javascript
详解webpack3编译兼容IE8的正确姿势
Dec 21 Javascript
elementui的默认样式修改方法
Feb 23 Javascript
微信小程序实现页面下拉刷新和上拉加载功能详解
Dec 03 Javascript
ES6 对象的新功能与解构赋值介绍
Feb 05 Javascript
使用Bootstrap做一个朝代历史表
Dec 10 Javascript
OpenLayers3实现地图鹰眼以及地图比例尺的添加
Sep 25 Javascript
JavaScript this关键字的深入详解
Jan 14 #Javascript
Vue实现多页签组件
Jan 14 #Vue.js
如何在vue中使用HTML 5 拖放API
Jan 14 #Vue.js
Vue中引入svg图标的两种方式
Jan 14 #Vue.js
vue+element table表格实现动态列筛选的示例代码
Jan 14 #Vue.js
vue 递归组件的简单使用示例
Jan 14 #Vue.js
vue element和nuxt的使用技巧分享
Jan 14 #Vue.js
You might like
thinkphp中U方法按路由规则生成url的方法
2018/03/12 PHP
PHP ajax+jQuery 实现批量删除功能实例代码小结
2018/12/06 PHP
laravel框架中控制器的创建和使用方法分析
2019/11/23 PHP
ThinkPHP类似AOP思想的参数验证的实现方法
2019/12/18 PHP
Jquery替换已存在于element上的event的方法
2010/03/09 Javascript
Jquery UI震动效果实现原理及步骤
2013/02/04 Javascript
ECMAScript5中的对象存取器属性:getter和setter介绍
2014/12/08 Javascript
jQuery实现按键盘方向键翻页特效
2015/03/18 Javascript
JSON对象 详解及实例代码
2016/10/18 Javascript
简单实现bootstrap导航效果
2017/02/07 Javascript
深入理解Promise.all
2018/08/08 Javascript
JS实现数组的增删改查操作示例
2018/08/29 Javascript
在vue中安装使用vux的教程详解
2018/09/16 Javascript
实例讲解JavaScript 计时事件
2020/07/04 Javascript
Python Web开发模板引擎优缺点总结
2014/05/06 Python
Python自动连接ssh的方法
2015/03/07 Python
python实现用于测试网站访问速率的方法
2015/05/26 Python
关于Python中空格字符串处理的技巧总结
2017/08/10 Python
Python基于辗转相除法求解最大公约数的方法示例
2018/04/04 Python
对PyQt5中的菜单栏和工具栏实例详解
2019/06/20 Python
利用Python实现Shp格式向GeoJSON的转换方法
2019/07/09 Python
使用django的ORM框架按月统计近一年内的数据方法
2019/07/18 Python
Python实现RabbitMQ6种消息模型的示例代码
2020/03/30 Python
Python 实现一个计时器
2020/07/28 Python
Python中的特殊方法以及应用详解
2020/09/20 Python
用sleep间隔进行python反爬虫的实例讲解
2020/11/30 Python
用CSS3实现无限循环的无缝滚动的实例代码
2017/07/04 HTML / CSS
巴西最大的运动品牌:Olympikus
2020/07/14 全球购物
制定岗位职责的原则
2013/11/08 职场文书
文员的职业生涯规划发展方向
2014/02/08 职场文书
教育英语专业毕业生的求职信
2014/03/13 职场文书
走群众路线学习笔记
2014/11/06 职场文书
运动会开幕词
2015/01/28 职场文书
500字作文之周记
2019/12/13 职场文书
浅谈克隆 JavaScript
2021/11/02 Javascript
游戏《东方异文石:爱亚利亚黎明》正式版发布
2022/04/03 其他游戏