ในจาวาสคริปต์คุณต้องการใช้สิ่งนี้เมื่อใด:
(function(){
//Bunch of code...
})();
มากกว่านี้:
//Bunch of code...
ในจาวาสคริปต์คุณต้องการใช้สิ่งนี้เมื่อใด:
(function(){
//Bunch of code...
})();
มากกว่านี้:
//Bunch of code...
คำตอบ:
มันคือทั้งหมดที่เกี่ยวกับการกำหนดขอบเขตตัวแปร ตัวแปรที่ประกาศในฟังก์ชั่นการดำเนินการด้วยตนเองจะใช้รหัสในฟังก์ชันการดำเนินการด้วยตนเองเท่านั้นตามค่าเริ่มต้น อนุญาตให้เขียนโค้ดได้โดยไม่ต้องกังวลว่าจะตั้งชื่อตัวแปรอย่างไรในบล็อกอื่น ๆ ของรหัส JavaScript
ตัวอย่างเช่นที่กล่าวถึงในความคิดเห็นโดยอเล็กซานเด :
(function() {
var foo = 3;
console.log(foo);
})();
console.log(foo);
นี้จะเข้าสู่ระบบก่อน3
แล้วโยนข้อผิดพลาดต่อไปconsole.log
เพราะfoo
ไม่ได้กำหนดไว้
var
เช่นนี้...function(){ foo=3;}
? มันจะตั้งค่าตัวแปรส่วนกลางใช่ไหม
function(){ var foo = 3; alert(foo); }; alert(foo);
ดังนั้นฉันยังไม่เข้าใจ
แบบง่ายๆ ดูธรรมดามากมันเกือบจะปลอบโยน:
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 ในเบราว์เซอร์ของคุณ มันเป็นเสมอง่ายขึ้นเพื่อทำการประเด็นรหัสของคุณเมื่อรายการในกองติดตามที่มีชื่อ!
ยืดยาวและหวังว่ามันจะช่วยได้!
:)
Self-invocation (หรือที่เรียกว่า auto-invocation) คือเมื่อฟังก์ชั่นดำเนินการทันทีตามคำจำกัดความของมัน นี่เป็นรูปแบบหลักและทำหน้าที่เป็นรากฐานสำหรับรูปแบบอื่น ๆ ของการพัฒนา JavaScript
ฉันเป็นแฟนตัวยงของ :) เพราะ:
อย่างยิ่งใหญ่ - (ทำไมคุณควรพูดให้ดี)
namespacing ขอบเขตของ JavaScript เป็นระดับฟังก์ชั่น
ฉันไม่อยากเชื่อเลยว่าจะไม่มีคำตอบใดที่บอกเป็นนัย ๆ
สิ่ง(function(){})()
ก่อสร้างไม่ได้ป้องกันจากการบอกเป็นนัย ๆ ซึ่งเป็นสิ่งที่ฉันกังวลมากขึ้นโปรดดูที่http://yuiblog.com/blog/2006/06/01/global-domination/
โดยทั่วไปบล็อกฟังก์ชั่นทำให้แน่ใจว่า "vars ทั่วโลก" ทั้งหมดที่คุณกำหนดไว้ถูก จำกัด อยู่ในโปรแกรมของคุณมันไม่ได้ป้องกันคุณจากการกำหนดรูปทรงกลมโดยปริยาย JSHintหรือสิ่งที่คล้ายกันสามารถให้คำแนะนำเกี่ยวกับวิธีการป้องกันพฤติกรรมนี้
var App = {}
ไวยากรณ์ที่กระชับยิ่งขึ้นมีระดับการป้องกันที่คล้ายคลึงกันและอาจถูกรวมไว้ในบล็อกฟังก์ชันเมื่ออยู่ในหน้า 'สาธารณะ' (ดูEmber.jsหรือSproutCoreสำหรับตัวอย่างจริงของไลบรารีที่ใช้โครงสร้างนี้)
ตราบใดที่private
คุณสมบัติยังคงมีอยู่พวกเขาจะถูกประเมินค่าเกินจริงหากคุณไม่ได้สร้างกรอบงานสาธารณะหรือห้องสมุด แต่ถ้าคุณต้องการใช้งานเหล่านั้นDouglas Crockfordมีแนวคิดที่ดี
ฉันได้อ่านคำตอบทั้งหมดสิ่งที่สำคัญมากหายไปฉันจะจูบ มี 2 เหตุผลหลักคือเหตุใดฉันจึงต้องการฟังก์ชั่นที่ไม่เปิดเผยตัวตนดำเนินการหรือดีกว่าพูดว่า " Expression Function ที่เรียกใช้ทันที (IIFE) ":
คนแรกได้รับการอธิบายเป็นอย่างดี สำหรับคนที่สองโปรดศึกษาตัวอย่างต่อไปนี้:
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
นำหน้าดังนั้นจึงไม่ควรใช้ตัวพิมพ์ใหญ่
มีพารามิเตอร์และ "Bunch of code" ส่งคืนฟังก์ชันหรือไม่
var a = function(x) { return function() { document.write(x); } }(something);
การปิด คุณค่าของการได้รับใช้ตามหน้าที่ที่ได้รับมอบหมายsomething
อาจมีค่าแตกต่างกัน (สำหรับวง) และทุกครั้งที่มีฟังก์ชั่นใหม่a
something
var x = something;
ในการทำงานนอกมากกว่าx
เป็นพารามิเตอร์แม้ว่า: IMO มันอ่านได้มากขึ้นด้วยวิธีนี้ ...
x
และขึ้นอยู่กับขอบเขตคำศัพท์โดยตรงdocument.write(something)
...
การแยกขอบเขตอาจจะ เพื่อให้ตัวแปรภายในการประกาศฟังก์ชันไม่สร้างมลภาวะเนมสเปซด้านนอก
แน่นอนว่าในการนำ JS ไปใช้งานครึ่งหนึ่งพวกเขาจะทำเช่นนั้นต่อไป
นี่เป็นตัวอย่างที่ชัดเจนว่าฟังก์ชั่นที่ไม่ระบุชื่อที่เรียกร้องตัวเองนั้นมีประโยชน์อย่างไร
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...
let
แทนvar
กรณีแรกจะไม่เป็นไร
ความแตกต่างอย่างหนึ่งคือตัวแปรที่คุณประกาศในฟังก์ชั่นเป็นแบบโลคอลดังนั้นมันจะหายไปเมื่อคุณออกจากฟังก์ชั่นและไม่ขัดแย้งกับตัวแปรอื่น ๆ ในโค้ดอื่น
เนื่องจากฟังก์ชั่นใน Javascript เป็นวัตถุชั้นหนึ่งโดยการกำหนดให้เป็นเช่นนั้นจึงกำหนด "class" ได้อย่างมีประสิทธิภาพเช่น C ++ หรือ C #
ฟังก์ชั่นนั้นสามารถกำหนดตัวแปรท้องถิ่นและมีฟังก์ชั่นภายใน ฟังก์ชั่นภายใน (วิธีการอินสแตนซ์ที่มีประสิทธิภาพ) จะสามารถเข้าถึงตัวแปรท้องถิ่น (ตัวแปรอินสแตนซ์ที่มีประสิทธิภาพ) แต่จะถูกแยกออกจากส่วนที่เหลือของสคริปต์
ฟังก์ชันที่เรียกใช้ด้วยตนเองใน javascript:
นิพจน์ที่เรียกตนเองนั้นถูกเรียกใช้ (เริ่มต้น) โดยอัตโนมัติโดยไม่ถูกเรียก นิพจน์ที่เรียกตนเองนั้นถูกเรียกใช้หลังจากสร้างขึ้นแล้ว โดยทั่วไปจะใช้เพื่อหลีกเลี่ยงการตั้งชื่อความขัดแย้งเช่นเดียวกับการบรรลุความห่อหุ้ม ตัวแปรหรือวัตถุที่ประกาศไม่สามารถเข้าถึงได้นอกฟังก์ชั่นนี้ เพื่อหลีกเลี่ยงปัญหาการย่อเล็กสุด (filename.min) ให้ใช้ฟังก์ชั่นที่ดำเนินการเอง
ฟังก์ชันการดำเนินการด้วยตนเองถูกใช้เพื่อจัดการขอบเขตของตัวแปร
ขอบเขตของตัวแปรคือขอบเขตของโปรแกรมที่มีการกำหนดไว้
ตัวแปรโกลบอลมีขอบเขตโกลบอล มันถูกกำหนดทุกที่ในรหัส 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();
ดังนั้นฟังก์ชั่นการดำเนินการด้วยตนเองจึงอนุญาตให้เขียนโค้ดได้โดยไม่ต้องกังวลว่าตัวแปรจะถูกตั้งชื่อในบล็อกอื่น ๆ ของรหัสจาวาสคริปต์หรือไม่
(function(){
var foo = {
name: 'bob'
};
console.log(foo.name); // bob
})();
console.log(foo.name); // Reference error
ที่จริงแล้วฟังก์ชั่นด้านบนจะถูกใช้เป็นนิพจน์ฟังก์ชันโดยไม่มีชื่อ
วัตถุประสงค์หลักของการห่อฟังก์ชั่นที่มีวงเล็บปิดและเปิดคือการหลีกเลี่ยงการก่อให้เกิดมลพิษในอวกาศโลก
ตัวแปรและฟังก์ชั่นภายในการแสดงออกของฟังก์ชั่นกลายเป็นส่วนตัว (เช่น) พวกเขาจะไม่สามารถใช้ได้นอกฟังก์ชั่น
คำตอบสั้น ๆ คือ: เพื่อป้องกันมลพิษของขอบเขตโลก (หรือสูงกว่า)
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
มาก่อน ฉันชอบมัน.
ก่อนอื่นคุณต้องไปที่MDN IIFEตอนนี้บางประเด็นเกี่ยวกับเรื่องนี้
ดูเหมือนว่าคำถามนี้จะได้รับคำตอบให้ทุกคนพร้อม แต่ฉันจะโพสต์การป้อนข้อมูลของฉันต่อไป
ฉันรู้เมื่อฉันต้องการใช้ฟังก์ชั่นการทำงานด้วยตนเอง
var myObject = {
childObject: new function(){
// bunch of code
},
objVar1: <value>,
objVar2: <value>
}
ฟังก์ชั่นอนุญาตให้ฉันใช้โค้ดพิเศษบางอย่างเพื่อกำหนดแอททริบิวต์ childObjects และคุณสมบัติสำหรับโค้ดทำความสะอาดเช่นการตั้งค่าตัวแปรที่ใช้กันทั่วไปหรือการดำเนินการสมการทางคณิตศาสตร์ Oh! หรือตรวจสอบข้อผิดพลาด ซึ่งตรงข้ามกับการ จำกัด เฉพาะไวยากรณ์การสร้างอินสแตนซ์ของวัตถุที่ซ้อนกันของ ...
object: {
childObject: {
childObject: {<value>, <value>, <value>}
},
objVar1: <value>,
objVar2: <value>
}
การเขียนโค้ดโดยทั่วไปมีหลายวิธีที่คลุมเครือในการทำสิ่งเดียวกันมากมายทำให้คุณสงสัยว่า "ทำไมต้องรำคาญ" แต่สถานการณ์ใหม่ก็ยังคงโผล่ขึ้นมาซึ่งคุณไม่สามารถพึ่งพาหลักการพื้นฐาน / แกนคนเดียวได้อีกต่อไป
ให้คำถามง่ายๆของคุณ: "ในจาวาสคริปต์เมื่อใดที่คุณต้องการใช้สิ่งนี้: ... "
ฉันชอบ @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 ที่การประกาศฟังก์ชั่นของฉันและฉันไม่ต้องการฟังก์ชั่นที่มีชื่อสำหรับการใช้งานในภายหลัง แต่ต้องรอที่จะแทรกการโทรหรือฉันต้องการคุณสมบัติอื่น ๆ .
IIRC ช่วยให้คุณสร้างคุณสมบัติและวิธีการส่วนตัว