一篇讲透:箭头函数、普通函数有什么区别

前言

📫 大家好,我是南木元元,热衷分享有趣实用的文章,希望大家多多支持,一起进步!

🍅 个人主页:南木元元****


目录

什么是箭头函数

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

更简洁的语法

箭头函数没有自己的this

箭头函数的this不会改变

箭头函数没有prototype属性

箭头函数不能作为构造函数

箭头函数不能使用arguments对象

箭头函数不能用作Generator函数

箭头函数不适用的场景

结语


什么是箭头函数

箭头函数是ES6 (ECMAScript 6)新增的使用箭头(=>)语法定义函数表达式的能力。任何可以使用函数表达式的地方,都可以使用箭头函数,并且它的语法比传统的函数表达式更加简洁。

javascript 复制代码
// 函数表达式
let functionExpressionSum = function(a, b) {
    return a + b;
}

// 箭头函数
let arrowSum = (a, b) => {
    return a + b;
}

下面就来详细讲解一下箭头函数和普通函数的区别。

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

更简洁的语法

  • 如果只有一个参数,可以不用括号。只有没有参数或多个参数的情况下,才需要使用括号。
javascript 复制代码
// 只有一个参数,可以不用括号,以下两种写法都有效
let double = (x) => { return 2 * x; };
let triple = x => { return 3 * x; };

// 没有参数需要括号
let getRandom = () => { return Math.random(); };

// 多个参数需要括号
let sum = (a, b) => { return a + b; };

// 无效的写法:
let multiply = a, b => { return a * b; };
  • 如果函数体的返回值只有一句,可以省略大括号(省略大括号会隐式返回这行代码的值)。
javascript 复制代码
// 以下两种写法都有效,而且返回相应的值
let double = (x) => { return 2 * x; };
let triple = (x) => 3 * x;

// 无效的写法
let multiply = (a, b) => return a * b;
  • 如果函数体不需要返回值,且只有一句话,可以给这个语句前面加一个void关键字。
javascript 复制代码
// 最常见的就是调用一个函数
let fn = () => void doesNotReturn();

由于其更简洁的语法,箭头函数的一个用处就是简化回调函数。

javascript 复制代码
// 普通函数写法
var result = arr.sort(function (a, b) {
  return a - b;
});

// 箭头函数写法
var result = arr.sort((a, b) => a - b);

箭头函数没有自己的this

所有函数在执行时,会创建一个函数执行上下文,普通函数的执行上下文中会有一个变量this,而箭头函数没有,箭头函数不会创建自己的this对象,只会继承在自己作用域的上一层this。

javascript 复制代码
var id = 'Global'

// 箭头函数定义在全局作用域
let fun1 = () => {
  console.log(this.id)
}

fun1() // 'Global'

输出:

可以⽤Babel理解⼀下箭头函数:

javascript 复制代码
// ES6 
const obj = { 
  getArrow() { 
    return () => { 
      console.log(this === obj); 
    }; 
  } 
}

// 转化后的ES5
var obj = { 
   getArrow: function getArrow() { 
     var _this = this; 
     return function () { 
        console.log(_this === obj); 
     }; 
   } 
};

上面代码中,转换后的ES5版本清楚地说明了,箭头函数里没有自己的this,而是引用外层的this。

箭头函数的this不会改变

箭头函数没有自己的this,所以箭头函数中this的指向在它定义时就已经确定了,之后不会改变。

javascript 复制代码
var name = 'GLOBAL';
var obj = {
    name: '南木元元',
    getName1: function(){
        console.log(this.name);
    },
    getName2: () => {
        console.log(this.name);
    }
};
obj.getName1();    // '南木元元'
obj.getName2();    // 'GLOBAL'

输出结果:

对象obj的方法b是使用箭头函数定义的,这个函数中的this就永远指向它定义时所处的全局执行环境中的this,即便这个函数是作为对象obj的方法调用,this依旧指向Window对象。所以其实定义对象的方法是不适合使用箭头函数的。

此外,call()、apply()、bind()等方法也不能改变箭头函数中this的指向。

javascript 复制代码
var id = 'Global';
let fun1 = () => {
    console.log(this.id)
};
fun1();                     // 'Global'
// this的指向不会改变
fun1.call({id: 'Obj'});     // 'Global'
fun1.apply({id: 'Obj'});    // 'Global'
fun1.bind({id: 'Obj'})();   // 'Global'

输出结果:

箭头函数没有prototype属性

来看下面代码。

javascript 复制代码
let fn = function(name) {
    console.log(name);
}
let fn2 = name => console.log(name);
console.log(fn.prototype);
console.dir(fn2.prototype);

