วัตถุประสงค์ของฟังก์ชั่นการทำงานด้วยตนเองใน javascript คืออะไร?


427

ในจาวาสคริปต์คุณต้องการใช้สิ่งนี้เมื่อใด:

(function(){
    //Bunch of code...
})();

มากกว่านี้:

//Bunch of code...

3
ดูคำอธิบาย ( ด้านเทคนิค ) และที่นี่ด้วย สำหรับไวยากรณ์ให้ดูว่าทำไมวงเล็บเป็นสิ่งที่จำเป็นและที่พวกเขาควรจะไป
Bergi


ทำไมมันถึงมีวงเล็บสองอันสุดท้ายก่อนเซมิโคลอน?
johnny

3
@johnny ส่วนก่อนวงเล็บสองอันสุดท้ายประกาศฟังก์ชัน (ไม่ระบุชื่อ) วงเล็บสองอันนั้นเรียกใช้ฟังก์ชัน
.

7
"การเรียกใช้ฟังก์ชันการแสดงออกทันที" หรือ IIFE เป็นชื่อที่ดีกว่าสำหรับสิ่งนี้
Flimm

คำตอบ:


404

มันคือทั้งหมดที่เกี่ยวกับการกำหนดขอบเขตตัวแปร ตัวแปรที่ประกาศในฟังก์ชั่นการดำเนินการด้วยตนเองจะใช้รหัสในฟังก์ชันการดำเนินการด้วยตนเองเท่านั้นตามค่าเริ่มต้น อนุญาตให้เขียนโค้ดได้โดยไม่ต้องกังวลว่าจะตั้งชื่อตัวแปรอย่างไรในบล็อกอื่น ๆ ของรหัส JavaScript

ตัวอย่างเช่นที่กล่าวถึงในความคิดเห็นโดยอเล็กซานเด :

(function() {
  var foo = 3;
  console.log(foo);
})();

console.log(foo);

นี้จะเข้าสู่ระบบก่อน3แล้วโยนข้อผิดพลาดต่อไปconsole.logเพราะfooไม่ได้กำหนดไว้


7
และเพื่อประโยชน์ของผู้คนมากมายที่นั่นรวมถึงวิศวกร Netflix ทั้งหมด: มันเป็นเพียงแค่ฟังก์ชั่น มันไม่ได้อยู่ในตัวของมันเองและเป็นตัวแทนของการปิด บางครั้งผู้เรียกค่าอัตโนมัติจะใช้ร่วมกับสถานการณ์ที่เกี่ยวข้องกับการปิดเพื่อทำสิ่งที่เป็นระเบียบ แต่ถ้าคุณไม่เห็นบางสิ่งบางอย่างเกี่ยวกับการอ้างอิงซึ่งจะเป็นการรวบรวมขยะและไปในภาษาที่ไม่ได้ปิด ประหลาดทำกับปิด
Erik Reppen

2
ดังนั้นนี่หมายความว่าส่วนใหญ่จะใช้กับการปิด?
Pir Abdul

@AlexanderBird, ไม่ถูกต้อง ... ถ้าคุณทำได้โดยไม่ต้องvarเช่นนี้...function(){ foo=3;}? มันจะตั้งค่าตัวแปรส่วนกลางใช่ไหม
T.Todua

2
@AlexanderBird แต่ที่เกิดขึ้นแล้วในตัวแปรท้องถิ่นภายในฟังก์ชั่น: function(){ var foo = 3; alert(foo); }; alert(foo);ดังนั้นฉันยังไม่เข้าใจ
João Pimentel Ferreira

อ่าฉันเข้าใจแล้วคุณจะได้คุณสมบัติทั้ง 3 อย่างพร้อมกัน: 1) คุณใช้งานฟังก์ชั่นโดยการประกาศเท่านั้น 2) เนื่องจากฟังก์ชันใด ๆ ขอบเขตตัวแปรจะเป็นแบบโลคอลเท่านั้น และ 3) ฟังก์ชันอาจไม่ระบุชื่อไม่ก่อให้เกิดมลพิษในขอบเขตหลัก
João Pimentel Ferreira

94

แบบง่ายๆ ดูธรรมดามากมันเกือบจะปลอบโยน:

var userName = "Sean";

console.log(name());

function name() {
  return userName;
}

อย่างไรก็ตามจะเกิดอะไรขึ้นถ้าฉันรวมไลบรารีจาวาสคริปต์ที่มีประโยชน์จริงๆไว้ในหน้าของฉันซึ่งแปลอักขระขั้นสูงเป็นตัวแทนระดับพื้นฐาน

รออะไร?

ฉันหมายถึงถ้ามีคนพิมพ์อักขระด้วยสำเนียงบางอย่าง แต่ฉันต้องการตัวอักษร AZ ในภาษาของฉัน ดี ... ตัวอักษร 'ñ' สเปนและฝรั่งเศส 'é' สามารถแปลเป็นตัวละครฐานของ 'n' และ 'e'

ดังนั้นใครบางคนที่เป็นคนดีได้เขียนตัวแปลงอักขระที่ครอบคลุมออกไปซึ่งฉันสามารถรวมไว้ในเว็บไซต์ของฉัน ... ฉันรวมมันไว้ด้วย

ปัญหาหนึ่ง: มันมีฟังก์ชั่นในนั้นเรียกว่า 'ชื่อ' เหมือนกับฟังก์ชั่นของฉัน

นี่คือสิ่งที่เรียกว่าการปะทะกัน เรามีฟังก์ชั่นสองประกาศในขอบเขตเดียวกันที่มีชื่อเดียวกัน เราต้องการหลีกเลี่ยงสิ่งนี้

ดังนั้นเราจำเป็นต้องกำหนดขอบเขตโค้ดของเราอย่างใด

วิธีเดียวในการกำหนดขอบเขตโค้ดใน javascript คือการล้อมในฟังก์ชัน:

function main() {
  // We are now in our own sound-proofed room and the 
  // character-converter libarary's name() function can exist at the 
  // same time as ours. 

  var userName = "Sean";

  console.log(name());

  function name() {
    return userName;
  }
}

นั่นอาจช่วยแก้ปัญหาของเราได้ ตอนนี้ทุกอย่างถูกล้อมรอบและสามารถเข้าถึงได้จากภายในวงเล็บปีกกาเปิดและปิดของเราเท่านั้น

เรามีฟังก์ชั่นในฟังก์ชั่น ... ซึ่งเป็นเรื่องแปลกที่จะมอง แต่ตามกฎหมายโดยสิ้นเชิง

ปัญหาเดียวเท่านั้น รหัสของเราไม่ทำงาน ตัวแปรชื่อผู้ใช้ของเราไม่เคยสะท้อนลงในคอนโซล!

เราสามารถแก้ปัญหานี้ได้โดยเพิ่มการเรียกไปยังฟังก์ชั่นของเราหลังจากการบล็อกรหัสที่มีอยู่ของเรา ...

function main() {
  // We are now in our own sound-proofed room and the 
  // character-converter libarary's name() function can exist at the 
  // same time as ours. 

  var userName = "Sean";

  console.log(name());

  function name() {
    return userName;
  }
}

main();

หรือก่อน!

main();

function main() {
  // We are now in our own sound-proofed room and the 
  // character-converter libarary's name() function can exist at the 
  // same time as ours. 

  var userName = "Sean";

  console.log(name());

  function name() {
    return userName;
  }
}

ข้อกังวลลำดับที่สอง: โอกาสที่ชื่อ 'main' ยังไม่ได้ถูกใช้มีอะไรบ้าง ... ช่างผอมแห้งเหลือเกิน

เราต้องการการกำหนดขอบเขตเพิ่มเติม และวิธีการใช้งานฟังก์ชั่น main () ของเราโดยอัตโนมัติ

ตอนนี้เรามาถึงฟังก์ชั่น auto-execution (หรือ self-executeing, self-running, what)

((){})();

ไวยากรณ์ผิดพลาด อย่างไรก็ตามมันใช้งานได้

เมื่อคุณตัดนิยามฟังก์ชันในวงเล็บและรวมถึงรายการพารามิเตอร์ (ชุดหรือวงเล็บอีก!) จะทำหน้าที่เป็นฟังก์ชั่นการโทร

ดังนั้นให้ดูที่รหัสของเราอีกครั้งโดยใช้ไวยากรณ์ดำเนินการด้วยตนเอง:

(function main() {
  var userName = "Sean";

    console.log(name());

    function name() {
      return userName;
    }
  }
)();

ดังนั้นในแบบฝึกหัดส่วนใหญ่ที่คุณอ่านตอนนี้คุณจะถูกกระหน่ำยิงด้วยคำว่า

หลังจากการพัฒนาอย่างมืออาชีพมาหลายปีฉันขอแนะนำให้คุณตั้งชื่อทุกฟังก์ชั่นที่คุณเขียนเพื่อการดีบั๊ก

เมื่อมีบางอย่างผิดปกติ (และจะเกิดขึ้น) คุณจะตรวจสอบ backtrace ในเบราว์เซอร์ของคุณ มันเป็นเสมอง่ายขึ้นเพื่อทำการประเด็นรหัสของคุณเมื่อรายการในกองติดตามที่มีชื่อ!

ยืดยาวและหวังว่ามันจะช่วยได้!


2
ขอบคุณ :) ฉันค้นหาอินเทอร์เน็ตทุกวิธีที่พยายามเข้าใจถึงข้อดีของ IIFE ที่เกี่ยวข้องกับฟังก์ชั่นปกติในแง่ของความเป็นส่วนตัวที่ผันแปรได้และคำตอบของคุณดีที่สุด ทุกคนบอกว่าข้อดีอย่างหนึ่งที่ดีที่สุดคือตัวแปรและฟังก์ชั่นใน IIFE นั้นเป็น 'ส่วนตัว' ในที่สุดเมื่อฟังก์ชั่นปกติให้คุณเหมือนกันทุกประการ ในที่สุดฉันคิดว่าฉันได้รับมันผ่านกระบวนการอธิบายของคุณ IIFE เป็นเพียงฟังก์ชั่น แต่ตอนนี้ฉันเข้าใจแล้วว่าทำไมต้องใช้มันขอบคุณอีกครั้ง!
viery365

ขอบคุณที่สละเวลาอธิบายสิ่งนี้ให้ดี
MSC

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

เพื่อนของฉันนี่คือคำตอบที่ฉันกำลังมองหา:)
João Pimentel Ferreira

นี่คือคำตอบที่ฉันกำลังค้นหาไม่ใช่คำตอบที่ได้รับการยอมรับ ฉันพูดถูกว่าไม่เกี่ยวกับการชนกันของชื่อตัวแปรแต่เกี่ยวกับการชนกันของชื่อฟังก์ชัน ? ตัวแปรในฟังก์ชั่นที่ไม่ใช่ iife ปกตินั้นมีการกำหนดขอบเขตแบบโลคัลและไม่ขัดแย้งกับตัวแปรโกลบอลใช่ไหม?
Kumar Manish

32

Self-invocation (หรือที่เรียกว่า auto-invocation) คือเมื่อฟังก์ชั่นดำเนินการทันทีตามคำจำกัดความของมัน นี่เป็นรูปแบบหลักและทำหน้าที่เป็นรากฐานสำหรับรูปแบบอื่น ๆ ของการพัฒนา JavaScript

ฉันเป็นแฟนตัวยงของ :) เพราะ:

  • มันเก็บรหัสให้น้อยที่สุด
  • มันบังคับแยกพฤติกรรมจากการนำเสนอ
  • มันให้การปิดซึ่งป้องกันความขัดแย้งของการตั้งชื่อ

อย่างยิ่งใหญ่ - (ทำไมคุณควรพูดให้ดี)

  • มันเกี่ยวกับการกำหนดและดำเนินการฟังก์ชั่นทั้งหมดในครั้งเดียว
  • คุณสามารถให้ฟังก์ชันการดำเนินการด้วยตนเองคืนค่าและส่งผ่านฟังก์ชันเป็นพารามิเตอร์ไปยังฟังก์ชันอื่น
  • มันเป็นสิ่งที่ดีสำหรับการห่อหุ้ม
  • นอกจากนี้ยังดีสำหรับการกำหนดขอบเขตของบล็อก
  • ใช่คุณสามารถใส่ไฟล์. js ทั้งหมดของคุณในฟังก์ชั่นการดำเนินการด้วยตนเองและสามารถป้องกันมลภาวะเนมสเปซส่วนกลาง ;)

เพิ่มเติมที่นี่


43
ข้อที่ 1. อย่างไร จุดที่ 2 นั้นมาจากแนวปฏิบัติที่ดีที่สุดที่แตกต่างอย่างสิ้นเชิง จุดที่ 3 ฟังก์ชั่นอะไรไม่ได้? 4,5,6,7 ความสัมพันธ์กัน? 8. เอาละ 1/8 ไม่เลวเลยนะฉันว่า
Erik Reppen

2
เจ็ดปีที่ผ่านมา แต่สำหรับจุดที่ 1 มันไม่ได้ลดรหัสเลยจริงๆแล้วมันเพิ่มรหัสขั้นต่ำสองบรรทัดในการสร้างฟังก์ชั่น
YungGun

1
จุดเดียวที่นี่คือ "มันให้ปิดซึ่งป้องกันการตั้งชื่อความขัดแย้ง" จุดอื่น ๆ ทุก rewording นี้หรือเท็จ บางทีคุณอาจทำให้คำตอบของคุณง่ายขึ้น?
pcarvalho

19

namespacing ขอบเขตของ JavaScript เป็นระดับฟังก์ชั่น


7
downvotes ยังคงมาในเพราะผมใช้namespacing instad ของการกำหนดขอบเขต ; นี่เป็นเรื่องของคำจำกัดความ - ดูตัวอย่างเช่นWikipedia : namespace ในวิทยาการคอมพิวเตอร์ (บางครั้งเรียกว่าขอบเขตชื่อ) เป็นคอนเทนเนอร์นามธรรมหรือสภาพแวดล้อมที่สร้างขึ้นเพื่อเก็บกลุ่มตรรกะของตัวระบุหรือสัญลักษณ์เฉพาะ (เช่นชื่อ) และตัวระบุเนมสเปซอาจจัดเตรียมบริบท (ขอบเขตในวิทยาการคอมพิวเตอร์) ให้กับชื่อและบางครั้งข้อกำหนดอาจใช้แทนกันได้
Christoph

5
จาวาสคริปต์ของขอบเขตการทำงานระดับให้พื้นที่ที่ชื่อตัวแปรอาศัยอยู่ในที่namespace ; ว่ามันเป็นนิรนามหนึ่งที่ไม่เกี่ยวข้องกับตัวระบุ namespace นั้นไม่เกี่ยวข้อง ...
Christoph

12

ฉันไม่อยากเชื่อเลยว่าจะไม่มีคำตอบใดที่บอกเป็นนัย ๆ

สิ่ง(function(){})()ก่อสร้างไม่ได้ป้องกันจากการบอกเป็นนัย ๆ ซึ่งเป็นสิ่งที่ฉันกังวลมากขึ้นโปรดดูที่http://yuiblog.com/blog/2006/06/01/global-domination/

โดยทั่วไปบล็อกฟังก์ชั่นทำให้แน่ใจว่า "vars ทั่วโลก" ทั้งหมดที่คุณกำหนดไว้ถูก จำกัด อยู่ในโปรแกรมของคุณมันไม่ได้ป้องกันคุณจากการกำหนดรูปทรงกลมโดยปริยาย JSHintหรือสิ่งที่คล้ายกันสามารถให้คำแนะนำเกี่ยวกับวิธีการป้องกันพฤติกรรมนี้

var App = {}ไวยากรณ์ที่กระชับยิ่งขึ้นมีระดับการป้องกันที่คล้ายคลึงกันและอาจถูกรวมไว้ในบล็อกฟังก์ชันเมื่ออยู่ในหน้า 'สาธารณะ' (ดูEmber.jsหรือSproutCoreสำหรับตัวอย่างจริงของไลบรารีที่ใช้โครงสร้างนี้)

ตราบใดที่privateคุณสมบัติยังคงมีอยู่พวกเขาจะถูกประเมินค่าเกินจริงหากคุณไม่ได้สร้างกรอบงานสาธารณะหรือห้องสมุด แต่ถ้าคุณต้องการใช้งานเหล่านั้นDouglas Crockfordมีแนวคิดที่ดี


8
โหมดที่เข้มงวดปกป้องจาก globals โดยนัย ที่ร่วมกับผู้บุกรุกอัตโนมัติจะมีคุณครอบคลุม ฉันไม่เคยเข้าใจ hooplah มากกว่าคุณสมบัติส่วนตัว ประกาศ vars ภายในตัวสร้าง func เสร็จสิ้น หากความคิดที่จะลืมใช้คำสำคัญ 'ใหม่' จะทำให้คุณตื่นขึ้นมาในเวลากลางคืนให้เขียนฟังก์ชันจากโรงงาน ทำอีกครั้ง
Erik Reppen

