คอมพิวเตอร์ หน้าต่าง อินเทอร์เน็ต

ประกาศฟังก์ชันในส่วนการประกาศ โครงสร้างโปรแกรม นิพจน์และตัวดำเนินการใน JavaScript

สวัสดีทุกคน! ในบทความนี้ฉันต้องการพูดคุยเกี่ยวกับอะไร เช่นการประกาศฟังก์ชันและการแสดงออกของฟังก์ชันในภาษาโปรแกรม จาวาสคริปต์.

ไซต์มีบทความเกี่ยวกับฟังก์ชันคืออะไร วิธีสร้างและใช้งานแล้ว หากยังไม่ได้อ่านก็สามารถอ่านได้

บทความนั้นก็พูดถึง ประกาศฟังก์ชัน.

ถ้าอยากถาม การแสดงออกของฟังก์ชันจากนั้นคุณต้องเขียนดังนี้:

Var func = function(a, b) ( ส่งคืน a + b; );

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

ตอนนี้เรามาพูดถึงความแตกต่างระหว่างการประกาศฟังก์ชันทั้งสองนี้

การประกาศฟังก์ชั่น

ผลรวม();

ผลรวมฟังก์ชัน() (
alert("ได้ผล!");
}

ดังนั้น หากคุณคิด นี่คือคำตอบที่ถูกต้อง: ใช่, จะทำงาน.

สิ่งนี้เป็นไปได้อย่างไร?

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

การแสดงออกของฟังก์ชัน

ทุกสิ่งที่นี่ตรงกันข้ามทุกประการ

ฟังก์ชั่น Var = ฟังก์ชั่น() (
alert("ได้ผล!");
};

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

ทำไมเราต้องมีการแสดงออกของฟังก์ชัน?

อันที่จริงมีการใช้ในหลาย ๆ ที่ แต่ฉันจะให้ตัวอย่างที่ซ้ำซากอย่างยิ่งที่นี่

ถ้า(อายุ >= 18) (
var func = ฟังก์ชั่น() (
alert("ยินดีต้อนรับ!");
};
) อื่น (
var func = ฟังก์ชั่น() (
alert("ยังเร็วไปสำหรับคุณ!");
};
}

ตอนนี้ขึ้นอยู่กับเงื่อนไขในตัวแปร ฟังก์ชั่นซอร์สโค้ดที่แตกต่างกันจะถูกเขียน ดังนั้น ฟังก์ชันจะทำงานแตกต่างออกไป

กับ ประกาศฟังก์ชันเคล็ดลับดังกล่าวจะไม่ทำงาน

ถ้า(อายุ >= 18) (
ฟังก์ชัน ฟังก์ชัน() (
alert("ยินดีต้อนรับ!");
}
) อื่น (
ฟังก์ชัน ฟังก์ชัน() (
alert("ยังเร็วไปสำหรับคุณ!");
}
}

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

ล่ามจะดูโค้ดจากบนลงล่าง ดังนั้นมันจะเขียนค่าของฟังก์ชันสุดท้ายแล้วเรียกมัน

ดังนั้น ฉันหวังว่าคุณจะเข้าใจความแตกต่างระหว่างการประกาศฟังก์ชัน 2 รายการนี้

ที่ การทำงานคำหลักสามารถใช้เพื่อกำหนดฟังก์ชันภายในนิพจน์

แหล่งที่มาของตัวอย่างเชิงโต้ตอบนี้จัดเก็บไว้ในที่เก็บ GitHub หากคุณต้องการมีส่วนร่วมในโครงการตัวอย่างเชิงโต้ตอบ โปรดโคลน https://github.com/mdn/interactive-examples และส่งคำขอดึงถึงเรา

ไวยากรณ์

var myFunction = ฟังก์ชั่น [ ชื่อ]([พารามิเตอร์1[, พารามิเตอร์2[, ..., พารามิเตอร์N]]]) { งบ };

พารามิเตอร์

name ชื่อฟังก์ชัน สามารถละเว้นได้ ซึ่งในกรณีนี้คือฟังก์ชัน ไม่ระบุชื่อ. ชื่อนี้ใช้เฉพาะในเนื้อหาของฟังก์ชันเท่านั้น paramN ชื่อของอาร์กิวเมนต์ที่จะส่งผ่านไปยังฟังก์ชัน งบ ข้อความที่ประกอบด้วยเนื้อความของฟังก์ชัน

คำอธิบาย

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

การยกนิพจน์ฟังก์ชัน

นิพจน์ฟังก์ชันใน JavaScript จะไม่ถูกยกขึ้น ซึ่งแตกต่างจากการประกาศฟังก์ชัน คุณไม่สามารถใช้นิพจน์ฟังก์ชันก่อนที่จะกำหนดได้:

Console.log(notHoisted) // undefinition //ถึงแม้ว่าชื่อตัวแปรจะถูกยกขึ้น แต่คำจำกัดความกลับไม่ได้เป็นเช่นนั้น ดังนั้นจึงไม่ได้กำหนดไว้ ไม่ยก(); // TypeError: notHoisted ไม่ใช่ฟังก์ชัน var notHoisted = function() ( console.log("bar"); );

นิพจน์ฟังก์ชันที่มีชื่อ

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

Var math = ( "factit": function factorial(n) ( console.log(n) if (n<= 1) { return 1; } return n * factorial(n - 1); } }; math.factit(3) //3;2;1;

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

Var foo = function() () foo.name // "foo" var foo2 = foo foo2.name // "foo" var bar = ฟังก์ชั่น baz() () bar.name // "baz" console.log(foo === foo2); // true console.log(typeof baz); // ไม่ได้กำหนด console.log(bar === baz); // false (ข้อผิดพลาดเนื่องจาก baz == ไม่ได้กำหนด)

ตัวอย่าง

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

Var x = function(y) ( ส่งคืน y * y; ); button.addEventListener("click", function(event) ( console.log("button is clicked!") ))

ข้อมูลจำเพาะ