输出结果:

箭头函数不能作为构造函数

上面说了,箭头函数没有自己的this,没有prototype属性,所以也就不能用作构造函数,即不可以对箭头函数使用new命令,否则会抛出错误。

javascript 复制代码
let fn = (name, age) => {
    this.name = name;
    this.age = age;
}

// 报错
let p = new fn('南木元元', 18);

输出结果:

为什么会这样呢?这其实跟new内部实现有关,new的实现步骤如下:

  • 创建一个新的空对象
  • 设置原型,将对象的原型设置为函数的prototype对象
  • 让函数的this指向这个对象,执行构造函数的代码
  • 返回新的对象
javascript 复制代码
function myNew(constructor, ...args) {
  // 基于原型链 创建一个新对象,并且继承构造函数constructor的原型对象prototype上的属性
  let newObj = Object.create(constructor.prototype);
  // 执行构造函数,并让this指向这个新对象
  let res = constructor.apply(newObj, args); 
  // 如果函数的执行结果有返回值并且是一个对象, 返回执行的结果, 否则, 返回新创建的对象
  return typeof res === 'object' ? res: newObj;
}

上面的第二、三步,箭头函数都是没有办法执行的。

箭头函数不能使用arguments对象

arguments是一个对应于传递给函数的参数的类数组对象。

arguments是在所有普通函数中都可用的一个类数组对象,类数组不是数组,而是类似数组的对象**,**它除了length属性和索引之外,不能调用数组的方法。

所以通常会使用Array.prototype.slice.call(arguments)/Array.from(arguments)/[...arguments]的方式,将它转换成一个数组。

javascript 复制代码
let fn = function () {
    console.log(arguments);
    console.log(Array.prototype.slice.call(arguments));
}
fn('param1', 'param2');

输出结果:

箭头函数不可以使用arguments对象,该对象在函数体内不存在。

javascript 复制代码
let fn = (name, age) => console.log(arguments);
// 报错
fn('南木元元', 18);

输出结果:

在箭头函数中访问arguments实际上获得的是它外层函数的arguments值。

javascript 复制代码
let fn = function(name, age) {
    let fn2 = name => {
        console.log(arguments);
    }
    fn2();
}
fn('南木元元', 18);

输出结果:

那么如果一定要用呢?可以用ES6中的rest参数代替。

javascript 复制代码
let fn = (...args) => console.log(args);
fn('南木元元', 18);

输出结果:

上述代码使用了rest参数(形式为**...变量名**)获取函数的多余参数,这样就不需要使用arguments对象了。

箭头函数不能用作Generator函数

箭头函数内部不可以使用yield命令,因此箭头函数不能用作Generator函数。

javascript 复制代码
let fn = function *() {
    yield '南木元元';
}
let p = fn();
console.log(p.next());

输出:

javascript 复制代码
let fn = *() => {
    yield '南木元元';
}
let p = fn();
console.log(p.next()); 

输出:

箭头函数不适用的场景

  • 对象方法,且方法内部使用this

第一个场景上面提到过,定义对象的方法并且方法内部使用this时不适合用箭头函数。

javascript 复制代码
var name = 'GLOBAL';
var obj = {
    name: '南木元元',
    getName: () => {
        console.log(this.name);
    }
};
obj.getName();    // 'GLOBAL'

上述代码中,调用obj.getName()方法时,如果是普通函数,该方法内部的this指向调用它的那个对象;如果写成上面那样的箭头函数,使得this指向了全局对象,因此不会得到预期结果。这是因为对象不构成单独的作用域,导致getName箭头函数定义时的作用域就是全局作用域。

  • 需要动态this

第二个场合是需要动态this的时候,也不应使用箭头函数。

javascript 复制代码
var button = document.getElementById('btn');
button.addEventListener('click', () => {
    console.log(this);    //由于使用了箭头函数,this会指向全局对象Window
});

上面代码运行时,点击按钮会报错,因为button的监听函数是一个箭头函数,导致里面的this就是全局对象。如果改成普通函数,this就会动态指向被点击的按钮对象。

结语

本文主要总结了箭头函数和普通函数的几大区别,箭头函数虽然语法简洁,但也有一些场合不适用,需要根据不同的场景选择使用合适的函数。

🔥如果此文对你有帮助的话,欢迎💗关注、👍点赞、⭐收藏、**✍️评论,**支持一下博主~

相关推荐
崔庆才丨静觅2 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60613 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了3 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅3 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅3 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅4 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment4 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅4 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊4 小时前
jwt介绍
前端
爱敲代码的小鱼4 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax