在项目开发中,包括面试的时候经常会遇到或问到箭头函数和普通函数有什么区别当我们猛然去想,好像一直以来只记得箭头函数中没有this
,当我们在箭头函数中使用this
会获取该函数上层的this
值。那么除此之外,就没有其他区别了吗,当然不是。这里我们就来总结总结。
mdn
中对箭头函数特点的描述是这样的:箭头函数表达式的语法比函数表达式更简洁,并且没有自己的this
、arguments
、super
或new.target
。箭头函数表达式更适用于那些本来需要匿名函数的地方,并且不能作构造函数。
由此可以看出箭头函数和普通函数的区别有以下几点:
- 语法形式不同,箭头函数更简短
- 没有单独的
this
- 通过
call
或apply
调用会忽略第一个参数,只能传递参数,不能绑定this
- 不绑定
arguments
- 不能使用
new
操作 - 没有
prototype
属性 - 不能使用
yield
关键字 - 箭头函数具有与常规函数不同的特殊运算符优先级解析规则
在箭头函数书写过程中也有一些需要注意的点:
- 返回对象字面量需要在外层添加小括号
- 箭头函数和箭头之间不能换行
箭头函数与普通函数的区别
语法形式不同,箭头函数更短
这里就不多做赘述,mdn
上的例子已经非常全面了。
var elements = [
'Hydrogen',
'Helium',
'Lithium',
'Beryllium'
];
elements.map(function(element) {
return element.length;
}); // 返回数组:[8, 6, 7, 9]
// 上面的普通函数可以改写成如下的箭头函数
elements.map((element) => {
return element.length;
}); // [8, 6, 7, 9]
// 当箭头函数只有一个参数时,可以省略参数的圆括号
elements.map(element => {
return element.length;
}); // [8, 6, 7, 9]
// 当箭头函数的函数体只有一个 `return` 语句时,可以省略 `return` 关键字和方法体的花括号
elements.map(element => element.length); // [8, 6, 7, 9]
// 在这个例子中,因为我们只需要 `length` 属性,所以可以使用参数解构
// 需要注意的是字符串 `"length"` 是我们想要获得的属性的名称,而 `lengthFooBArX` 则只是个变量名,
// 可以替换成任意合法的变量名
elements.map(({ "length": lengthFooBArX }) => lengthFooBArX); // [8, 6, 7, 9]
箭头函数没有单独的this
这算是箭头函数与普通函数区别中最为重要的一点了,毕竟this
的使用还是很频繁的。
在箭头函数出现之前,每一个新函数根据他是如何被调用的来定义这个函数的this值:
- 如果该函数是一个构造函数,
this
指针指向一个新生成的对象。 - 在严格模式下的函数调用下,
this
指向undefined
- 如果该函数是一个对象的方法,则它的
this
指向这个对象
等,详细内容可以看this指向
在箭头函数中不会创建自己的this
,它只会从自己的作用域链的上一层继承this
。我们可以看一下具体案例:
function Person(){
console.log(this); // Person {}
setTimeout(() => {
console.log(this); //Person {}
}, 1000);
}
var p = new Person();
我们可以看到第一个this
是按照普通函数this
指向来指定的,指向了新生成的p
变量。但是在setTimeout
的回调箭头函数中的this
与其上层函数Person
函数完全相同。
通过call或apply调用会忽略第一个参数,只能传递参数,不能绑定this
由于箭头函数没有自己的this
指针,通过call()
或apply()
方法调用一个函数时,只能传递参数(不能绑定this
),第一个参数会被忽略,同样的使用bind()
调用是一样的。当然也不会报错,函数会被正常调用,只是不会绑定this
值。
let fun = (num1, num2) => {
console.log(num1);
console.log(num2);
console.log(this);
}
let arr = new Array();
fun.call(arr, 2, 3); // 2 3 Window
fun.call(2, 3); // 3 undefined Window
不绑定arguments
箭头函数不绑定arguments
对象。
var args = function(){
return arguments[0]
}
var arr = () => arguments[0];
args(1) // 1
args(1) // VM1109:1 Uncaught ReferenceError: arguments is not defined
我们可以通过剩余参数来得到传入的实际参数。
var arr = (...args) => args;
arr(1, 2) // [1, 2]
不能使用new操作
箭头函数不能用作构造器,和new
一起用会抛出错误。
let Fun = () => {}
let fun = new Fun() // VM1867:1 Uncaught TypeError: Fun is not a constructor
没有prototype属性
箭头函数没有prototype
属性,也就没有constructor
了。
let Fun = () => {}
console.log(Fun.prototype) //undefined
不能使用yield关键字
yield
关键字通常不能在箭头函数中使用(除非是嵌套在允许使用的函数内)。因此,箭头函数不能用作函数生成器。
箭头函数具有与常规函数不同的特殊运算符优先级解析规则
let callback;
callback = callback || function() {}; // ok
callback = callback || () => {};
// Uncaught SyntaxError: Malformed arrow function parameter list
callback = callback || (() => {}); // ok
箭头函数语法注意点
返回对象字面量需要在外层添加小括号
在箭头函数中,只有一个返回的话可以不用写return,(a, b) => {a + b}
就表示会把传过来的参数相加。但是如果我们要返回一个字面量的对象,直接写成(a, b) => {sum: a + b}
是不可以的,因为解析的时候会把{}
内部作为一个代码块去解析。
let sum = (a, b) => {sum: a + b}
console.log(sum(1, 2)) // undefined
let sum = (a, b) => ({sum: a + b})
console.log(sum(1, 2)) // {sum: 3}
箭头函数在参数和箭头之间不能换行
let sum = (a, b)
=> {a + b} // Uncaught SyntaxError: Unexpected token '=>'