क्या 'एरो फ़ंक्शंस' और 'फ़ंक्शंस' बराबर / विनिमेय हैं?


519

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);

वेरिएडिक कार्य

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

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

5
तीर कार्यों के बारे में इसी तरह के सवाल अधिक से अधिक ES2015 के अधिक लोकप्रिय होने के साथ आए हैं। मुझे ऐसा नहीं लगा कि इस मुद्दे के लिए एक अच्छा विहित प्रश्न / उत्तर था इसलिए मैंने इसे बनाया। यदि आपको लगता है कि पहले से ही एक अच्छा है, तो कृपया मुझे बताएं और मैं इसे डुप्लिकेट के रूप में बंद कर दूंगा या इसे हटा दूंगा। उदाहरणों को बेहतर बनाने या नए जोड़ने के लिए स्वतंत्र महसूस करें।
फेलिक्स क्लिंग

2
जावास्क्रिप्ट एक्मा 6 के बारे में सामान्य फ़ंक्शन को एरो फ़ंक्शन में कैसे बदलें ? बेशक, एक सामान्य प्रश्न उतना अच्छा और सामान्य कभी नहीं हो सकता है जितना विशेष रूप से एक विहित के लिए लिखा गया है।
बरगी

इस Plnkr उदाहरण को देखें चर केवल बटन द्वारा कहे जाने वाले प्रत्येक बार 1 thisसे बहुत अधिक timesCalledवेतन वृद्धि है। जो मेरे व्यक्तिगत प्रश्न का उत्तर देता है: .click( () => { } )और .click(function() { }) दोनों एक ही संख्या में कार्य करते हैं जब एक लूप में उपयोग किया जाता है जैसा कि आप प्लकर में गाइड काउंट से देख सकते हैं।
abbaf33f

जवाबों:


749

tl; डॉ: नहीं! एरो फ़ंक्शंस और फ़ंक्शन घोषणाएं / अभिव्यक्तियाँ समतुल्य नहीं हैं और इन्हें नेत्रहीन रूप से प्रतिस्थापित नहीं किया जा सकता है।
यदि आप जिस फ़ंक्शन को बदलना चाहते हैं वह उपयोग नहीं करता है this, argumentsऔर इसके साथ नहीं बुलाया जाता है new, तो हाँ।


जैसा कि अक्सर: यह निर्भर करता है । फ़ंक्शन फ़ंक्शन / अभिव्यक्तियों की तुलना में एरो फ़ंक्शंस का व्यवहार अलग-अलग होता है, इसलिए पहले अंतरों पर एक नज़र डालते हैं:

1. लेक्सिकल thisऔरarguments

एरो फ़ंक्शंस के पास अपना thisया argumentsबाध्यकारी नहीं है। इसके बजाय, उन पहचानकर्ताओं को किसी अन्य चर की तरह शाब्दिक दायरे में हल किया जाता है। इसका मतलब है कि एक तीर फ़ंक्शन के अंदर, thisऔर पर्यावरण में और argumentsमानों को संदर्भित करता है तीर फ़ंक्शन को (यानी "बाहर" तीर ") में परिभाषित किया गया है:thisarguments

// 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 )
  • वैरिएडिक फ़ंक्शन (यदि वे उपयोग करते हैं 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), आप नहीं कर सकते हैं एक तीर फ़ंक्शन का उपयोग !

वेरिएडिक कार्य

चूंकि एरो फ़ंक्शंस के पास अपना नहीं है arguments, आप बस उन्हें एक तीर फ़ंक्शन के साथ बदल नहीं सकते हैं। हालांकि, ES2015 उपयोग करने के लिए एक विकल्प प्रस्तुत करता है arguments: बाकी पैरामीटर

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

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

संबंधित प्रश्न:

आगे के संसाधन:


6
संभवतः यह उल्लेख के लायक है कि लेक्सिकल thisभी प्रभावित करता है superऔर यह कि उनके पास कोई नहीं है .prototype
loganfsmyth

1
यह भी उल्लेख करना अच्छा होगा कि वे सिंथेटिक रूप से विनिमेय नहीं हैं - एक तीर फ़ंक्शन ( AssignmentExpression) को हर जगह एक फ़ंक्शन एक्सप्रेशन ( PrimaryExpression) में नहीं छोड़ा जा सकता है और यह लोगों को बार-बार यात्रा करता है (विशेषकर तब से जब वह पार्स कर रहा है) प्रमुख जेएस कार्यान्वयन में त्रुटियां)।
JMM

@ जेएमएम: "यह लोगों को अक्सर यात्राएं करता है" क्या आप एक ठोस उदाहरण प्रदान कर सकते हैं? ऐनक पर स्किमिंग करते हुए, ऐसा लगता है कि जिन जगहों पर आप एफई लगा सकते हैं, लेकिन एएफ नहीं, वैसे भी रनटाइम एरर होंगे ...
फेलिक्स क्लिंग

ज़रूर, मेरा मतलब है कि फंक्शन एक्सप्रेशन ( () => {}()) या कुछ ऐसा करने के लिए एरो फंक्शन को शुरू करने की कोशिश करने जैसा सामान x || () => {}। यही मेरा मतलब है: रनटाइम (पार्स) त्रुटियां। (और हालांकि यह मामला है, काफी बार लोगों को लगता है कि त्रुटि त्रुटि में है।) क्या आप तर्क त्रुटियों को कवर करने की कोशिश कर रहे हैं जो किसी का ध्यान नहीं जाएगा क्योंकि वे आवश्यक रूप से त्रुटि करते हैं जब पार्स या निष्पादित किया जाता है? new'आईएनजी एक रनटाइम त्रुटि सही है?
JMM

यहाँ जंगली में इसके कुछ लिंक आ रहे हैं: substack / node-browserify # 1499 , babel / babel-eslint # 245 (यह एक async तीर है, लेकिन मुझे लगता है कि यह एक ही मूल मुद्दा है), और मुद्दों का एक गुच्छा कोलाहल जो अभी मुश्किल है, लेकिन यहाँ एक T2847 है
JMM

11

एरो फ़ंक्शंस => अब तक का सबसे अच्छा ईएस 6 फ़ीचर। वे 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, reduceयाforEach
  3. फ़ंक्शन के लिए फ़ंक्शन घोषणाओं का उपयोग करें जिन्हें आप नाम से बुलाएंगे (क्योंकि वे फहराए गए हैं)।
  4. कॉलबैक के लिए एरो फ़ंक्शंस का उपयोग करें (क्योंकि वे बहुत ख़राब होते हैं)।

2
2. 2. उनके पास तर्क नहीं हैं, मुझे खेद है कि यह सच नहीं है, एक का उपयोग किए बिना तर्क हो सकता है ... ऑपरेटर, शायद आप यह कहना चाहते हैं कि आपके पास तर्क के रूप में सरणी नहीं है
कार्माइन टैम्बस्किया

@CarmineTambascia विशेष कार्य के बारे में पढ़ें argumentsजो कि तीर के कार्यों में उपलब्ध नहीं है: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
vichle

0

के साथ तीर फ़ंक्शन का उपयोग करने के लिए 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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.