'ฟังก์ชันลูกศร' และ 'ฟังก์ชัน' เทียบเท่า / ใช้แทนกันได้หรือไม่?

Dec 19 2015

ฟังก์ชัน Arrow ใน ES2015 ให้ไวยากรณ์ที่กระชับยิ่งขึ้น

  • ฉันสามารถแทนที่การประกาศ / นิพจน์ฟังก์ชันทั้งหมดของฉันด้วยฟังก์ชันลูกศรได้หรือไม่
  • ฉันต้องระวังอะไรบ้าง?

ตัวอย่าง:

ฟังก์ชันตัวสร้าง

function User(name) {
  this.name = name;
}

// vs

const User = name => {
  this.name = name;
};

วิธีการต้นแบบ

User.prototype.getName = function() {
  return this.name;
};

// vs

User.prototype.getName = () => this.name;

วิธีวัตถุ (ตามตัวอักษร)

const obj = {
  getName: function() {
    // ...
  }
};

// vs

const obj = {
  getName: () => {
    // ...
  }
};

การโทรกลับ

setTimeout(function() {
  // ...
}, 500);

// vs

setTimeout(() => {
  // ...
}, 500);

ฟังก์ชัน Variadic

function sum() {
  let args = [].slice.call(arguments);
  // ...
}

// vs
const sum = (...args) => {
  // ...
};

คำตอบ

817 FelixKling Dec 19 2015 at 00:58

tl; dr: ไม่! ฟังก์ชันลูกศรและการประกาศฟังก์ชัน / นิพจน์ไม่เทียบเท่าและไม่สามารถแทนที่แบบสุ่มสี่สุ่มห้าได้
หากฟังก์ชั่นที่คุณต้องการที่จะเปลี่ยนไม่ได้ใช้this, argumentsและไม่ได้เรียกว่ามีnewแล้วใช่


จึงมักจะเป็น: มันขึ้นอยู่กับ ฟังก์ชันลูกศรมีพฤติกรรมที่แตกต่างจากการประกาศฟังก์ชัน / นิพจน์ดังนั้นเรามาดูความแตกต่างกันก่อน:

1. คำศัพท์thisและarguments

ฟังก์ชันลูกศรไม่มีของตัวเองthisหรือการargumentsผูก แต่ตัวระบุเหล่านั้นจะได้รับการแก้ไขในขอบเขตคำศัพท์เช่นเดียวกับตัวแปรอื่น ๆ นั่นหมายความว่าภายในฟังก์ชันลูกศรthisและargumentsอ้างถึงค่าของthisและargumentsในสภาพแวดล้อมฟังก์ชันลูกศรถูกกำหนดไว้ใน (เช่นฟังก์ชันลูกศร "นอก"):

// Example using a function expression
function createObject() {
  console.log('Inside `createObject`:', this.foo);
  return {
    foo: 42,
    bar: function() {
      console.log('Inside `bar`:', this.foo);
    },
  };
}

createObject.call({foo: 21}).bar(); // override `this` inside createObject

// Example using a arrow function
function createObject() {
  console.log('Inside `createObject`:', this.foo);
  return {
    foo: 42,
    bar: () => console.log('Inside `bar`:', this.foo),
  };
}

createObject.call({foo: 21}).bar(); // override `this` inside createObject

ในกรณีการแสดงออกของฟังก์ชันthisหมายถึงวัตถุที่สร้างขึ้นภายในไฟล์createObject. ฟังก์ชั่นในกรณีที่ลูกศรthisหมายถึงthisของcreateObjectตัวเอง

สิ่งนี้ทำให้ฟังก์ชันลูกศรมีประโยชน์หากคุณต้องการเข้าถึงthisสภาพแวดล้อมปัจจุบัน:

// currently common pattern
var that = this;
getData(function(data) {
  that.data = data;
});

// better alternative with arrow functions
getData(data => {
  this.data = data;
});

หมายเหตุว่าเรื่องนี้ก็หมายความว่าเป็นไม่ได้ที่เป็นไปได้ในการตั้งค่าฟังก์ชั่นของลูกศรthisด้วยหรือ.bind.call

หากคุณไม่ค่อยคุ้นเคยthisให้ลองอ่าน

2. ไม่สามารถเรียกใช้ฟังก์ชันลูกศรด้วย new

ES2015 แยกความแตกต่างระหว่างฟังก์ชันที่สามารถเรียกและฟังก์ชันที่สามารถสร้างได้ ถ้าฟังก์ชันสามารถสร้างได้ก็สามารถเรียกด้วย newเช่นnew User(). ถ้าฟังก์ชันสามารถเรียกใช้ได้ก็สามารถเรียกได้โดยไม่ต้องnew(เช่นการเรียกฟังก์ชันปกติ)

ฟังก์ชันที่สร้างขึ้นผ่านการประกาศฟังก์ชัน / นิพจน์มีทั้งที่สร้างได้และสามารถเรียกใช้ได้
ฟังก์ชันลูกศร (และวิธีการ) สามารถเรียกใช้ได้เท่านั้น classตัวสร้างสามารถสร้างได้เท่านั้น

หากคุณพยายามเรียกใช้ฟังก์ชันที่เรียกไม่ได้หรือสร้างฟังก์ชันที่ไม่สามารถสร้างได้คุณจะได้รับข้อผิดพลาดรันไทม์


เมื่อทราบสิ่งนี้เราสามารถระบุสิ่งต่อไปนี้ได้

เปลี่ยนได้:

  • ฟังก์ชันที่ไม่ใช้thisหรือarguments.
  • ฟังก์ชันที่ใช้กับ .bind(this)

ไม่สามารถเปลี่ยนได้:

  • ฟังก์ชันตัวสร้าง
  • เพิ่มฟังก์ชัน / วิธีการในต้นแบบ (เพราะมักจะใช้this)
  • ฟังก์ชัน Variadic (หากใช้arguments(ดูด้านล่าง))

มาดูสิ่งนี้โดยใช้ตัวอย่างของคุณ:

ฟังก์ชันตัวสร้าง

newนี้จะไม่ทำงานเพราะฟังก์ชั่นลูกศรไม่สามารถเรียกว่ามี ใช้การประกาศฟังก์ชัน / นิพจน์หรือใช้classต่อไป

วิธีการต้นแบบ

ไม่น่าจะเป็นไปได้มากนักเนื่องจากวิธีการต้นแบบมักจะใช้thisเพื่อเข้าถึงอินสแตนซ์ หากไม่ได้ใช้thisคุณสามารถเปลี่ยนได้ อย่างไรก็ตามหากคุณสนใจไวยากรณ์ที่กระชับเป็นหลักให้ใช้classไวยากรณ์วิธีการที่กระชับ:

class User {
  constructor(name) {
    this.name = name;
  }
  
  getName() {
    return this.name;
  }
}

วิธีการของวัตถุ

ในทำนองเดียวกันสำหรับวิธีการในตัวอักษรวัตถุ หากเมธอดต้องการอ้างอิงอ็อบเจ็กต์เองthisโดยใช้นิพจน์ฟังก์ชันต่อไปหรือใช้ไวยากรณ์วิธีการใหม่:

const obj = {
  getName() {
    // ...
  },
};

การโทรกลับ

มันขึ้นอยู่กับ. คุณควรแทนที่อย่างแน่นอนหากคุณใช้นามแฝงด้านนอกthisหรือใช้.bind(this):

// old
setTimeout(function() {
  // ...
}.bind(this), 500);

// new
setTimeout(() => {
  // ...
}, 500);

แต่:ถ้ารหัสที่เรียกการโทรกลับตั้งค่าอย่างชัดเจนthisเป็นค่าเฉพาะเช่นเดียวกับที่มักเกิดขึ้นกับตัวจัดการเหตุการณ์โดยเฉพาะกับ jQuery และการเรียกกลับใช้this(หรือarguments) คุณจะไม่สามารถใช้ฟังก์ชันลูกศรได้

ฟังก์ชัน Variadic

เนื่องจากฟังก์ชันลูกศรไม่มีเป็นของตัวเองargumentsคุณจึงไม่สามารถแทนที่ด้วยฟังก์ชันลูกศรได้ อย่างไรก็ตาม ES2015 แนะนำทางเลือกในการใช้argumentsคือพารามิเตอร์ที่เหลือ

// old
function sum() {
  let args = [].slice.call(arguments);
  // ...
}

// new
const sum = (...args) => {
  // ...
};

คำถามที่เกี่ยวข้อง:

แหล่งข้อมูลเพิ่มเติม:

17 Ashutosh Jan 10 2020 at 03:22

ฟังก์ชั่นลูกศร => คุณสมบัติ ES6 ที่ดีที่สุดจนถึงตอนนี้ พวกเขาเป็นส่วนเสริมที่ทรงพลังอย่างมากสำหรับ ES6 ที่ฉันใช้อยู่ตลอดเวลา

เดี๋ยวก่อนคุณไม่สามารถใช้ฟังก์ชั่นลูกศรได้ทุกที่ในโค้ดของคุณมันจะไม่ทำงานในทุกกรณีเช่นthisเมื่อฟังก์ชันลูกศรไม่สามารถใช้งานได้ ไม่ต้องสงสัยเลยว่าฟังก์ชันลูกศรเป็นส่วนเสริมที่ยอดเยี่ยมซึ่งทำให้โค้ดมีความเรียบง่าย

แต่คุณไม่สามารถใช้ฟังก์ชันลูกศรเมื่อจำเป็นต้องใช้บริบทแบบไดนามิก: การกำหนดวิธีการสร้างวัตถุด้วยตัวสร้างรับเป้าหมายจากสิ่งนี้เมื่อจัดการกับเหตุการณ์

ไม่ควรใช้ฟังก์ชันลูกศรเนื่องจาก:

  1. พวกเขาไม่มี this

    โดยใช้ "การกำหนดขอบเขตศัพท์" เพื่อหาว่าค่าของ " this" ควรเป็นเท่าใด ในคำง่ายๆการกำหนดขอบเขตคำศัพท์จะใช้ " this" จากภายในเนื้อความของฟังก์ชัน

  2. พวกเขาไม่มี arguments

    ฟังก์ชันลูกศรไม่มีargumentsวัตถุ แต่ฟังก์ชันเดียวกันสามารถทำได้โดยใช้พารามิเตอร์ส่วนที่เหลือ

    let sum = (...args) => args.reduce((x, y) => x + y, 0) sum(3, 3, 1) // output - 7 `

  3. ไม่สามารถใช้กับไฟล์ new

    ฟังก์ชั่นลูกศรไม่สามารถเป็นตัวกำหนดได้เนื่องจากไม่มีคุณสมบัติต้นแบบ

เมื่อใดควรใช้ฟังก์ชั่นลูกศรและเมื่อไม่:

  1. อย่าใช้เพื่อเพิ่มฟังก์ชันเป็นคุณสมบัติในตัวอักษรของวัตถุเพราะเราไม่สามารถเข้าถึงสิ่งนี้ได้
  2. นิพจน์ฟังก์ชันเหมาะที่สุดสำหรับเมธอดอ็อบเจ็กต์ ลูกศรฟังก์ชั่นที่ดีที่สุดสำหรับการเรียกกลับหรือวิธีการเช่นmap, หรือreduceforEach
  3. ใช้การประกาศฟังก์ชันสำหรับฟังก์ชันที่คุณเรียกด้วยชื่อ (เนื่องจากถูกยกขึ้น)
  4. ใช้ฟังก์ชันลูกศรสำหรับการโทรกลับ (เนื่องจากมีแนวโน้มที่จะสั้นกว่า)
2 toddmo May 16 2020 at 08:56

ในการใช้ฟังก์ชันลูกศรfunction.prototype.callฉันได้สร้างฟังก์ชันตัวช่วยในต้นแบบวัตถุ:

  // Using
  // @func = function() {use this here} or This => {use This here}
  using(func) {
    return func.call(this, this);
  }

การใช้งาน

  var obj = {f:3, a:2}
  .using(This => This.f + This.a) // 5

แก้ไข

คุณไม่จำเป็นต้องมีผู้ช่วย คุณสามารถทำได้:

var obj = {f:3, a:2}
(This => This.f + This.a).call(undefined, obj); // 5