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

151 阅读4分钟

前言

在ES6中,我们引进了一种新的函数:箭头函数箭头函数表达式的语法比普通函数表达式的语法更加简洁,并且没有自己的thisargumentsupernew.target。箭头函数的表达式更适合那些本来需要匿名函数的地方,并且不能用他来作构造函数

什么是箭头函数

箭头函数相当于匿名函数,并且简化了函数的定义。箭头函数有两种定义的格式:

x => x * x

这种写法相当于:

function (x) {
    return x * x
}

当箭头函数只包含一个表达式和参数时,我们可以省略()和 {...}和return

另一种写法:

    x => {
        if (x > 10) {
            return x * x
        } else {
            return - x * x
        }
    }

当箭头函数包含多条语句的时候,这个时候就不能省略{...}和return

当参数只有一个的时候,()可以省略

(x) => {
    return x + 1
} 

x => {
    return x + 1
}

是同样的意思

当需要返回一个一个对象的时候,写法如下:

x = ({foo : x})

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

This是可变的

箭头函数看上去是匿名函数的一种缩写,但实际上,箭头函数与普通函数有着很大的区别,箭头函数的this是词法作用域,由上下文确认,是不变的。普通函数的This是由调用的对象确认的,在函数定义时,无法确定普通函数的This指向,This的执行时可变的。

    var name = 'zzz'
    var a = {
        name : 'hhh',
        say : function () {
            console.log('say:', this.name );
        },
        say1: () => {
            console.log('say1', this.name);
        }
    }
    a.say()
    a.say1()

image.png

对于普通函数来说,内部的this指向函数运行时所在的对象。这对箭头函数并不成立,它没有自己的this对象,内部的this就是定义时上层作用域中的This。也就是说,普通函数的This是可变的,而箭头函数的This在定义时就决定好的,是不可变的

没有自己的This

我们可以通过下面这个例子来看看箭头函数是否有自己的This

    const obj = {
        a : () => {
            console.log(this);
        }
    }
    obj.a()

    const obj1 = {
        a : function() {
            console.log(this);
        }
    }
    obj1.a()

image.png

对象obj1中没有使用箭头函数,直接输出他的this,因为是obj1调用函数a,所以输出的This指向为对象;对象obj中使用了箭头函数,它也输出了this,同时是对象调用这个函数,但它的This指向并不是对象,而是window
如果箭头函数有自己的This,它输出也应该是object,但它输出的This指向是window,且箭头函数的This是它上一层作用域中的This

箭头函数的This永远不会改变,call,apply,bind也无法改变

一般情况下,我们可以使用call,apply,bind来改变函数的this指向,但在箭头函数中,由于箭头函数的this在定义时就确认了,且永远指向它定义时的上层作用域中的this,所以这些方法无法改变箭头函数的this指向。

    var name = 'zzz'
    var a = {
        name : 'hhh',
        say : function () {
            console.log(this.name);
        },
        say1 : () => {
            console.log(this.name);
        }
    }
    a.say.call({name: 666})
    a.say1.call({name: 999})

image.png

我们在调用时,想通过call来改变函数的this指向,第一个函数say是一个普通函数,它经过call的调用,输出的值为666;第二个函数say1是一个箭头函数,它也经过了call的调用,但它输出的值还是zzz,说明箭头函数的this指向没有改变。箭头函数的this永远不会改变,即使使用call,apply,bind也无法改变。

没有arguments

一般普通函数中,都存在一个argument的类数组来存储调用函数时所传入的参数。

    function b(b) {
        console.log(arguments[0]);
    }
    b(2)

image.png

但在箭头函数中,没有arguments这个类数组。

    let a = {
        test: (a) => {
            console.log(arguments[0]);
        }
    }
    a.test(1)

image.png

虽然箭头函数没有自己的arguments,但我们可以通过箭头函数来访问外围函数的arguments

    function constant() {
        return () => arguments[0]
    }
    var result = constant(1)
    console.log(result());

image.png

如果要访问箭头函数中的参数,可以通过命名参数,或是rest参数的形式访问参数

不能使用new关键字调用

在JS的函数内部有两个方法:callconstrouct
当我们通过new调用函数时,执行constrouct也就是构造器的方法来创建一个实例对象,然后再执行函数体,将this绑定到实体上。当直接调用时,执行call方法,直接执行函数体。
箭头函数并没有constrouct方法,不能被当做构造函数,如果通过new关键字来调用,则会报错。

    var Foo = () => {}
    var foo = new Foo()

image.png

没有原型

JS中所有的对象都是通过new关键字来创建的,每个函数都有一个属性prototype,但箭头函数没有。

    var Foo = () => {}
    console.log(Foo.prototype);

image.png

没有super

箭头函数连原型都没有,那自然就没有super来访问父类的属性。