Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
本题难度:⭐ ⭐
答:
ES6 设计箭头函数主要有两个作用:
- 让函数代码写起来更简洁
- 解决对象内函数嵌套函数时的 this 指向问题
代码更简洁
const f = v => v
// 等同于
const f = function (v) {
return v
}
const f = () => 5
// 等同于
const f = function () {
return 5
}
const sum = (num1, num2) => num1 + num2
// 等同于
const sum = function (num1, num2) {
return num1 + num2
}
改变 this 指向
对象里有函数嵌套函数的情况,使用 this 会指向 window。
比如下面这个例子,DOM 事件的回调函数封装在一个对象里面。
const handler = {
id: '123456',
init: function () {
document.addEventListener(
'click',
function (event) {
return this.doSomething(event.type)
},
false
)
},
doSomething: function (type) {
console.log('Handling ' + type + ' for ' + this.id)
}
}
handler.init()
点击事件触发的时候,直接报错。
因为 window 上根本没有 doSomething 这个方法,这个方法是在 handler 对象中的。
改造成箭头函数就可以解决这个问题,改变 this 指向,让 this 指向当前函数上一层作用域中的 this,也就是 handler 这个对象,也就可以正常调用 doSomething 这个方法。
const handler = {
id: '123456',
init: function () {
document.addEventListener(
'click',
event => this.doSomething(event.type), // 这么写就没问题
false
)
},
doSomething: function (type) {
console.log('Handling ' + type + ' for ' + this.id)
}
}
handler.init()
可以用 babel 转 ES5 来查看 this 指向改变的原理,其实就是用一个临时变量 _this 把箭头函数上一层作用域中的 this 存起来,用在箭头函数中:
其他需要注意的
this 指向不会改变
由于箭头函数没有自己的this指针,通过 call、apply或 bind 方法调用一个函数时,只能传递参数不能绑定this,他们的第一个参数会被忽略。
const adder = {
base: 1,
add: function (a) {
const f = v => v + this.base
return f(a)
},
addThruCall: function (a) {
const f = v => v + this.base
const b = {
base: 2
}
return f.call(b, a)
}
}
console.log(adder.add(1)) // 输出 2
console.log(adder.addThruCall(1)) // 仍然输出 2
没有 arguments
在箭头函数里调用 arguments,直接报错。
const arr = () => {
console.log(arguments)
}
console.log(arr(1, 2, 3)) // Uncaught ReferenceError: arguments is not defined
可以使用 剩余参数 来代替 arguments
const fn = (...args) => {
console.log(args)
}
console.log(fn(1, 2, 3)) // [1, 2, 3]
不是构造函数
把箭头函数当作构造函数,直接报错。
const Fn = () => {}
const f = new Fn() // Uncaught TypeError: Fn is not a constructor
不能重复声明函数
普通函数可以重复声明,后面的会覆盖前面的
function print () {
console.log(1)
}
function print () {
console.log(2)
}
print() // 输出 2
箭头函数不行,直接报错
function print () {
console.log(1)
}
const print = () => { // Module parse failed: Identifier 'print' has already been declared
console.log(1)
}
不适合用箭头函数的场景
由于箭头函数使得 this 从“动态”变成“静态”,下面两个场合不应该使用箭头函数。
第一个场合是定义对象的方法,且该方法内部包括this。
const cat = {
lives: 9,
jumps: () => {
this.lives--
}
}
上面代码中,cat.jumps()方法是一个箭头函数,这是错误的。调用cat.jumps()时,如果是普通函数,该方法内部的this指向cat;如果写成上面那样的箭头函数,使得this指向全局对象,因此不会得到预期结果。这是因为对象不构成单独的作用域,导致jumps箭头函数定义时的作用域就是全局作用域。
第二个场合是需要动态this的时候,也不应使用箭头函数。
const button = document.getElementById('press')
button.addEventListener('click', () => {
this.classList.toggle('on')
})
上面代码运行时,点击按钮会报错,因为button的监听函数是一个箭头函数,导致里面的this就是全局对象。如果改成普通函数,this就会动态指向被点击的按钮对象。
另外,如果函数体很复杂,有许多行,或者函数内部有大量的读写操作,不单纯是为了计算值,这时也不应该使用箭头函数,而是要使用普通函数,这样可以提高代码可读性。
参考资料:
结尾
如果我的文章对你有帮助,你的👍就是对我的最大支持^_^
我是阿林,输出洞见技术,再会!
上一篇:
「前端每日一问(25)」说一下函数形参、实参、剩余参数、默认参数、隐式参数
下一篇: