ฟังก์ชันซ้อน JavaScript


97

ฉันได้รับโค้ดสำหรับ javascript ซึ่งฉันไม่เข้าใจ:

function dmy(d) {
    function pad2(n) {
        return (n < 10) ? '0' + n : n;
    }

    return pad2(d.getUTCDate()) + '/' +
       pad2(d.getUTCMonth() + 1) + '/' +
       d.getUTCFullYear();
}

function outerFunc(base) {
    var punc = "!";

    //inner function
    function returnString(ext) {
       return base + ext + punc;
    }

    return returnString;
}

ฟังก์ชันสามารถกำหนดภายในฟังก์ชันอื่นได้อย่างไร? เราสามารถเรียก pad2 () จากภายนอกฟังก์ชัน () ได้หรือไม่?

ช่วยเปิดไฟให้หน่อย ขอบคุณ


14
ฟังก์ชันสามารถสร้างได้ภายในฟังก์ชัน นั่นคือใช้ได้อย่างสมบูรณ์แบบ
0x499602D2

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับ fucntions ที่ซ้อนกันโปรดดูที่วิกิพีเดีย
Mawg กล่าวว่าคืนสถานะ Monica

คำตอบ:


141

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

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

function foo(doBar)
{
  function bar()
  {
    console.log( 'bar' );
  }

  function baz()
  {
    console.log( 'baz' );
  }

  window.baz = baz;
  if ( doBar ) bar();
}

ในตัวอย่างนี้ฟังก์ชั่น baz จะสามารถใช้ได้สำหรับการใช้งานหลังจากที่ฟังก์ชั่นได้รับการทำงานเป็นมันแทนที่foo window.bazฟังก์ชันบาร์จะไม่สามารถใช้ได้กับบริบทใด ๆ นอกจากขอบเขตที่มีอยู่ภายในfooฟังก์ชัน

เป็นตัวอย่างอื่น:

function Fizz(qux)
{
  this.buzz = function(){
    console.log( qux );
  };
}

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


window.baz = baz คืออะไร? ทำไมสาย m? ke baz ถึงมี?
Ziyang Zhang

@ ZiyangZhang ย่อหน้าหลังบล็อกโค้ดนั้นมีคำอธิบายมีส่วนใดที่ไม่ชัดเจนหรือไม่?
zzzzBov

35

มันถูกเรียกว่าปิด

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

เป็นคุณสมบัติที่ทรงพลังมาก คุณสามารถดูคำอธิบายเพิ่มเติมได้ที่นี่:

javascript_closures_for_dummies.html มิเรอร์บน Archive.org


14
function x() {}

เทียบเท่า (หรือคล้ายกันมาก) กับ

var x = function() {}

เว้นแต่ฉันจะเข้าใจผิด

จึงไม่มีอะไรน่าตลกเกิดขึ้น


8
ไวยากรณ์แรกจะถูกย้ายไปที่จุดเริ่มต้นของเอกสาร ดังนั้นจึงเป็นไปได้ที่จะเรียกใช้ฟังก์ชัน 'x' ก่อนที่ฟังก์ชันจะเริ่มทำงาน
ทอม

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

@TheZ ฉันคิดว่า Chrome เพิ่งเพิ่มการอนุมานชื่อฟังก์ชันในการดีบักดังนั้นคุณจะไม่ปวดหัวเหมือนเมื่อก่อนในกรณีทั่วไป
jinglesthula

@jinglesthula ใช่! Chrome เพิ่มการอนุมานชื่อนี้ในขณะที่ย้อนกลับไปและเป็นที่ชื่นชมมาก :)
TheZ

10

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

function foo() {
    function bar() {
        return 1;
    }
    return bar();
}

fooจัดการbarภายในตัวเองbarไม่สามารถสัมผัสได้จากขอบเขตภายนอกเว้นแต่จะกำหนดไว้ในขอบเขตภายนอก

ดังนั้นสิ่งนี้จะไม่ทำงาน:

function foo() {
    function bar() {
        return 1;
    }
}

bar(); // throws error: bar is not defined

4

เมื่อคุณประกาศฟังก์ชันภายในฟังก์ชันฟังก์ชันภายในจะพร้อมใช้งานเฉพาะในขอบเขตที่มีการประกาศหรือในกรณีของคุณpad2สามารถเรียกได้เฉพาะในdmyขอบเขตเท่านั้น

ตัวแปรทั้งหมดที่มีdmyอยู่สามารถมองเห็นได้pad2แต่จะไม่เกิดขึ้นในลักษณะอื่น: D


2

เป็นเรื่องปกติอย่างยิ่งใน Javascript (และหลายภาษา) ที่จะมีฟังก์ชันภายในฟังก์ชัน

ใช้เวลาในการเรียนรู้ภาษาอย่าใช้มันบนพื้นฐานที่คล้ายกับสิ่งที่คุณรู้อยู่แล้ว ฉันขอแนะนำให้ดูชุดการนำเสนอ YUI ของ Douglas Crockford บน Javascript โดยเน้นพิเศษที่Act III: Function the Ultimate (ลิงก์ไปยังการดาวน์โหลดวิดีโอสไลด์และการถอดเสียง)


0

function foo() {
  function bar() {
    return 1;
  }
}
bar();

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

function foo() {
  function bar() {
    return 1;
  }
  bar();
}

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