箭头函数作为ES6中新加入的语法,以其简化了我们的代码和让开发人员摆脱了“飘忽不定”的this指向等特点,深受广大开发者的喜爱,同时也深受面试官的喜爱,箭头函数常因其不同于普通函数的特点出现在各大公司的面试题中,so,本文会对箭头函数与普通函数进行一些分析。
如果这篇文章有帮助到你,❤️关注+点赞❤️鼓励一下作者,文章公众号首发,关注 前端南玖 第一时间获取最新的文章~
介绍箭头函数(Arrow Function)ES6中允许使用“箭头”(=>) 来定义函数。箭头函数相当于匿名函数,并且简化了函数定义。
我们来看一下如何使用 (=>) 来声明一个函数:
// 箭头函数 let foo = (name) => `我是${name}` foo('南玖') // 我是南玖 // 等同于下面这个普通函数 let foo2 = function(name) { return `我是${name}` }箭头函数有两种格式,一种像上面的,只包含一个表达式,连{ ... }和return都省略掉了。还有一种可以包含多条语句,这时候就不能省略{ ... }和return:
let foo = (name) => { if(name){ return `我是${name}` } return '前端南玖' } foo('南玖') // 我是南玖⚠️这里需要注意的是如果箭头函数返回的是一个字面量对象,则需要用括号包裹该字面量对象返回
let foo = (name) => ({ name, job: 'front end' }) // 等同于 let foo2 = function (name) { return { name, job: 'front end' } }OK,箭头函数的基本介绍我们先看到这里,下面我们通过对比箭头函数与普通函数的区别来进一步了解箭头函数~
箭头函数与普通函数的区别我们可以通过打印箭头函数和普通函数来看看两者到底有什么区别:
let fn = name => { console.log(name) } let fn2 = function(name) { console.log(name) } console.dir(fn) // console.dir(fn2) //从打印结果来看,箭头函数与普通函数相比,缺少了caller,arguments,prototype
声明方式不同,匿名函数声明一个普通函数需要使用关键字function来完成,并且使用function既可以声明成一个具名函数也可以声明成一个匿名函数
声明一个箭头函数则只需要使用箭头就可以,无需使用关键字function,比普通函数声明更简洁。
箭头函数只能声明成匿名函数,但可以通过表达式的方式让箭头函数具名
this指向不同对于普通函数来说,内部的this指向函数运行时所在的对象,但是这一点对箭头函数不成立。它没有自己的this对象,内部的this就是定义时上层作用域中的this。也就是说,箭头函数内部的this指向是固定的,相比之下,普通函数的this指向是可变的。
var name = '南玖' var person = { name: 'nanjiu', say: function() { console.log('say:',this.name) }, say2: () => { console.log('say2:',this.name) } } person.say() // say: nanjiu person.say2() // say2: 南玖这里第一个say定义的是一个普通函数,并且它是作为对象person的方法来进行调用的,所以它的this指向的就是person,所以它应该会输出say: nanjiu
而第二个say2定义的是一个箭头函数,我们知道箭头函数本身没有this,它的this永远指向它定义时所在的上层作用域,所以say2的this应该指向的是全局window,所以它会输出say2: 南玖
我们也可以通过Babel 转箭头函数产生的 ES5 代码来证明箭头函数没有自己的this,而是引用的上层作用域中this。
// ES6 function foo() { setTimeout(() => { console.log('id:', this.id); }, 100); } // ES5 function foo() { var _this = this; setTimeout(function () { console.log('id:', _this.id); }, 100); }转换后的 ES5 版本清楚地说明了,箭头函数里面根本没有自己的this,而是引用的上层作用域中this。
箭头函数的this永远不会变,call、apply、bind也无法改变我们可以用call、apply、bind来改变普通函数的this指向,但是由于箭头函数的this指向在它定义时就已经确定了,永远指向它定义时的上层作用域中的this,所以使用这些方法永远也改变不了箭头函数this的指向。
var name = '南玖' var person = { name: 'nanjiu', say: function() { console.log('say:',this.name) }, say2: () => { console.log('say2:',this.name) } } person.say.call({name:'小明'}) // say: 小明 person.say2.call({name:'小红'}) // say2: 南玖还是上面那个例子,只不过我们在调用的时候使用call试图改变this指向,第一个say是一个普通函数,它经过call调用,打印出的是say: 小明,这说明普通函数的this已经改变了,第二个say2是一个箭头函数,它也经过call调用,但它打印出的仍然是say2: 南玖,这就能够证明箭头函数的this永远不会变,即使使用call、apply、bind也无法改变
箭头函数没有原型prototype let fn = name => { console.log(name) } let fn2 = function(name) { console.log(name) } console.log(fn.prototype) // undefined console.dir(fn2.prototype) // {constructor: ƒ} 箭头函数不能当成一个构造函数为什么箭头函数不能当成一个构造函数呢?我们先来用new调用一下看看会发生什么:
let fn = name => { console.log(name) } const f = new fn('nanjiu')结果符合我们的预期,这样调用会报错
我们知道new内部实现其实是分为以下四步:
新建一个空对象
链接到原型
绑定this,执行构造函数