8

ฉันได้อ่านคำตอบทั้งหมดสิ่งที่สำคัญมากหายไปฉันจะจูบ มี 2 ​​เหตุผลหลักคือเหตุใดฉันจึงต้องการฟังก์ชั่นที่ไม่เปิดเผยตัวตนดำเนินการหรือดีกว่าพูดว่า " Expression Function ที่เรียกใช้ทันที (IIFE) ":

  1. การจัดการ namespace ที่ดีขึ้น (หลีกเลี่ยงมลภาวะ Namespace -> JS Module)
  2. การปิด (การจำลองสมาชิกคลาสส่วนตัวที่รู้จักกันจาก OOP)

คนแรกได้รับการอธิบายเป็นอย่างดี สำหรับคนที่สองโปรดศึกษาตัวอย่างต่อไปนี้:

var MyClosureObject = (function (){
  var MyName = 'Michael Jackson RIP';
  return {
    getMyName: function () { return MyName;},
    setMyName: function (name) { MyName = name}
  }
}());

ข้อควรสนใจที่ 1:เราไม่ได้กำหนดฟังก์ชั่นให้กับMyClosureObjectยิ่งผลลัพธ์ของการเรียกใช้ฟังก์ชันนั้นมากขึ้น ระวัง()ในบรรทัดสุดท้าย

ข้อควรสนใจที่ 2:สิ่งที่คุณต้องรู้เพิ่มเติมเกี่ยวกับฟังก์ชั่นใน Javascript คือฟังก์ชั่นด้านในสามารถเข้าถึงพารามิเตอร์และตัวแปรของฟังก์ชั่นได้

ให้เราลองทำการทดลองบางอย่าง:

ฉันสามารถMyNameใช้getMyNameและใช้งานได้:

 console.log(MyClosureObject.getMyName()); 
 // Michael Jackson RIP

วิธีการที่แยบยลต่อไปนี้จะไม่ทำงาน:

console.log(MyClosureObject.MyName); 
// undefined

แต่ฉันสามารถตั้งชื่ออื่นและรับผลลัพธ์ที่ต้องการ:

MyClosureObject.setMyName('George Michael RIP');
console.log(MyClosureObject.getMyName()); 
// George Michael RIP

แก้ไข:ในตัวอย่างข้างต้นMyClosureObjectได้รับการออกแบบให้ใช้งานโดยไม่มีส่วนnewนำหน้าดังนั้นจึงไม่ควรใช้ตัวพิมพ์ใหญ่


7

มีพารามิเตอร์และ "Bunch of code" ส่งคืนฟังก์ชันหรือไม่

var a = function(x) { return function() { document.write(x); } }(something);

การปิด คุณค่าของการได้รับใช้ตามหน้าที่ที่ได้รับมอบหมายsomething อาจมีค่าแตกต่างกัน (สำหรับวง) และทุกครั้งที่มีฟังก์ชั่นใหม่asomething


+1; ฉันชอบที่ชัดเจนvar x = something;ในการทำงานนอกมากกว่าxเป็นพารามิเตอร์แม้ว่า: IMO มันอ่านได้มากขึ้นด้วยวิธีนี้ ...
คริสโต

@Christoph: หากค่าของบางสิ่งบางอย่างเปลี่ยนไปหลังจากที่ฟังก์ชั่นถูกสร้างขึ้นมันจะใช้ค่าใหม่และไม่ใช่ค่าในช่วงเวลาของการสร้าง
stesch

@stesch: คุณได้รับมาจากไหน เท่าที่ฉันรู้นั่นไม่ใช่กรณี; วิธีเดียวที่จะได้รับการอ้างอิงจริงใน JS คือการใช้อาร์กิวเมนต์-object แต่ถึงกระนั้นมันก็ไม่สามารถใช้ได้กับเบราว์เซอร์ทั้งหมด
Christoph

