js ES6箭头函数的作用
前置知识
1、箭头函数语法简洁,相较于传统的函数表达式,箭头函数的语法更为简洁,尤其适用于简单的函数。
2、解决this取向问题,在传统函数中,this
的值取决于函数的调用方式,这可能会导致一些难以理解和调试的问题。而箭头函数不会绑定自己的 this
,它会捕获其所在上下文的 this
值。
3、每个传统函数都有自己的this,通常情况下都指向全局对象window。
4、箭头函数不会绑定 arguments对象、super关键字等。
箭头函数和普通函数的this指向
普通函数
let name = "window"
var obj = {name:"dong",getName: function(){ console.log(this.name) }
}
obj.getName() // dong
这个例子中,我们执行getName 方法,打印的结果是 dong,说明这里的 this指向是 obj,obj对象中有name,所以返回obj.name;
var name = "window"
var obj = {name:"dong",getName: function(){return function(){console.log(this.name)}}
}
obj.getName()() // window
我们在 getName 函数中在返回一个匿名函数,执行这个匿名函数发现this.name 是window,这里匿名函数的执行环境是全局的,this.name首先在匿名函数中找,找不到name就往上一层找,上一层是全局,然后打印的是全局name。那怎么能让匿名函数打印obj的name那?
var name = "window"
var obj = {name:"dong",getName: function(){var that = thisreturn function(){console.log(that.name)}}
}
obj.getName()() // dong
这个我们应该都不陌生,都在开发中用过,用一个变量(that)保存this,此时匿名函数中的that.name就会去that上找,也就是obj上去找,obj上有name属性,结果打印的就是obj.name
为了进一步理解this指向,我看下面这道面试题,并判断其运行结果
window.val = 2
var obj2 = {val: 10,getVal:function(){this.val *= 2val *= 2console.log(val)console.log(this.val)}
}
// 执行下面指令,说出打印结果
obj2.getVal()
let func = obj2.getVal
func()
首先我们执行 obj2.getVal();
在getVal中,此时this指向 obj2,所以 this.val=10, 这里this.val*2,那么this.val = 20;val首先在getVal里找,没有定义会就去找全局定义有无val(如果全局没有val,那么val就没有定义,就会报错),这里全局val=2,那么val*2 = 4;所以这里打印的是 4 和20;
然后在执行 var func = obj2.getVal 在执行func()
这里我们把 obj2.getVal的this指向指到了 全局,也就是window,所以执行func(),这里的this.val是window.val,window.val在上一步 obj2.getVal()时 已经等于4了,所以这里 *2,然后在*2, window.val=16;所以打印结果如下:
箭头函数
有了箭头函数就没有自己的this了,很好的解决了匿名函数this指向问题,
let obj3 = {func1:function(){console.log(this)},func2:function(){setTimeout(()=>{console.log(this)})},func3:()=>{console.log(this)}
}
obj3.func1() // obj3
obj3.func2() // obj3
obj3.func3() // window
如果在箭头函数中仍然使用this,那么这个this指向函数作用域链,和普通函数一样。同样以面试题为例
window.val = 2
var obj2 = {val: 10,getVal:()=>{obj2.val *= 2this.val *= 2console.log(obj2.val)console.log(this.val)}
}obj2.getVal()
let func = obj2.getVal
func()
这里就很简单明了,这里吗的this指向的作用域是全局,所以this.val是2,调用obj2.getVal()打印4,调用func()打印8。
箭头函数的作用
那么有了普通函数,为什么还需要箭头函数那?箭头函数的作用是什么那?其实箭头函数解决了函数的二义性。那什么是二义性那?
例如我们创建一个函数,我们调用这个函数有两种调用方式,一种是直接调用,另一种是用new关键字来调用,这就是函数的二义性,当然也包括js的一些内置函数,也是可以用两种方法调用的。
function func(){console.log('func')
}
// 调用方式1
func()// 调用方式2
new func()Number();
new Number()Date();
new Date();
后来我们开发会给函数命名上定义了规范,普通函数是小写字母开头,构造函数是大写字母开头想我们。
function func(){console.log('func')
}function Func(){console.log('Func')
}
为了解决这个问题,在发布的ES6中引入了箭头函数和class
箭头函数调用,如果用new关键字调用就会报错
const func = ()=>{console.log("func")
}
func()
new func()
class调用,如果没有使用new来调用就会报错
class Dong{func(){console.log("func")}
}
let a = new Dong()
a.func()
Dong().func()
小知识
那么如何用普通函数不能使用new 关键字那?
可以在定义函数中加入判断如下:
function func(){if(new.target){throw('Uncaught TypeError: func is not a constructor')}console.log("func")
}
func()
new func()
这样我们就可以让普通函数不能使用new 关键字了。