ข้อมูลจำเพาะ สถานะ ความคิดเห็น
ECMAScript ร่างล่าสุด (ECMA-262)
ร่าง
ECMAScript 2015 (ฉบับที่ 6, ECMA-262)
คำจำกัดความของ "คำจำกัดความฟังก์ชัน" ในข้อกำหนดนั้น
มาตรฐาน
ECMAScript 5.1 (ECMA-262)
มาตรฐาน
ECMAScript ฉบับที่ 3 (ECMA-262)
คำจำกัดความของ "คำจำกัดความฟังก์ชัน" ในข้อกำหนดนั้น
มาตรฐาน คำจำกัดความเริ่มต้น ใช้งานใน JavaScript 1.5

ความเข้ากันได้ของเบราว์เซอร์

ตารางความเข้ากันได้ในหน้านี้สร้างขึ้นจากข้อมูลที่มีโครงสร้าง หากคุณต้องการมีส่วนร่วมในข้อมูล โปรดตรวจสอบ https://github.com/mdn/browser-compat-data และส่งคำขอดึงถึงเรา

อัปเดตข้อมูลความเข้ากันได้บน GitHub

เดสก์ทอปมือถือเซิร์ฟเวอร์
โครเมียมขอบไฟร์ฟอกซ์อินเทอร์เน็ตเอ็กซ์พลอเรอร์โอเปร่าซาฟารีมุมมองเว็บ Androidโครมสำหรับแอนดรอยด์ไฟร์ฟอกซ์สำหรับ Androidโอเปร่าสำหรับ Androidซาฟารีบน iOSซัมซุงอินเตอร์เน็ตโหนด js
การทำงานChrome รองรับเต็มรูปแบบ ใช่ขอบสนับสนุนเต็ม 12Firefox รองรับเต็มรูปแบบ 1การสนับสนุน IE เต็มรูปแบบ ใช่รองรับ Opera เต็มรูปแบบ ใช่รองรับ Safari เต็มรูปแบบ ใช่รองรับ WebView Android เต็มรูปแบบ ใช่รองรับ Chrome Android เต็มรูปแบบใช่Firefox Android รองรับเต็มรูปแบบ 4รองรับ Opera Android เต็มรูปแบบ ใช่Safari iOS รองรับเต็มรูปแบบ ใช่Samsung Internet Android รองรับเต็มรูปแบบ ใช่nodejs รองรับเต็มที่ ใช่
เครื่องหมายจุลภาคต่อท้ายในพารามิเตอร์การสนับสนุน Chrome เต็มรูปแบบ 58Edge ไม่มีหมายเลขรองรับFirefox รองรับเต็มรูปแบบ 52IE ไม่มีหมายเลขรองรับโอเปร่าสนับสนุนอย่างเต็มที่ 45Safari ไม่มีหมายเลขรองรับรองรับ WebView Android เต็มรูปแบบ 58Chrome Android รองรับเต็มรูปแบบ 58Firefox Android รองรับเต็มรูปแบบ 52Opera Android รองรับเต็มรูปแบบ 43Safari iOS ไม่มีหมายเลขรองรับSamsung Internet Android รองรับเวอร์ชันเต็ม 7.0nodejs รองรับ 8.0.0 เต็มรูปแบบ

ตำนาน

การสนับสนุนอย่างเต็มที่การสนับสนุนอย่างเต็มที่ ไม่สนับสนุนไม่สนับสนุน

เนื่องจากเป็นวัตถุภาษา C จึงต้องประกาศฟังก์ชัน การประกาศฟังก์ชันผู้ใช้ เช่น การประกาศดำเนินการในสองรูปแบบ - ในรูปแบบของคำอธิบายและในรูปแบบของคำจำกัดความ

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

มาตรฐานภาษาใช้วิธีการประกาศฟังก์ชันต่อไปนี้:

result_typeบัตรประจำตัวประชาชน _functions(ตัวแปร type1, ..., ตัวแปรประเภท N);

โปรดทราบว่าไม่จำเป็นต้องระบุตัวระบุตัวแปรในวงเล็บต้นแบบ เนื่องจากคอมไพเลอร์ภาษาไม่ได้ประมวลผลตัวแปรเหล่านั้น

คำอธิบายต้นแบบช่วยให้คอมไพลเลอร์ตรวจสอบว่าประเภทและจำนวนพารามิเตอร์ตรงกันเมื่อมีการเรียกใช้ฟังก์ชันจริง

ตัวอย่างคำอธิบายฟังก์ชันสนุกๆ พร้อมรายการพารามิเตอร์:

ลอยสนุก (int, float, int, int);

คำจำกัดความที่สมบูรณ์ของฟังก์ชันมีดังนี้:

result_typeบัตรประจำตัวประชาชน _functions (รายการพารามิเตอร์)

รหัสฟังก์ชัน

ประเภทผลลัพธ์จะกำหนดประเภทของนิพจน์ที่มีค่าจะถูกส่งกลับไปยังจุดการโทรโดยใช้ตัวดำเนินการ กลับ<выражение> .

หากไม่ได้ระบุประเภทฟังก์ชัน ระบบจะใช้ประเภทเริ่มต้นแทน ภายใน .

รายการพารามิเตอร์ประกอบด้วยรายการประเภทพารามิเตอร์และตัวระบุพารามิเตอร์ คั่นด้วยเครื่องหมายจุลภาค

ฟังก์ชันอาจไม่มีพารามิเตอร์ แต่จำเป็นต้องมีวงเล็บไม่ว่าในกรณีใด

หากฟังก์ชันไม่ส่งคืนค่าใด ๆ จะต้องประกาศให้เป็นฟังก์ชันประเภทนั้น เป็นโมฆะ (ว่างเปล่า).

ในกรณีนี้ผู้ปฏิบัติงาน กลับ คุณไม่จำเป็นต้องใส่มัน

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

ตัวอย่างของฟังก์ชันที่กำหนดค่าที่น้อยที่สุดของตัวแปรจำนวนเต็มสองตัว:

int นาที (int x, int y)