@Christoph: "JavaScript: ส่วนดี" ดักลาส Crockford (O'Reilly)
stesch

@stesch: มันไม่ทำงานตามที่คุณอธิบาย: ค่าใหม่จะใช้ถ้าคุณวางตัวแปรxและขึ้นอยู่กับขอบเขตคำศัพท์โดยตรงdocument.write(something)...
Christoph

6

การแยกขอบเขตอาจจะ เพื่อให้ตัวแปรภายในการประกาศฟังก์ชันไม่สร้างมลภาวะเนมสเปซด้านนอก

แน่นอนว่าในการนำ JS ไปใช้งานครึ่งหนึ่งพวกเขาจะทำเช่นนั้นต่อไป


4
การใช้งานอะไรที่จะเป็นอย่างไร
Matthew Crumley

1
การใช้งานใด ๆ ที่ไม่ได้เขียนในโหมดเข้มงวดและมีและประกาศ var โดยนัยที่ทำให้มันเป็นโลก
Erik Reppen

5

นี่เป็นตัวอย่างที่ชัดเจนว่าฟังก์ชั่นที่ไม่ระบุชื่อที่เรียกร้องตัวเองนั้นมีประโยชน์อย่างไร

for( var i = 0; i < 10; i++ ) {
  setTimeout(function(){
    console.log(i)
  })
}

เอาท์พุท: 10, 10, 10, 10, 10...

for( var i = 0; i < 10; i++ ) {
  (function(num){
    setTimeout(function(){
      console.log(num)
    })
  })(i)
}

เอาท์พุท: 0, 1, 2, 3, 4...


คุณสามารถอธิบายเพิ่มเติมเล็กน้อยเกี่ยวกับสิ่งที่เกิดขึ้นสำหรับรหัสชุดแรก
radio_head

ด้วยการใช้letแทนvarกรณีแรกจะไม่เป็นไร
Vitaly Zdanevich

3

ความแตกต่างอย่างหนึ่งคือตัวแปรที่คุณประกาศในฟังก์ชั่นเป็นแบบโลคอลดังนั้นมันจะหายไปเมื่อคุณออกจากฟังก์ชั่นและไม่ขัดแย้งกับตัวแปรอื่น ๆ ในโค้ดอื่น


1

เนื่องจากฟังก์ชั่นใน Javascript เป็นวัตถุชั้นหนึ่งโดยการกำหนดให้เป็นเช่นนั้นจึงกำหนด "class" ได้อย่างมีประสิทธิภาพเช่น C ++ หรือ C #

ฟังก์ชั่นนั้นสามารถกำหนดตัวแปรท้องถิ่นและมีฟังก์ชั่นภายใน ฟังก์ชั่นภายใน (วิธีการอินสแตนซ์ที่มีประสิทธิภาพ) จะสามารถเข้าถึงตัวแปรท้องถิ่น (ตัวแปรอินสแตนซ์ที่มีประสิทธิภาพ) แต่จะถูกแยกออกจากส่วนที่เหลือของสคริปต์


1

ฟังก์ชันที่เรียกใช้ด้วยตนเองใน javascript:

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


1

ฟังก์ชันการดำเนินการด้วยตนเองถูกใช้เพื่อจัดการขอบเขตของตัวแปร

ขอบเขตของตัวแปรคือขอบเขตของโปรแกรมที่มีการกำหนดไว้

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

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

var globalvar = "globalvar"; // this var can be accessed anywhere within the script

function scope() {
    alert(globalvar);
    localvar = "localvar" //can only be accessed within the function scope
}

scope(); 

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


1
(function(){
    var foo = {
        name: 'bob'
    };
    console.log(foo.name); // bob
})();
console.log(foo.name); // Reference error

ที่จริงแล้วฟังก์ชั่นด้านบนจะถูกใช้เป็นนิพจน์ฟังก์ชันโดยไม่มีชื่อ

วัตถุประสงค์หลักของการห่อฟังก์ชั่นที่มีวงเล็บปิดและเปิดคือการหลีกเลี่ยงการก่อให้เกิดมลพิษในอวกาศโลก

ตัวแปรและฟังก์ชั่นภายในการแสดงออกของฟังก์ชั่นกลายเป็นส่วนตัว (เช่น) พวกเขาจะไม่สามารถใช้ได้นอกฟังก์ชั่น


1

คำตอบสั้น ๆ คือ: เพื่อป้องกันมลพิษของขอบเขตโลก (หรือสูงกว่า)

IIFE (รื้อฟื้นทันทีนิพจน์ฟังก์ชั่น) เป็นวิธีที่ดีที่สุดสำหรับการเขียนสคริปต์เป็นปลั๊กอิน Add-on สคริปต์ผู้ใช้หรือสคริปต์สิ่งที่คาดว่าจะทำงานร่วมกับสคริปของคนอื่น สิ่งนี้ทำให้มั่นใจได้ว่าตัวแปรใด ๆ ที่คุณกำหนดจะไม่ส่งผลต่อสคริปต์อื่น ๆ

นี่เป็นวิธีอื่นในการเขียนการแสดงออกของ IIFE ฉันชอบวิธีต่อไปนี้เป็นการส่วนตัว:

void function() {
  console.log('boo!');
  // expected output: "boo!"
}();

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void

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


ดีฉันไม่เคยเห็นการใช้งานvoidมาก่อน ฉันชอบมัน.
.

1

ก่อนอื่นคุณต้องไปที่MDN IIFEตอนนี้บางประเด็นเกี่ยวกับเรื่องนี้

  • นี่คือการแสดงออกของฟังก์ชั่นที่ถูกเรียกทันทีแสดงออกฟังก์ชั่นรื้อฟื้นทันทีดังนั้นเมื่อไฟล์ javascript ของคุณถูกเรียกใช้จาก HTML ฟังก์ชั่นนี้เรียกว่าทันที
  • สิ่งนี้จะช่วยป้องกันการเข้าถึงตัวแปรภายในสำนวน IIFE รวมถึงสร้างมลภาวะระดับโลก

0

ดูเหมือนว่าคำถามนี้จะได้รับคำตอบให้ทุกคนพร้อม แต่ฉันจะโพสต์การป้อนข้อมูลของฉันต่อไป

ฉันรู้เมื่อฉันต้องการใช้ฟังก์ชั่นการทำงานด้วยตนเอง

var myObject = {
    childObject: new function(){
        // bunch of code
    },
    objVar1: <value>,
    objVar2: <value>
}

ฟังก์ชั่นอนุญาตให้ฉันใช้โค้ดพิเศษบางอย่างเพื่อกำหนดแอททริบิวต์ childObjects และคุณสมบัติสำหรับโค้ดทำความสะอาดเช่นการตั้งค่าตัวแปรที่ใช้กันทั่วไปหรือการดำเนินการสมการทางคณิตศาสตร์ Oh! หรือตรวจสอบข้อผิดพลาด ซึ่งตรงข้ามกับการ จำกัด เฉพาะไวยากรณ์การสร้างอินสแตนซ์ของวัตถุที่ซ้อนกันของ ...

object: {
    childObject: {
        childObject: {<value>, <value>, <value>}
    }, 
    objVar1: <value>,
    objVar2: <value>
}

การเขียนโค้ดโดยทั่วไปมีหลายวิธีที่คลุมเครือในการทำสิ่งเดียวกันมากมายทำให้คุณสงสัยว่า "ทำไมต้องรำคาญ" แต่สถานการณ์ใหม่ก็ยังคงโผล่ขึ้นมาซึ่งคุณไม่สามารถพึ่งพาหลักการพื้นฐาน / แกนคนเดียวได้อีกต่อไป


0

ให้คำถามง่ายๆของคุณ: "ในจาวาสคริปต์เมื่อใดที่คุณต้องการใช้สิ่งนี้: ... "

ฉันชอบ @ken_browning และ @ sean_holding คำตอบ แต่นี่เป็นอีกกรณีการใช้งานที่ฉันไม่เห็นพูดถึง:

let red_tree = new Node(10);

(async function () {
    for (let i = 0; i < 1000; i++) {
        await red_tree.insert(i);
    }
})();

console.log('----->red_tree.printInOrder():', red_tree.printInOrder());

โดยที่ Node.insert เป็นการกระทำแบบอะซิงโครนัส

ฉันไม่สามารถรอได้โดยไม่ต้องใช้คำสำคัญ async ที่การประกาศฟังก์ชั่นของฉันและฉันไม่ต้องการฟังก์ชั่นที่มีชื่อสำหรับการใช้งานในภายหลัง แต่ต้องรอที่จะแทรกการโทรหรือฉันต้องการคุณสมบัติอื่น ๆ .


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.