箭头函数在 ES6 的时候推出了.
它的语法有点类似于 .NET
里的 lamdba
表达式.
基本语法
(参数类表)=>{函数体}
let sum = (a,b) => a + b
一般用于匿名回调函数使用
app.post(url,(response)=>{
//.....
})
// 等价于
app.post(url,(response)=>{
//...
})
抛开this
关键字,箭头函数和普通的函数是完全等价的.
它俩可以互换使用.
this和箭头函数
在JavaScript
中,我们使用this
有这么几种情况.
- JS 构造函数中,
this
指向当前实例化出来的对象.
function UserCreator(name,age) {
this.name = name
this.age = age
}
UserCreator.prototype.showInfo = function() {
console.log(`${this.name} -- ${this.age}`)
}
let user = new UserCreator('张三',24)
user.showInfo()
- 对象字面量中,
this
指向当前的对象
let obj = {
message:'message',
show:function() {
console.log(this.message)
}
}
obj.show()
- 全局范围内,使用
functionName()
直接调用的,基本都是指向window对象.
function isWindow() {
console.log(this === window)
}
isWindow()
- 当然也可以使用
call
,apply
来改变方法调用的实际对象.
obj.show.call({message:'我是另外一个message'})
--
其实说白了,所有的 JavaScript
函数都是不一个独立存在的.
它们的调用都会传入一个对象.
对于 obj.method()
===> method(obj)
对于 method()
===> method(window)
'
也就是说,普通函数的this,我们可以在定义的时候如果不去改它,那么它们就是符合我们预期的指向.但我们也可以去手动的修改this的指向,通过 call/apply
当箭头函数遇上了this.
看了很多博客讲的这些知识,一上来就给结论,然后证明结论.让我总感觉有点不知其所以然
.
所以,决定开始自己慢慢琢磨这个点.
- 在全局作用域上,箭头函数和普通函数没有区别,都是指向的window.
let arrowFn = () => {
console.log(this === window)
}
arrowFn()
- 在构造函数里,
箭头函数的this就指向了window,而非当前实例化出来的对象.
UserCreator.prototype.arrowFn = () => {
console.log(this === window)
}
- 在对象字面量里,
箭头函数的this仍然指向了window
let obj = {
show2:()=>{
console.log(this+'----')
}
}
所以,只要涉及到了this
关键字,那么箭头函数和普通函还是有很大的区别的.
箭头函数的this
和箭头函数所声明的词法作用域相关
.
箭头函数,没有this
,它的this
是从当前此法作用域继承过来的.
UserCreator.prototype.arrowFn =
// 当前作用域为 window
() => {
console.log(this === window)
}
如果这么看这一段代码的话,this === window
好像比较好理解.
关键在于
let obj = {
show2:()=>{
console.log(this===window) //true
},
-
show2
是obj
的一个属性. - 在词法作用域上,这个箭头函数是属于
obj.show2
的. - 所以,感性上就感觉
this
指向的是obj
. 但实际上,指向的是window
. - 有点蒙圈.(后续原因是箭头函数没有被另外一个函数给包括起来,所以从全局的词法作用域,也就是最外围的那个js执行环境继承来的this对象,所以也就是window对象.)
一个比较常见的解释箭头函数和普通函数this
的代码.
let obj2 = {
message: 'message',
show: function () {
console.log(this.message) // 没问题
setTimeout(function(){
console.log(this.message) // 由于这个回调函数,没有显示的指向obj.method() 所以,它里面的this指向的是window对象. // 输出结构是 undefiend
},1000);
}
}
obj2.show()
undefined
但是,如果改成箭头函数,this,就由它外围的词法总作用域决定.而外围的this
,指向的是obj2
对象.
let obj2 = {
message: 'message',
show:function(){
setTimeout(() => {
console.log(this.message)
}, 1000);
}
}
message
当写完第二个箭头函数的 DEMO
后,突然有点对箭头函数 this
的指向有点眉目了.
首先箭头函数,没有
this
.它的this
是来自外部最近的词法作用域
的.在上线那个例子中,由于
this
指向了obj2
对象,而这个obj2
对象最近的词法作用域
难道是show:function(){}这对被function括起来的大括号?
所以,对于箭头函数来说,
词法作用域在于
,这个那个function把箭头函数括起来了?外围的funciton的this是谁,箭头函数的this就是谁?
let obj2 = {
message: 'message',
getMessage:function(){
// 词法作用域,this == obj2
(()=>{
console.log(this.message)
})()
}
}
结果符合预期.
在来一个例子证明自己的想法.
function doSomething() {
return () => {
console.log(this.message)
}
}
doSomething.call({message:'我是dosomething的函数调用的对象,我里面有个箭头函数,箭头函数的this就是我,所以可以用this.message'})()
如果上述猜测没错的话,箭头函数一直嵌套下去结果会如何呢?
function doSomething2() {
console.log(this.name)
// 箭头函数继承this
;
(()=>{
console.log(this.name)
this.name = '我被第一个箭头函数改了,在套一层'
;
(()=>{
console.log(this.name)
this.name = '我被第二个箭头函数改了,还套一层'
console.log(this.name)
})()
})()
}
在来一个例子证明:箭头函数的this继承自最近的把它嵌套的function里的this指向.
let obj3 = {
message:'message',
show:function() { // this === obj3
return function() {
console.log(this === window) //this === window
return () => { // 最近的 function --> this === window
console.log(this.message) // 所以结果就是: undefined
}
}
}
}
obj3.show()()()
总结:
- 箭头函数写在全局时,它的
this
从全局作用域继承过来.全局的环境,本质上也可以理解成一个巨大的function
,或者是最外围的function
,这个function
里的this
===window
.所以箭头函数就继承了这个this
===window
.
- 箭头函数
this
更多的词法作用域
意义在于,把箭头函数包在另一个函数fn
里.fn
里的this
是谁,箭头函数继承的this
就是谁.
用另一个函数把箭头函数包裹起来,外围的函数this是谁,箭头函数的this就是谁。