กลับ(x

ต้องใช้ฟังก์ชันทั้งหมดที่ส่งคืนค่าทางด้านขวาของนิพจน์ C มิฉะนั้นผลลัพธ์ที่ส่งคืนจะหายไป

หากฟังก์ชันไม่มีรายการพารามิเตอร์ เมื่อประกาศฟังก์ชันดังกล่าว แนะนำให้ระบุคีย์เวิร์ดที่เป็นโมฆะในวงเล็บด้วย ตัวอย่างเช่น, เป็นโมฆะหลัก (เป็นโมฆะ).

นิพจน์ใน JavaScriptเป็นการรวมกัน ตัวถูกดำเนินการและ ตัวดำเนินการ.

การดำเนินงานในนิพจน์จะถูกดำเนินการตามลำดับตามค่าลำดับความสำคัญ (ยิ่งค่าลำดับความสำคัญสูงเท่าใดก็ยิ่งสูงเท่านั้น) ผลลัพธ์ที่ส่งคืนไม่ได้เป็นประเภทเดียวกันกับประเภทข้อมูลที่กำลังประมวลผลเสมอไป ตัวอย่างเช่น การดำเนินการเปรียบเทียบเกี่ยวข้องกับตัวถูกดำเนินการประเภทต่างๆ แต่ผลลัพธ์ที่ส่งคืนจะเป็นประเภทบูลีนเสมอ

ข้าว. 1. โครงสร้างนิพจน์ใน JavaScript

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

ผู้ประกอบการเป็นสัญลักษณ์ภาษาที่ใช้ดำเนินการต่างๆ กับข้อมูล ตัวดำเนินการสามารถเขียนได้โดยใช้อักขระเครื่องหมายวรรคตอนหรือคำสำคัญ

ขึ้นอยู่กับจำนวนตัวถูกดำเนินการ ตัวดำเนินการประเภทต่างๆ ต่อไปนี้จะมีความโดดเด่น:
เอกนารี— ตัวถูกดำเนินการหนึ่งตัวเกี่ยวข้องกับการปฏิบัติการ
ไบนารี่— การดำเนินการเกี่ยวข้องกับตัวถูกดำเนินการสองตัว
ประกอบไปด้วย- รวมตัวถูกดำเนินการสามตัวเข้าด้วยกัน

รูปแบบการแสดงออกที่ง่ายที่สุดคือ ตัวอักษร— สิ่งที่ประเมินตัวเอง เช่น หมายเลข 100 สตริง "Hello world" ตัวแปรยังสามารถเป็นนิพจน์ได้ เนื่องจากตัวแปรจะประเมินค่าที่กำหนดให้กับตัวแปรนั้น

นิพจน์และตัวดำเนินการใน JavaScript

1. ตัวดำเนินการทางคณิตศาสตร์

ตัวดำเนินการทางคณิตศาสตร์ออกแบบมาเพื่อดำเนินการทางคณิตศาสตร์ โดยทำงานกับตัวถูกดำเนินการตัวเลข (หรือตัวแปรที่เก็บค่าตัวเลข) โดยส่งคืนค่าตัวเลขตามผลลัพธ์

หากหนึ่งในตัวถูกดำเนินการเป็นสตริง ตัวแปล JavaScript จะพยายามแปลงเป็นประเภทตัวเลข จากนั้นดำเนินการตามความเหมาะสม หากไม่สามารถแปลงประเภทได้ ผลลัพธ์จะเป็น NaN (ไม่ใช่ตัวเลข)

ตารางที่ 1. ตัวดำเนินการทางคณิตศาสตร์
ผู้ปฏิบัติงาน/ปฏิบัติการ คำอธิบาย ลำดับความสำคัญ
+ นอกจากนี้ เพิ่มตัวถูกดำเนินการที่เป็นตัวเลข หากหนึ่งในตัวถูกดำเนินการเป็นสตริง ผลลัพธ์ของนิพจน์จะเป็นสตริง 12
- การลบ ลบตัวถูกดำเนินการที่สองจากตัวแรก 12
- ยูนินารีลบ แปลงจำนวนบวกให้เป็นจำนวนลบและในทางกลับกัน 14
* การคูณ คูณตัวถูกดำเนินการสองตัว 13
/ แผนก แบ่งตัวถูกดำเนินการตัวแรกด้วยตัวที่สอง ผลลัพธ์ของการหารอาจเป็นจำนวนเต็มหรือเลขทศนิยมก็ได้ 13
% การแบ่งโมดูโล่ (ส่วนที่เหลือ) คำนวณส่วนที่เหลือซึ่งเป็นผลมาจากการหารจำนวนเต็มของตัวถูกดำเนินการตัวแรกด้วยตัวที่สอง ใช้กับทั้งจำนวนเต็มและจำนวนจุดลอยตัว 13
วาร์ x = 5, y = 8, z; z = x + y; // ส่งคืน 13 z = x - y; // กลับ -3 z = - y; // กลับ -8 z = x * y; // กลับ 40 z = x / y; // ส่งกลับ 0.625 z = y % x; // กลับ 3

2. ผู้ดำเนินการมอบหมาย

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

วาร์ ก = 5; // กำหนดค่าตัวเลข 5 ให้กับตัวแปร a var b = "hello"; // เก็บสตริงเฮลโลว์ไว้ในตัวแปร b var m = n = z = 10; // กำหนดตัวแปร m, n, z ค่าตัวเลข 10 x += 10; // เทียบเท่ากับ x = x + 10; x -= 10; // เทียบเท่ากับ x = x - 10; x *= 10; // เทียบเท่ากับ x = x * 10; x /= 10; // เทียบเท่ากับ x = x / 10; x %= 10; // เทียบเท่ากับ x = x % 10;

3. ตัวดำเนินการเพิ่มและลด

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

var x = y = m = n = 5, z, s, k, l; z = ++x * 2; /* จากการคำนวณจะส่งกลับค่า z = 12, x = 6 เช่น ค่าของ x จะเพิ่มขึ้น 1 ก่อนจากนั้นจึงดำเนินการคูณ */ s = y++ * 2; /* จากการคำนวณจะส่งกลับค่า s = 10, y = 6 เช่น ขั้นแรก ดำเนินการคูณ จากนั้นค่าที่เพิ่มขึ้น 1 จะถูกเก็บไว้ในตัวแปร y */ k = --m * 2; // ส่งกลับค่า k = 8, m = 4 l = n-- * 2; // ส่งกลับค่า l = 10, n = 4

4. ตัวดำเนินการเปรียบเทียบ

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

หากไม่สามารถแปลงตัวถูกดำเนินการทั้งสองเป็นตัวเลขหรือสตริงได้สำเร็จ ตัวดำเนินการจะส่งคืนค่า false เสมอ

หากตัวถูกดำเนินการทั้งสองตัวเป็นสตริง/ตัวเลข หรือสามารถแปลงเป็นสตริง/ตัวเลขได้ ระบบจะเปรียบเทียบค่าเหล่านั้นเป็นสตริง/ตัวเลข

ถ้าตัวถูกดำเนินการตัวหนึ่งเป็นสตริง/แปลงเป็นสตริง และอีกตัวเป็นตัวเลข/แปลงเป็นตัวเลข ตัวดำเนินการจะพยายามแปลงสตริงเป็นตัวเลขและทำการเปรียบเทียบตัวเลข หากสตริงไม่ใช่ตัวเลข สตริงนั้นจะถูกแปลงเป็น NaN และผลลัพธ์ของการเปรียบเทียบจะเป็น false

ส่วนใหญ่แล้วการดำเนินการเปรียบเทียบจะใช้เมื่อจัดสาขาในโปรแกรม

ตารางที่ 4. ตัวดำเนินการเปรียบเทียบ
ผู้ปฏิบัติงาน/ปฏิบัติการ คำอธิบาย ลำดับความสำคัญ
== ความเท่าเทียมกัน ทดสอบสองค่าด้วยค่าเดียวกัน อนุญาตให้แปลงประเภทได้ คืนค่าเป็นจริงหากตัวถูกดำเนินการเหมือนกัน และคืนค่าเป็นเท็จหากต่างกัน 9
!= อสมการ คืนค่าเป็นจริงหากตัวถูกดำเนินการไม่เท่ากัน 9
=== ตัวตน ทดสอบตัวถูกดำเนินการสองตัวสำหรับ "ข้อมูลประจำตัว" โดยใช้คำจำกัดความที่เข้มงวดของการจับคู่ คืนค่าเป็นจริงหากตัวถูกดำเนินการเท่ากันโดยไม่มีการแปลงประเภท 9
!== ไม่มีตัวตน ดำเนินการยืนยันตัวตน คืนค่าเป็นจริงหากตัวถูกดำเนินการไม่เท่ากันโดยไม่มีการแปลงประเภท 9
> เพิ่มเติม คืนค่าเป็นจริงหากตัวถูกดำเนินการตัวแรกมากกว่าตัวที่สอง มิฉะนั้นจะส่งคืนค่าเท็จ 10
>= มากกว่าหรือเท่ากับ คืนค่าเป็นจริงหากตัวถูกดำเนินการตัวแรกไม่น้อยกว่าตัวที่สอง มิฉะนั้นจะส่งคืนค่าเท็จ 10
คืนค่าเป็นจริงหากตัวถูกดำเนินการตัวแรกน้อยกว่าตัวที่สอง มิฉะนั้นจะส่งกลับค่าเท็จ 10
คืนค่าเป็นจริงหากตัวถูกดำเนินการตัวแรกไม่มากกว่าตัวที่สอง มิฉะนั้นจะส่งคืนค่าเท็จ 10
5 == "5"; // คืนค่าจริง 5 != -5.0; // คืนค่าจริง 5 === "5"; // กลับเท็จเท็จ === เท็จ; // คืนค่าจริง 1 !== จริง; // คืนค่าจริง 1 != จริง; // จะคืนค่าเท็จเนื่องจากค่าจริงถูกแปลงเป็น 1 3 > -3; // คืนค่าจริง 3 >= "4"; //คืนค่าเท็จ

5. ตัวดำเนินการเชิงตรรกะ

ตัวดำเนินการเชิงตรรกะอนุญาตให้คุณรวมเงื่อนไขที่ส่งคืนค่าบูลีน มักใช้ในคำสั่ง if Conditional

(2 < 3) && (3===3); // вернет true, так как выражения в обеих скобках дают true (x < 10 && x >0); // จะคืนค่าเป็นจริงหาก x อยู่ในช่วงตั้งแต่ 0 ถึง 10 !false; // คืนค่าจริง

6. ตัวดำเนินการ Bitwise

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

ตารางที่ 6. ตัวดำเนินการ Bitwise
ผู้ปฏิบัติงาน/ปฏิบัติการ คำอธิบาย ลำดับความสำคัญ
& ระดับบิต และ ถ้าทั้งสองบิตเป็น 1 บิตผลลัพธ์จะเป็น 1 มิฉะนั้นผลลัพธ์จะเป็น 0 8
| บิตไวส์หรือ หากตัวถูกดำเนินการตัวใดตัวหนึ่งมี 1 ที่ตำแหน่ง ผลลัพธ์ก็จะมี 1 อยู่ที่ตำแหน่งนั้นด้วย มิฉะนั้น ผลลัพธ์ที่ตำแหน่งนั้นจะเป็น 0 6
↑ เอกสิทธิ์เฉพาะบุคคล หรือ หากค่าเดียวเท่านั้นที่มี 1 ที่ตำแหน่งใดๆ ผลลัพธ์ก็จะมี 1 ที่ตำแหน่งนั้น มิฉะนั้น ผลลัพธ์ที่ตำแหน่งนั้นจะเป็น 0 7
~ การปฏิเสธ การดำเนินการปฏิเสธระดับบิตจะดำเนินการกับการแทนค่าไบนารีของนิพจน์ ตำแหน่งใดๆ ที่มี 1 ในนิพจน์เดิมจะถูกแทนที่ด้วย 0 ตำแหน่งใดๆ ที่มี 0 ในนิพจน์ดั้งเดิมจะกลายเป็น 0 จำนวนบวกเริ่มต้นที่ 0 จำนวนลบเริ่มต้นที่ -1 ดังนั้น ~ n == -(n+1) 14
ตัวดำเนินการเลื่อนบิตของตัวถูกดำเนินการตัวแรกไปทางซ้ายตามจำนวนตำแหน่งบิตที่กำหนดโดยตัวถูกดำเนินการตัวที่สอง เลขศูนย์ใช้เพื่อเติมตำแหน่งทางด้านขวา ส่งกลับผลลัพธ์ประเภทเดียวกันกับตัวถูกดำเนินการทางซ้าย 11
>> เลื่อนไปทางขวา ตัวดำเนินการเลื่อนบิตของตัวถูกดำเนินการตัวแรกไปทางขวาตามจำนวนตำแหน่งบิตที่กำหนดโดยตัวถูกดำเนินการตัวที่สอง ตัวเลขที่ถูกเลื่อนออกนอกช่วงจะถูกลบออก บิตที่สำคัญที่สุด (ที่ 32) จะไม่มีการเปลี่ยนแปลงเพื่อรักษาเครื่องหมายของผลลัพธ์ หากตัวถูกดำเนินการตัวแรกเป็นค่าบวก บิตที่สำคัญที่สุดของผลลัพธ์จะถูกเติมด้วยศูนย์ หากตัวถูกดำเนินการตัวแรกเป็นค่าลบ บิตที่สำคัญที่สุดของผลลัพธ์จะถูกเติมด้วยตัวถูกดำเนินการ การเลื่อนค่าไปทางขวาหนึ่งตำแหน่งจะเทียบเท่ากับการหารด้วย 2 (ทิ้งเศษที่เหลือ) และการเลื่อนไปทางขวาด้วยสองตำแหน่งจะเทียบเท่ากับการหารด้วย 4 เป็นต้น 11
>>> เลื่อนไปทางขวาแบบ Bitwise โดยไม่มีเครื่องหมาย ตัวดำเนินการเลื่อนบิตของตัวถูกดำเนินการตัวแรกไปทางขวาตามจำนวนตำแหน่งบิตที่กำหนดโดยตัวถูกดำเนินการตัวที่สอง เลขศูนย์จะถูกเพิ่มทางด้านซ้าย โดยไม่คำนึงถึงเครื่องหมายของตัวถูกดำเนินการตัวแรก ตัวเลขที่ถูกเลื่อนออกนอกช่วงจะถูกลบออก 11
var x = 9, y = 5, z = 2, s = -5 ผลลัพธ์; // 9 เทียบเท่ากับ 1001, 5 เทียบเท่ากับ 0101 ผลลัพธ์ = x & y; // จะส่งกลับผลลัพธ์ 1 (เทียบเท่ากับ 0001) = x | ใช่; // จะส่งกลับผลลัพธ์ 13 (เทียบเท่ากับ 1101) = x ^ y; // ส่งกลับผลลัพธ์ 12 (เทียบเท่ากับ 1100) = ~ y; // จะส่งคืนค่า -6 (เทียบเท่ากับ 1100) ผลลัพธ์ = x<< y; // вернет 288 (эквивалентно 100100000) result = x >>z; // ส่งกลับ 2 (เทียบเท่ากับ 10) ผลลัพธ์ = s >>> z; // จะส่งกลับ 1073741822 (เทียบเท่ากับ 1111111111111111111111111111110)

7. ตัวดำเนินการสตริง

มีโอเปอเรเตอร์หลายตัวที่ทำงานกับสตริงในลักษณะพิเศษ

"1" + "10"; // กลับ "110" "1" + 10; // ส่งกลับ "110" 2 + 5 + "ดินสอสี"; // ส่งคืน "ดินสอสี 7 แท่ง" "ดินสอสี" + 2 + 5; // ส่งคืน "ดินสอสี 25 แท่ง" "1" > "10"; // กลับเท็จ "10"<= 10; // вернет true "СССР" == "ссср"; // вернет false x = "micro"; x+= "soft"; // вернет "microsoft"

8. ผู้ปฏิบัติงานพิเศษ

ตารางที่ 8. ตัวดำเนินการพิเศษ
ผู้ปฏิบัติงาน/ปฏิบัติการ คำอธิบาย ลำดับความสำคัญ
. การเข้าถึงทรัพย์สิน เข้าถึงคุณสมบัติของวัตถุ 15
,การคำนวณหลายรายการ ประเมินนิพจน์อิสระหลายรายการที่เขียนในบรรทัดเดียว 1
การจัดทำดัชนีอาร์เรย์ เข้าถึงองค์ประกอบอาร์เรย์หรือคุณสมบัติของวัตถุ 15
() การเรียกใช้ฟังก์ชัน, การจัดกลุ่ม การดำเนินการกลุ่มหรือการเรียกใช้ฟังก์ชัน 15
ประเภทของคำจำกัดความของชนิดข้อมูล ตัวดำเนินการ Unary ส่งคืนชนิดข้อมูลของตัวถูกดำเนินการ 14
instanceof การตรวจสอบประเภทของวัตถุ ตัวดำเนินการตรวจสอบว่าวัตถุนั้นเป็นอินสแตนซ์ของคลาสใดคลาสหนึ่งหรือไม่ ตัวถูกดำเนินการทางซ้ายต้องเป็นวัตถุ ตัวถูกดำเนินการทางขวาต้องมีชื่อของคลาสอ็อบเจ็กต์ ผลลัพธ์จะเป็นจริงหากวัตถุทางด้านซ้ายเป็นตัวอย่างของคลาสทางด้านขวา มิฉะนั้นจะเป็นเท็จ 10
ในการตรวจสอบการมีอยู่ของทรัพย์สิน ตัวถูกดำเนินการทางซ้ายจะต้องเป็นสตริง และตัวถูกดำเนินการทางขวาจะต้องเป็นอาร์เรย์หรือวัตถุ หากค่าทางซ้ายเป็นคุณสมบัติของวัตถุ ผลลัพธ์จะเป็น true 10
ใหม่ การสร้างวัตถุ ตัวดำเนินการสร้างอ็อบเจ็กต์ใหม่ที่มีคุณสมบัติที่ไม่ได้กำหนดไว้ จากนั้นเรียกใช้ฟังก์ชัน Constructor เพื่อเตรียมใช้งาน (ส่งพารามิเตอร์) สามารถใช้สร้างอาร์เรย์ได้ 1
ลบ ลบ ตัวดำเนินการอนุญาตให้คุณลบคุณสมบัติออกจากวัตถุหรือองค์ประกอบออกจากอาร์เรย์ คืนค่าเป็นจริงหากการลบสำเร็จ มิฉะนั้นจะคืนค่าเป็นเท็จ เมื่อลบองค์ประกอบอาร์เรย์ ความยาวจะไม่เปลี่ยนแปลง 14
โมฆะ การกำหนดนิพจน์โดยไม่มีค่าส่งคืน ตัวดำเนินการ Unary ละทิ้งค่าของตัวถูกดำเนินการและส่งกลับค่าที่ขีดล่าง 14
?: ตัวดำเนินการนิพจน์แบบมีเงื่อนไข ตัวดำเนินการแบบไตรภาคช่วยให้คุณสามารถจัดระเบียบการแยกย่อยแบบง่ายๆ นิพจน์เกี่ยวข้องกับตัวถูกดำเนินการสามตัว ตัวถูกดำเนินการตัวแรกต้องเป็นค่าบูลีนหรือแปลงเป็นหนึ่งตัว และตัวที่สองและสามต้องเป็นค่าใดก็ได้ หากตัวถูกดำเนินการตัวแรกเป็นจริง นิพจน์เงื่อนไขก็จะรับค่าของตัวถูกดำเนินการตัวที่สอง ถ้าเป็นเท็จ - แสดงว่าอันที่สาม 3
document.write("สวัสดีชาวโลก"); // แสดงสตริงสวัสดีชาวโลก i = 0, j = 1; // เก็บค่าไว้ในตัวแปร function1(10, 5); // การเรียกใช้ฟังก์ชัน function1 พร้อมพารามิเตอร์ 10 และ 5 var year = ; // สร้างอาร์เรย์ที่มีองค์ประกอบ typeof (a:1); // return "object" var d = new Date(); // สร้างวัตถุใหม่โดยใช้ตัวสร้าง Date() d อินสแตนซ์ของ Date; // return true var mycar = (ยี่ห้อ: "Honda", รุ่น: "Accord", ปี: 2548); "ทำ" ใน mycar; // return true var obj = new Object(); // สร้างวัตถุว่าง var food = ["นม", "ขนมปัง", "เนื้อ", "น้ำมันมะกอก", "ชีส"]; ลบอาหาร // ลบองค์ประกอบที่สี่ออกจากอาเรย์อาหาร x > 10 ? x * 2: x / 2; // ส่งคืน x * 2 ถ้า x > 10 มิฉะนั้น x / 2

9. ความคิดเห็นใน JavaScript

ความคิดเห็นบรรทัดเดียว: คุณต้องนำสัญลักษณ์ด้านหน้าข้อความความคิดเห็น //

ฟังก์ชั่นเป็นหนึ่งในองค์ประกอบพื้นฐานใน JavaScript ฟังก์ชั่นคือขั้นตอน JavaScript ซึ่งเป็นชุดคำสั่งที่ทำงานหรือคำนวณค่า หากต้องการใช้ฟังก์ชัน คุณต้องกำหนดฟังก์ชันไว้ที่ไหนสักแห่งในขอบเขตที่คุณต้องการเรียกใช้ฟังก์ชัน

วิธีเป็นฟังก์ชันที่เป็นคุณสมบัติของวัตถุ อ่านเพิ่มเติมเกี่ยวกับออบเจ็กต์และวิธีการในการทำงานกับออบเจ็กต์

ฟังก์ชั่นการโทร

การกำหนดฟังก์ชันไม่ได้ดำเนินการ การกำหนดฟังก์ชันเพียงตั้งชื่อฟังก์ชันและระบุสิ่งที่ต้องทำเมื่อมีการเรียกใช้ฟังก์ชัน กำลังโทรฟังก์ชันจะดำเนินการตามที่ระบุจริง ๆ ด้วยพารามิเตอร์ที่ระบุ ตัวอย่างเช่น หากคุณกำหนดฟังก์ชัน square คุณสามารถเรียกมันได้ดังนี้:

สี่เหลี่ยม(5);

คำสั่งก่อนหน้าเรียกฟังก์ชันด้วยอาร์กิวเมนต์ 5 ฟังก์ชันดำเนินการคำสั่งและส่งกลับค่า 25

ฟังก์ชั่นจะต้องอยู่ในขอบเขตเมื่อมีการเรียกใช้ แต่การประกาศฟังก์ชั่นสามารถยกขึ้นได้ (ปรากฏด้านล่างการโทรในโค้ด) ดังในตัวอย่างนี้:

Console.log (สี่เหลี่ยม (5)); /* ... */ ฟังก์ชั่น สแควร์(n) ( return n * n; )

ขอบเขตของฟังก์ชันคือฟังก์ชันที่ถูกประกาศ หรือทั้งโปรแกรมหากมีการประกาศที่ระดับบนสุด

บันทึก:ใช้งานได้เฉพาะเมื่อกำหนดฟังก์ชันโดยใช้ไวยากรณ์ด้านบน (เช่น ฟังก์ชัน funcName()()) รหัสด้านล่างจะไม่ทำงาน นั่นหมายความว่าการยกฟังก์ชันใช้งานได้เฉพาะกับการประกาศฟังก์ชันเท่านั้น ไม่ใช่กับการแสดงออกของฟังก์ชัน

Console.log (สี่เหลี่ยมจัตุรัส); // ยกกำลังสองด้วยค่าเริ่มต้นที่ไม่ได้กำหนด console.log(สี่เหลี่ยม(5)); // Uncaught TypeError: สแควร์ไม่ใช่ฟังก์ชัน var square = function(n) ( return n * n; )

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

ฟังก์ชั่นสามารถเรียกตัวเองได้ ตัวอย่างเช่น นี่คือฟังก์ชันที่คำนวณแฟคทอเรียลแบบวนซ้ำ:

ฟังก์ชัน factorial(n) ( if ((n === 0) || (n === 1)) return 1; else return (n * factorial(n - 1)); )

จากนั้นคุณสามารถคำนวณแฟกทอเรียลของหนึ่งถึงห้าได้ดังนี้:

วาร์ ก, ข, ค, ง, อี; ก = แฟกทอเรียล (1); // a รับค่า 1 b = แฟกทอเรียล (2); // b รับค่า 2 c = แฟกทอเรียล (3); // c รับค่า 6 d = แฟกทอเรียล (4); // d รับค่า 24 e = factorial(5); //e รับค่า 120

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

ขอบเขตของฟังก์ชัน

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

// ตัวแปรต่อไปนี้ถูกกำหนดไว้ในขอบเขตสากล var num1 = 20, num2 = 3, name = "Chamahk"; // ฟังก์ชันนี้ถูกกำหนดไว้ในฟังก์ชันขอบเขตสากล multiply() ( return num1 * num2; ) multiply(); // ส่งคืน 60 // ตัวอย่างฟังก์ชันที่ซ้อนกัน function getScore() ( var num1 = 2, num2 = 3; function add() ( return name + " Score " + (num1 + num2); ) return add(); ) getScore (); // ส่งกลับ "ชะมะคะแนน 5"

ขอบเขตและสแต็กฟังก์ชัน

การเรียกซ้ำ

ฟังก์ชั่นสามารถอ้างถึงและเรียกตัวเองได้ มีสามวิธีสำหรับฟังก์ชันในการอ้างถึงตัวเอง:

  1. ชื่อของฟังก์ชัน
  2. ตัวแปรในขอบเขตที่อ้างถึงฟังก์ชัน

ตัวอย่างเช่น พิจารณาคำจำกัดความของฟังก์ชันต่อไปนี้:

Var foo = function bar() ( // คำสั่งไปที่นี่ );

ภายในเนื้อหาของฟังก์ชัน สิ่งต่อไปนี้จะเทียบเท่ากันทั้งหมด:

  1. บาร์()
  2. อาร์กิวเมนต์.callee()
  3. ฟู()

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

วาร์ x = 0; ในขณะที่(x< 10) { // "x < 10" is the loop condition // do stuff x++; }

สามารถแปลงเป็นฟังก์ชันแบบเรียกซ้ำและการเรียกใช้ฟังก์ชันนั้นได้:

Function loop(x) ( if (x >= 10) // "x >= 10" เป็นเงื่อนไขการออก (เทียบเท่ากับ "!(x< 10)") return; // do stuff loop(x + 1); // the recursive call } loop(0);

อย่างไรก็ตาม อัลกอริธึมบางตัวไม่สามารถเป็นการวนซ้ำอย่างง่ายได้ ตัวอย่างเช่น การรับโหนดทั้งหมดของโครงสร้างแบบต้นไม้ (เช่น DOM) ทำได้ง่ายกว่าโดยใช้การเรียกซ้ำ:

ฟังก์ชั่น walkTree(node) ( if (node ​​​​== null) // return; // ทำบางสิ่งกับ node for (var i = 0; i< node.childNodes.length; i++) { walkTree(node.childNodes[i]); } }

เมื่อเปรียบเทียบกับฟังก์ชันลูป การเรียกซ้ำแต่ละครั้งจะทำการเรียกซ้ำหลายครั้งที่นี่

มีความเป็นไปได้ที่จะแปลงอัลกอริธึมแบบเรียกซ้ำให้เป็นแบบไม่เรียกซ้ำ แต่บ่อยครั้งที่ตรรกะนั้นซับซ้อนกว่ามากและการทำเช่นนี้จำเป็นต้องใช้สแต็ก ในความเป็นจริง การเรียกซ้ำนั้นใช้สแต็ก: สแต็กฟังก์ชัน

พฤติกรรมที่เหมือนสแต็กสามารถเห็นได้ในตัวอย่างต่อไปนี้:

ฟังก์ชั่น foo(i) ( ถ้า (i< 0) return; console.log("begin: " + i); foo(i - 1); console.log("end: " + i); } foo(3); // Output: // begin: 3 // begin: 2 // begin: 1 // begin: 0 // end: 0 // end: 1 // end: 2 // end: 3

ฟังก์ชั่นและการปิดที่ซ้อนกัน

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

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

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

ตัวอย่างต่อไปนี้แสดงฟังก์ชันที่ซ้อนกัน:

ฟังก์ชัน addSquares(a, b) ( function square(x) ( return x * x; ) return square(a) + square(b); ) a = addSquares(2, 3); // ส่งคืน 13 b = addSquares(3, 4); // ส่งคืน 25 c = addSquares(4, 5); // คืนค่า 41

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

ฟังก์ชั่นภายนอก(x) ( ฟังก์ชั่นภายใน(y) ( กลับ x + y; ) กลับภายใน; ) fn_inside = ภายนอก(3); // ลองคิดดู: ขอฟังก์ชันที่บวก 3 ให้กับสิ่งที่คุณให้ // ​​it result = fn_inside(5); // ส่งกลับ 8 result1 = ภายนอก (3) (5); // คืนค่า 8

การอนุรักษ์ตัวแปร

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

สิ่งนี้ไม่แตกต่างจากการจัดเก็บการอ้างอิงในออบเจ็กต์อื่น แต่มักจะชัดเจนน้อยกว่าเนื่องจากไม่ได้ตั้งค่าการอ้างอิงโดยตรงและไม่สามารถตรวจสอบได้

ฟังก์ชันที่ซ้อนกันแบบทวีคูณ

ฟังก์ชันสามารถคูณซ้อนกันได้ เช่น ฟังก์ชัน (A) ที่มีฟังก์ชัน (B) ที่มีฟังก์ชัน (C) การปิดแบบฟอร์มทั้งฟังก์ชัน B และ C ที่นี่ ดังนั้น B จึงสามารถเข้าถึง A และ C สามารถเข้าถึง B ได้ นอกจากนี้ เนื่องจาก C สามารถเข้าถึง B ซึ่งสามารถเข้าถึง A ได้ C จึงสามารถเข้าถึง A ได้ ดังนั้น การปิดจึงสามารถมีหลายขอบเขตได้ พวกมันมีขอบเขตของฟังก์ชันที่มีอยู่ซ้ำ ๆ สิ่งนี้เรียกว่า การผูกมัดขอบเขต. (เหตุใดจึงเรียกว่า "การผูกมัด" จะอธิบายในภายหลัง)

ลองพิจารณาตัวอย่างต่อไปนี้:

ฟังก์ชัน A(x) ( ฟังก์ชั่น B(y) ( ฟังก์ชั่น C(z) ( console.log(x + y + z); ) C(3); ) B(2); ) A(1); // บันทึก 6 (1 + 2 + 3)

ในตัวอย่างนี้ C เข้าถึง B "sy และ A "s x สิ่งนี้สามารถทำได้เนื่องจาก:

  1. B ก่อให้เกิดการปิดซึ่งรวมถึง A เช่น B สามารถเข้าถึงอาร์กิวเมนต์และตัวแปรของ A
  2. C ก่อให้เกิดการปิดรวมถึง B.
  3. เนื่องจากการปิดของ B รวมถึง A การปิดของ C รวมถึง A, C สามารถเข้าถึงทั้ง B และอาร์กิวเมนต์และตัวแปรของ A "กล่าวอีกนัยหนึ่ง C ห่วงโซ่ขอบเขตของ B และ A ตามลำดับนั้น

อย่างไรก็ตามสิ่งที่ตรงกันข้ามไม่เป็นความจริง A ไม่สามารถเข้าถึง C ได้ เนื่องจาก A ไม่สามารถเข้าถึงอาร์กิวเมนต์หรือตัวแปรใดๆ ของ B ซึ่ง C เป็นตัวแปรของ ดังนั้น C ยังคงเป็นส่วนตัวของ B เท่านั้น

ข้อขัดแย้งของชื่อ

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

ฟังก์ชั่นภายนอก() ( var x = 5; ฟังก์ชั่นภายใน(x) ( return x * 2; ) กลับภายใน; ) ภายนอก())(10); // คืนค่า 20 แทนที่จะเป็น 10

ข้อขัดแย้งของชื่อเกิดขึ้นที่คำสั่ง return x และอยู่ระหว่างพารามิเตอร์ x ภายในและตัวแปร s ภายนอก x ห่วงโซ่ขอบเขตที่นี่คือ ( inside , Outside , global object) ดังนั้นภายใน "s x มาก่อนภายนอก "s x และส่งคืน 20 (ภายใน "s x) แทนที่จะเป็น 10 (นอก "s x)

การปิด

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

Var pet = function(name) ( // ฟังก์ชั่นภายนอกกำหนดตัวแปรชื่อ "name" var getName = function() ( return name; // ฟังก์ชั่นภายในสามารถเข้าถึงตัวแปร "name" ของตัวแปรภายนอก //function ) return getName; // คืนฟังก์ชั่นภายในซึ่งจะเปิดเผยไปยังขอบเขตภายนอก ) myPet = pet("Vivie"); สัตว์เลี้ยงของฉัน(); // ส่งกลับ "วิวี่"

อาจซับซ้อนกว่าโค้ดด้านบนมาก อ็อบเจ็กต์ที่มีวิธีการจัดการตัวแปรภายในของฟังก์ชันภายนอกสามารถส่งคืนได้

Var createPet = function(name) ( var sex; return ( setName: function(newName) ( name = newName; ), getName: function() ( return name; ), getSex: function() ( return sex; ), setSex: ฟังก์ชั่น(newSex) ( if(typeof newSex === "string" && (newSex.toLowerCase() === "male" || newSex.toLowerCase() === "Female")) ( sex = newSex; ) ) ) ) var pet = createPet("Vivie"); pet.getName(); // Vivie pet.setName("โอลิเวอร์"); pet.setSex("ชาย"); สัตว์เลี้ยง.getSex(); // ตัวผู้ pet.getName(); //โอลิเวอร์

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

Var getCode = (function() ( var apiCode = "0]Eal(eh&2"; // โค้ดเราไม่ต้องการให้บุคคลภายนอกสามารถแก้ไขได้... return function() ( return apiCode; ); ))() ; getCode(); // ส่งคืน apiCode

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

Var createPet = function(name) ( // ฟังก์ชั่นภายนอกกำหนดตัวแปรชื่อ "name" return ( setName: function(name) ( // ฟังก์ชั่นที่แนบมายังกำหนดตัวแปรชื่อ "name" อีกด้วย name = name; // เราจะเข้าถึง "ชื่อ" ที่กำหนดโดยฟังก์ชันภายนอกได้อย่างไร ) ) )

การใช้วัตถุอาร์กิวเมนต์

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

อาร์กิวเมนต์[i]

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

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

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

ฟังก์ชั่น myConcat(separator) ( var result = ""; // เริ่มต้นรายการ var i; // วนซ้ำอาร์กิวเมนต์สำหรับ (i = 1; i< arguments.length; i++) { result += arguments[i] + separator; } return result; }

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

// ส่งกลับ "แดง, ส้ม, น้ำเงิน, " myConcat(", ", "red", "orange", "blue"); // ส่งคืน "elephant; giraffe; lion; cheetah; " myConcat("; ", "elephant", "giraffe", "lion", "cheetah"); // ส่งกลับ "sage. basil. oregano.pepper. parsley. " myConcat(". ", "sage", "basil", "oregano", "pepper", "parsley");

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

ปัจจัยสองประการที่มีอิทธิพลต่อการใช้ฟังก์ชันลูกศร ได้แก่ ฟังก์ชันที่สั้นลงและการไม่ผูกมัดฟังก์ชันนี้

ฟังก์ชั่นที่สั้นกว่า

ในรูปแบบการทำงานบางรูปแบบ เรายินดีต้อนรับฟังก์ชันที่สั้นกว่า เปรียบเทียบ:

Var a = [ "ไฮโดรเจน", "ฮีเลียม", "ลิเธียม", "เบริลเลียม" ]; var a2 = a.map(function(s) ( return s.length; )); console.log(a2); // บันทึก var a3 = a.map(s => s.length); console.log(a3); // บันทึก

ไม่แยกอันนี้.

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

Function Person() ( // ตัวสร้าง Person() กำหนด `this` ในตัวมันเอง this.age = 0; setInterval(function growUp() ( // ในโหมดไม่เข้มงวด ฟังก์ชัน growUp() จะกำหนด `this` // เป็น global object ซึ่งแตกต่างจาก `this` // ที่กำหนดโดย Person() Constructor. this.age++; ), 1000); ) var p = new Person();

ใน ECMAScript 3/5 ปัญหานี้ได้รับการแก้ไขแล้วโดยการกำหนดค่าในสิ่งนี้ให้กับตัวแปรที่สามารถปิดได้

Function Person() ( var self = this; // บางคนเลือก `that` แทนที่จะเป็น `self`. // เลือกหนึ่งอย่างและสอดคล้องกัน self.age = 0; setInterval(function growUp() ( // การเรียกกลับหมายถึง ตัวแปร `self` ซึ่ง // ค่าเป็นวัตถุที่คาดหวัง self.age++; ), 1000); )