箭头函数与普通函数对比

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

箭头函数的this指向规则:

1. 箭头函数没有prototype

直接看个例子就能说明:

let a = () =>{};
console.log(a.prototype); // undefined

function b() {};
console.log(b.prototype); // {constructor: ƒ}

2.箭头函数的this指向在定义的时候的外层第一个普通函数的this。

同样的我们来看一个例子:

let a,
	barObj = { msg: 'bar的this指向' };
	fooObj = { msg: 'foo的this指向' };
	
function bar() {
  a = () => {
    console.log(this, 'this指向定义的时候外层第一个普通函数'); // 
  }; // 在bar中定义 this继承于bar函数的this指向
}
function foo() {
  a(); 
}

bar.call(barObj); // 将bar的this指向barObj
foo.call(fooObj); // 将foo的this指向fooObj
// 结果:{ msg: 'bar的this指向' }

从这个例子中我们就可以看出,箭头函数的this指向继承于在定义a时bar()中this(barObj),而在foo中调用a时,虽然调用a函数的的foo()的this指向为fooObj,但这并没有修改a的指向,所以箭头函数的this指向和定义箭头的时有关,和运行时无关。

3.不能直接修改箭头函数的this指向

我们接下来尝试下直接修改箭头函数的this指向,看看有没有效果。

a.call(fooObj); // 结果:{ msg: 'bar的this指向' }

很明显,直接修改箭头函数的this指向并没有生效。
那么,如果我们想要修改箭头函数的this指向,就真的没有办法了吗?
仔细想一下,箭头函数的this指向是继承自外层第一个普通函数的,那如果我们去修改被继承的普通函数的this指向能不能改变箭头函数的this指向呢?

bar.call(fooObj); // 将bar普通函数的this指向barObj 然后内部的箭头函数也会指向barObj
a();  // {msg: "foo的this指向"}

可以看到我们修改被继承的普通函数的this指向,箭头函数的this指向也跟着改变了。

4. 箭头函数外层没有普通函数,严格模式和非严格模式下它的this都会指向window(全局对象)

在非严格模式下,普通函数默认绑定的this指向全局对象,在严格模式下this指向undefined。那么在非严格模式和严格模式下箭头函数的this又指向什么呢?

// 非严格模式
a = () => {console.log(this);};
a(); // Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}
// 严格模式
'use strict'; 
a = () => {console.log(this);};
a(); // Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}

经过我们测试,可以看到箭头函数在严格模式和非严格模式下它的this都会指向window(全局对象)。

箭头函数的arguments

1.当箭头函数的this指向全局,使用arguments会报未声明的错误。

我们直接来举个例子尝试一下:

let b = () => {
  console.log(arguments);
};
b(1, 2, 3, 4); // Uncaught ReferenceError: arguments is not defined

可以看到,这时使用确实arguments会报错,未声明arguments。
接着我们来看下箭头函数的this指向普通函数时的情况。

2.箭头函数的this指向继承自普通函数时,它的argumens继承于该普通函数

function bar() {
  console.log(arguments); // ['外层第二个普通函数的参数']
  bb('外层第一个普通函数的参数');
  function bb() {
    console.log(arguments); // ["外层第一个普通函数的参数"]
    let a = () => {
      console.log(arguments, 'arguments继承this指向的那个普通函数'); // ["外层第一个普通函数的参数"]
    };
    a('箭头函数的参数'); // this指向bb
  }
}
bar('外层第二个普通函数的参数');

// Arguments ["外层第二个普通函数的参数", callee: ƒ, Symbol(Symbol.iterator): ƒ]
// Arguments ["外层第一个普通函数的参数", callee: ƒ, Symbol(Symbol.iterator): ƒ]
// Arguments ["外层第一个普通函数的参数", callee: ƒ, Symbol(Symbol.iterator): ƒ] "arguments继承this指向的那个普通函数"

可以看到箭头函数的arguments继承于普通函数arguments。

箭头函数不支持重命名函数参数,普通函数的函数参数支持重命名

如下示例,普通函数的函数参数支持重命名,后面出现的会覆盖前面的,箭头函数会抛出错误:

function func1(a, a) {
  console.log(a, arguments); // 2 [1,2]
}

var func2 = (a,a) => {
  console.log(a); // 报错:在此不允许重复参数名称
};
func1(1, 2); func2(1, 2);

箭头函数的注意事项及不适用场景

箭头函数的注意事项

  1. 一条语句返回对象字面量,需要加括号,或者直接写成多条语句的return形式,否则像func中演示的一样,花括号会被解析为多条语句的花括号,不能正确解析。
var func1 = () => { foo: 1 }; // 想返回一个对象,花括号被当成多条语句来解析,执行后返回undefined
var func2 = () => ({foo: 1}); // 用圆括号是正确的写法
var func2 = () => {
  return {
    foo: 1 // 更推荐直接当成多条语句的形式来写,可读性高
  };
};
  1. 箭头函数在参数和箭头之间不能换行!
var func = ()
           => 1;  // 报错: Unexpected token =>
  1. 箭头函数的解析顺序相对靠前
let a = false || function() {}; // ok
let b = false || () => {}; // error
let c = false || (() => {}); // ok

箭头函数不适用场景:

我们先来看个例子:

const obj = {
  array: [1, 2, 3],
  sum: () => {
    // 根据上面说到的:外层没有普通函数this会指向全局对象
    return this.array.push('全局对象下没有array,这里会报错'); // 找不到push方法
  }
};
obj.sum();

因为这个箭头函数没有外层的普通函数,所以此时这个箭头函数的this指向全局对象。
当我们改写成下面这样的时候就没有问题了。

sum() {
  return this.array.push('this指向obj');
}

同样的,还有这个回调函数中的this:

const button = document.getElementById('myButton');
button.addEventListener('click', () => {
    this.innerHTML = 'Clicked button'; // this又指向了全局
});

同样的把箭头函数修改成普通函数就能解决。

小结

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

  1. 箭头函数没有prototype(原型),所以箭头函数本身没有this,箭头函数的this在定义的时候继承自外层第一个普通函数的this。
  2. 如果箭头函数外层没有普通函数,严格模式和非严格模式下它的this都会指向window(全局对象)。
  3. 箭头函数本身的this指向不能改变,但可以修改它要继承的对象的this。
  4. 箭头函数的this指向全局,使用arguments会报未声明的错误。箭头函数的this指向普通函数时,它的argumens继承于该普通函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值