Hàm lồng nhau trong JavaScript


96

Tôi nhận được một đoạn mã cho javascript mà tôi không hiểu:

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

Làm thế nào một hàm có thể được xác định trong một hàm khác? Chúng ta có thể gọi pad2 () từ bên ngoài hàm () của tôi không?

Xin vui lòng đặt một số ánh sáng vào nó. Cảm ơn


13
các hàm có thể được tạo bên trong các hàm. Điều đó hoàn toàn hợp lệ.
0x499602D2

Câu trả lời:


140

Các hàm là một loại biến khác trong JavaScript (tất nhiên là có một số sắc thái). Tạo một hàm trong một hàm khác sẽ thay đổi phạm vi của hàm giống như cách nó sẽ thay đổi phạm vi của một biến. Điều này đặc biệt quan trọng đối với việc sử dụng với việc đóng cửa để giảm tổng ô nhiễm không gian tên toàn cầu.

Các chức năng được xác định trong một chức năng khác sẽ không thể truy cập được bên ngoài chức năng trừ khi chúng đã được gắn vào một đối tượng có thể truy cập bên ngoài chức năng:

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

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

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

Trong ví dụ này, hàm baz sẽ có sẵn để sử dụng sau khi foohàm đã được chạy, vì nó bị ghi đè window.baz. Hàm bar sẽ không khả dụng cho bất kỳ ngữ cảnh nào ngoài các phạm vi có trong foohàm.

như một ví dụ khác:

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

Các Fizzchức năng được thiết kế như một nhà xây dựng do đó, khi chạy, nó gán một buzzchức năng để các đối tượng mới được tạo ra.


Window.baz = baz là gì? Tại sao dòng này m? Ke baz có sẵn?
Ziyang Zhang

@ZiyangZhang, đoạn sau khối mã đó có giải thích, có một phần cụ thể nào đó không rõ ràng không?
zzzzBov

35

Nó được gọi là sự đóng cửa .

Về cơ bản, chức năng được định nghĩa trong chức năng khác chỉ có thể truy cập được trong chức năng này. Nhưng kết quả có thể được thông qua và sau đó kết quả này có thể được gọi.

Nó là một tính năng rất mạnh mẽ. Bạn có thể xem thêm giải thích tại đây:

javascript_closures_for_dummies.html mirror trên Archive.org


13
function x() {}

tương đương (hoặc rất giống) với

var x = function() {}

trừ khi tôi nhầm.

Vì vậy, không có gì vui xảy ra.


8
Cú pháp đầu tiên sẽ được chuyển đến đầu tài liệu. vì vậy có thể gọi hàm 'x' trước khi funtion được khởi tạo.
Tom

10
Cú pháp đầu tiên cũng sẽ giúp bạn ngăn xếp dấu vết đẹp hơn nhiều với chức năng đặt tên, thứ hai sẽ cung cấp cho bạn đau đầu
TheZ

@TheZ Tôi nghĩ Chrome gần đây đã thêm suy luận tên chức năng để gỡ lỗi để bạn không gặp phải vấn đề đau đầu như trước đây trong trường hợp phổ biến.
jinglesthula

@jinglesthula Có! Chrome đã thêm suy luận tên này một thời gian trước và nó được đánh giá cao :)
TheZ

10

Chức năng-khởi tạo được cho phép bên trong và bên ngoài các chức năng. Bên trong các hàm đó, cũng giống như các biến, các hàm lồng nhau là cục bộ và do đó không thể lấy được từ phạm vi bên ngoài.

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

foothao tác barbên trong chính nó. barkhông thể chạm vào từ phạm vi bên ngoài trừ khi nó được xác định trong phạm vi bên ngoài.

Vì vậy, điều này sẽ không hoạt động:

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

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

4

Khi bạn khai báo một hàm trong một hàm, các hàm bên trong chỉ khả dụng trong phạm vi mà chúng được khai báo, hoặc trong trường hợp của bạn, pad2chỉ có thể được gọi trong dmyphạm vi.

Tất cả các biến hiện có trong dmyđều hiển thị trong pad2, nhưng nó không xảy ra theo chiều ngược lại: D


2

Hoàn toàn bình thường trong Javascript (và nhiều ngôn ngữ) có các hàm bên trong các hàm.

Hãy dành thời gian để học ngôn ngữ, đừng sử dụng nó trên cơ sở nó giống với những gì bạn đã biết. Tôi khuyên bạn nên xem loạt bài thuyết trình YUI của Douglas Crockford về Javascript, đặc biệt tập trung vào Act III: Function the Ultimate (liên kết đến tải xuống video, trang trình bày và bản ghi)


0

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

Sẽ ném ra một lỗi. Vì barđược xác định bên trong foo, barsẽ chỉ có thể truy cập bên trong foo.
Để sử dụng, barbạn cần phải chạy nó bên trong foo.

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.