箭头函数的有点和缺点

文章讲述了JavaScript中this的指向问题,特别是在箭头函数中的行为,以及箭头函数在多层嵌套时的简洁性。同时,讨论了super关键字在继承和调用父类方法中的应用,强调了在需要动态this或使用arguments、super、new.target时不应使用箭头函数。
摘要由CSDN通过智能技术生成

this题目

以下代码中有几个this?

function foo() {
  return () => {
    return () => {
      return () => {
        console.log('id:', this.id);
      };
    };
  };
}
var f = foo.call({id: 1});
var t1 = f.call({id: 2})()(); // id: 1
var t2 = f().call({id: 3})(); // id: 1
var t3 = f()().call({id: 4}); // id: 1

上面代码之中,只有一个this,就是函数foo的this,所以t1、t2、t3都输出同样的结果。因为所有的内层函数都是箭头函数,都没有自己的this,它们的this其实都是最外层foo函数的this。

优缺点

由于箭头函数在定义的时候被绑定,下面两个场合不应该使用箭头函数。

    const cat = {
      lives: 9,
      jumps: () => {
        console.log("this是什么", this);
        this.lives--;
      },
    };
    cat.jumps();

可以发现this是window对象。

如果是普通函数,该方法内部的this指向cat;如果写成上面那样的箭头函数,使得this指向全局对象,因此不会得到预期结果。这是因为对象不构成单独的作用域,导致jumps箭头函数定义时的作用域就是全局作用域。

这和我们之前举的例子的不同:

    var handler = {
      id: "123456",
      init: function () {
        document.addEventListener(
          "click",
          (event) => this.fun(event.type),
          false
        );
      },
      fun: function (type) {
        console.log("this指向谁", this);
      },
      arrow: () => {
        console.log("我是箭头函数,this指向谁", this);
      },
    };
    handler.init();
    handler.arrow();

在之前的例子中,箭头函数的this实际上是外层函数的this,他的外层函数是谁呢?(也就是init)的this。而init是一个普通函数,所以谁调用它,this就指向谁。所以this就是handler对象。

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

var button = document.getElementById('button');
button.addEventListener('click', () => {
 this.classList.add('on');
});

上面代码运行时,点击按钮会报错,因为button的监听函数是一个箭头函数,箭头函数不会绑定自己的 this 值,它会捕获其所在上下文的 this 值。如果你使用箭头函数指向上一级上下文的 this,而上一层的this就是全局对象window。window没classList属性,所以自然会报错。我们希望this指向dom对象,也就是这个按钮,此时必须使用普通函数。

优点

在函数有多重嵌套时,可以使得函数简洁易懂

function insert(value) {
  return {into: function (array) {
    return {after: function (afterValue) {
      array.splice(array.indexOf(afterValue) + 1, 0, value);
      return array;
    }};
  }};
}
insert(2).into([1, 3]).after(1); //[1, 2, 3]

如果用箭头函数改写:

let insert = (value) => ({into: (array) => ({after: (afterValue) => {
  array.splice(array.indexOf(afterValue) + 1, 0, value);
  return array;
}})});
insert(2).into([1, 3]).after(1); //[1, 2, 3]

其他特性

除了this,以下三个变量在箭头函数之中也是不存在的,指向外层函数的对应变量:arguments、super、new.target。

function foo() {
  setTimeout(() => {
    console.log('args:', arguments);
  }, 100);
}
foo(2, 4, 6, 8)
// args: [2, 4, 6, 8]

上面代码中,箭头函数内部的变量arguments,其实是函数foo的arguments变量。

super的作用

在 JavaScript 中,super 是一个关键字,用于在子类中调用父类的方法或访问父类的属性。它主要用于继承和类之间的关系,使子类能够重用和扩展父类的功能。

在使用 super 时,通常有两个主要用途:

调用父类的构造函数:在子类的构造函数中使用 super() 可以调用父类的构造函数,从而初始化父类的属性。这是确保子类实例拥有父类属性的一种方式。

访问父类的方法:在子类的方法中,可以使用 super 关键字调用父类中的同名方法,以便在子类中扩展父类的方法。

以下是 super 关键字的两种用法的示例:

1.调用父类的构造函数:

class Animal {
  constructor(name) {
    this.name = name;
  }

  makeSound() {
    console.log("Some generic sound");
  }
}

class Dog extends Animal {
  constructor(name, breed) {
    super(name); // 调用父类的构造函数来初始化父类属性
    this.breed = breed;
  }

  makeSound() {
    super.makeSound(); // 调用父类的方法
    console.log("Woof! Woof!");
  }
}

const myDog = new Dog("Buddy", "Golden Retriever");
console.log(myDog.name); // 输出: Buddy
console.log(myDog.breed); // 输出: Golden Retriever
myDog.makeSound(); // 输出: Some generic sound   Woof! Woof!

在上面的例子中,Dog 是 Animal 的子类。在 Dog 类的构造函数中,使用 super(name) 来调用父类 Animal 的构造函数,确保在创建 Dog 实例时会初始化 name 属性。在 Dog 类的 makeSound() 方法中,使用 super.makeSound() 来调用父类 Animal 的 makeSound() 方法,以便在子类中扩展父类的功能。

2.访问父类方法

class Vehicle {
  constructor(type) {
    this.type = type;
  }

  start() {
    console.log(`Starting ${this.type}`);
  }
}

class Car extends Vehicle {
  constructor(type, brand) {
    super(type);
    this.brand = brand;
  }

  start() {
    super.start(); // 调用父类的方法
    console.log(`Driving the ${this.brand} car`);
  }
}

const myCar = new Car("car", "Toyota");
myCar.start(); // 输出: Starting car   Driving the Toyota car

在上面的例子中,Car 是 Vehicle 的子类。在 Car 类的 start() 方法中,使用 super.start() 来调用父类 Vehicle 的 start() 方法,以便在子类中扩展父类的方法。

总结:super 是用于在 JavaScript 类中访问和调用父类方法和构造函数的关键字,它在继承和类之间的关系中起着重要的作用。

如果不用super会放生什么?
https://www.imqianduan.com/javascript/405.html

什么是 new.target?

https://blog.csdn.net/Hoshizola/article/details/119462690

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

codereasy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值