箭头函数与普通函数的区别

JavaScript中箭头函数与普通函数到底有什么区别?

简单来说: 普通函数拥有自身的this,而箭头函数自身没有this

箭头函数表达式(箭头函数)的语法比函数表达式(普通函数)更简洁,并且箭头函数没有自己的this,arguments,super或new.target。箭头函数表达式更适用于那些本来需要匿名函数的地方,并且它不能用作构造函数。

我们先来看看普通函数和箭头函数的语法

COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 普通函数
// 第一种: 函数声明
function commonFn(){
console.log(this)
}
// 第二种: 函数表达式
const commonFn = function(){
console.log(this)
}
commonFn() // 调用

// 箭头函数
// 第一种: 没有参数,填写一个圆括号
const arrowsFn = ()=>{
console.log(this)
}
// 第二种价: 有一个参数,可以有圆括号,也可以没有圆括号
const arrowsFn = (data)=>{
console.log(this)
}
const arrowsFn = data=>{
console.log(this)
}
// 第三种: 有一个参数以上,必须拥有括号否则error
const arrowsFn = (data,name,age)=>{
console.log(this)
}
// 第四种: 有一个参数,并且只有一行代码需要返回时
const arrowsFn = (data)=> data
// 等同于
const arrowsFn = (data)=>{
return data
}
arrowsFn()

没有单独的this
在箭头函数出现之前,每一个新函数根据它是如何被调用的来定义这个函数的this值:

  • 如果该函数是一个构造函数,this指针指向一个新的对象
  • 在严格模式下的函数调用下,this指向undefined
  • 如果该函数是一个对象的方法,则它的this指针指向这个对象

我们来看看一段代码

COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var name = '张三'
function test(name){
console.log(name,this.name) // 输出:李四 张三
}
test('李四')
// 为什么会这样呢?这就要涉及到this指向的问题了
// 换个变量名你就能看懂了
var name = '张三'
function test(username){
console.log(username,this.name) // 输出:李四 张三
}
test('李四')
// 为什么this要指向全局的name呢?
var name = '张三'
function test(username){
console.log(username,this.username) // 输出:李四 undefined
}
test('李四')

实际上this是根据一个原则指向的:谁调用我,我就指向谁
当我们调用test('李四')的时候其实是window.test('李四')所有才会导致this指向全局的name变量

我们在看一段代码,你可能就会明白了(这里我就不绕弯了,直接使用不同的变量名)

COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var username = '李四'
var obj = {
name: '张三',
age: 18,
test: function(uname){
console.log(uname,this.uname) // 迪迦 undefined
console.log(name,this.name) // '' 张三
console.log(username,this.username) // 李四 undefined
setTimeout(function(uname){
console.log(uname,this.uname) // undefined undefined
console.log(name,this.name) // '' ''
console.log(username,this.username) // 李四 李四
},500)
}
}
obj.test('迪迦')

解析:其中有6个输出,下面我就以1-6的形式进行对号解析(文字有点多,耐心阅读)

首先说明以下,我们是通过obj来调用方法的(上面已经提到过,谁调用,this就指向谁),所有这里的this是指向obj对象的

  1. 调用方法时传入了一个迪迦的字符串,所有当我们输出uname的时候就会得到我们传入的迪迦
    在obj里并没有uname所有才会输出undefined
  2. 开头已经说了,谁调用,指向谁,那为什么name会输出空字符串呢?
    因为函数会向上查找内容直到window才会停止,如果window也没有的话则为undefined(注意是在声明的地方向上查找,而不是调用的地方上查找),而window全局变量了是有一个name变量的并且内容为’’(空字符串)所有就找到了’’
    第二个参数输出张山,原因是this指向obj的(obj调用了方法,所以this指向obj)
  3. 输出李四因为当前方法内没有username变量,所以会向上查找,直到window
    在obj里并没有username,所以输出undefined
  4. setTimeout方法是属于全局方法,其实默认是省略掉了window(window.setTimeout())
    第一个输出参数:为什么不输出迪迦,而是undefined?
    这个问题就比较刁钻了,由于setTimeout方法是window方法(全局方法),那么在调用setTimeout方法的时候是window调用的(window.setTimeout())而setTimeout方法内定义了一个函数,并且需要一个函数为uname的参数,可并没有人传入这个方法传入任何内容,而方法内又要输出这个变量,所以它只能向上查找,可是window就是最后一层了,并且window并没有uname,所以输出undefined
    第二个输出参数:全局变量并没有uname所以输出undefined
  5. 为什么输出为两个’’(空字符串),原因很简单,setTimeout是window全局方法,如果setTimeout内没有通过var name = ‘hi’或者通过调用其他方法的返回值的话,window全局变量种有一个name变量为’’(空字符串),你可以打开所有网站,输入控制台输入console.log(window)window全局变量中的确又nameconsole.log(window.name)或者console.log(name)都会输出’’(空字符串)
  6. 同第五个console.log的说法差不多,this指向window,并且会向上查询,所有会的到全局的username

把普通函数改为箭头函数

COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var username = '李四'
var obj = {
name: '张三',
age: 18,
test: (uname)=>{
console.log(uname,this.uname) // 迪迦 undefined
console.log(name,this.name) // '' ''
console.log(username,this.username) // 李四 李四
setTimeout((uname)=>{
console.log(uname,this.uname) // undefined undefined
console.log(name,this.name) // '' ''
console.log(username,this.username) // 李四 李四
},500)
}
}
obj.test('迪迦')

解析: 这次解析我就不写那么多文字了,你只需要记住一点,箭头函数没有this,所有它会向上查找,直到window才会停下,如果window没有就返回undefined(下面的解析,重复的话我就不说了)

注意:obj对象是没有this的,只有方法才会有this

  1. 输出传入的参数迪迦。同第四个解析
  2. 由于前面说过,window全部变量下有个name变量并且内容为’’空字符串
  3. 由于obj没有this,箭头函数也没有,所有输出全局变量username的内容
  4. 由于箭头函数没有this,所有它就会向上查找,obj也没有this,就找到了window,window没有就undefined
  5. 同第二个解析
  6. 同第三个解析

关于window全局变量为什么会有name变量的问题:https://blog.lete114.top/article/browser-window.name-property.html

Authorship: Lete乐特
Article Link: https://blog.imlete.cn/article/arrows-common-function.html
Copyright: All posts on this blog are licensed under the CC BY-NC-SA 4.0 license unless otherwise stated. Please cite Lete乐特 's Blog !