Cấu trúc (function () {}) () trong JavaScript là gì?


790

Tôi đã từng biết điều này có nghĩa là gì, nhưng giờ tôi đang vật lộn ...

Đây có phải là về cơ bản nói document.onload?

(function () {

})();

20
btw, mặc dù bạn sẽ thấy mọi người gọi chức năng này là 'tự gọi mình', điều đó rõ ràng không đúng. Thuật ngữ iife có lợi thế của sự chính xác.
AakashM

6
Điều này đưa ra một lời giải thích tuyệt vời về cấu trúc này. Đó cũng là nơi thuật ngữ "IIFE" bắt nguồn. benalman.com/news/2010/11/ từ
jeremysawgie


2
Đối với việc đặt tên của cấu trúc này, cũng có một cái nhìn ở đây . Đọc về mục đích của cấu trúc này , và một lời giải thích kỹ thuật (cũng ở đây ). Đối với cú pháp, hãy xem tại sao dấu ngoặc đơn là cần thiếtchúng nên đi đâu .
Bergi

Câu trả lời:


854

Đó là một biểu thức chức năng được gọi ngay lập tức , hoặc IIFE viết tắt là . Nó thực thi ngay sau khi nó được tạo.

Nó không có gì để làm với bất kỳ xử lý sự kiện cho bất kỳ sự kiện (chẳng hạn như document.onload).
Hãy xem xét phần trong cặp dấu ngoặc đơn đầu tiên: .... đó là biểu thức hàm thông thường. Sau đó nhìn vào cặp cuối cùng , điều này thường được thêm vào một biểu thức để gọi hàm; trong trường hợp này, biểu hiện trước của chúng tôi.(function(){})();(function(){})();

Mẫu này thường được sử dụng khi cố gắng tránh gây ô nhiễm không gian tên toàn cầu, bởi vì tất cả các biến được sử dụng bên trong IIFE (giống như trong bất kỳ chức năng bình thường nào khác ) không thể nhìn thấy ngoài phạm vi của nó.
Đây là lý do tại sao, có thể, bạn đã nhầm lẫn công trình này với một trình xử lý sự kiện window.onload, bởi vì nó thường được sử dụng như sau:

(function(){
  // all your code here
  var foo = function() {};
  window.onload = foo;
  // ...
})();
// foo is unreachable here (it’s undefined)

Sửa chữa được đề xuất bởi Guffa :

Hàm được thực thi ngay sau khi được tạo, không phải sau khi được phân tích cú pháp. Toàn bộ khối tập lệnh được phân tích cú pháp trước khi bất kỳ mã nào trong đó được thực thi. Ngoài ra, mã phân tích không tự động có nghĩa là nó được thực thi, ví dụ như IIFE nằm trong một hàm thì nó sẽ không được thực thi cho đến khi hàm được gọi.

Cập nhật Vì đây là một chủ đề khá phổ biến, điều đáng nói là IIFE cũng có thể được viết bằng chức năng mũi tên của ES6 (như Gajus đã chỉ ra trong một bình luận ):

((foo) => {
 // do something with foo here foo
})('foo value')

@ gion_13 sự khác biệt giữa giai đoạn tạo và giai đoạn phân tích là gì?
akantoword

1
@jlei theo cách tôi thấy, vòng đời của chương trình js bao gồm các giai đoạn sau: phân tích cú pháp, tạo / biên dịch, thực thi. Mặc dù việc triển khai thực tế (và đặt tên :))) có thể khác nhau từ trình duyệt này đến trình duyệt khác, chúng tôi có thể xác định các giai đoạn này trong mã của mình bằng cách xem ra các lỗi phân tích cú pháp, cẩu và chạy thời gian. Cá nhân tôi đã không tìm thấy nhiều tài nguyên về điều này bởi vì nó quá thấp và đó không phải là thứ mà lập trình viên có thể kiểm soát. Bạn có thể tìm thấy một số loại giải thích trong bài viết SO này: stackoverflow.com/a/34562772/491075
gion_13

@sam Firat của tất cả, có khai báo varianle và từ khóa mới. Điều này có nghĩa là trong ví dụ của bạn, bạn đang khởi tạo một vật cản mới được xác định bởi hàm tạo của nó (biểu thức hàm ẩn danh) và nó được gọi thông qua toán tử mới, không phải bằng cách gọi phân biệt như trong ví dụ IIFE. Chắc chắn rằng chức năng này hoạt động như một bao đóng cho nội dung của nó nhưng cho đến nay là một trường hợp sử dụng khác.
gion_13

Làm thế nào điều này gây ô nhiễm không gian tên toàn cầu? foo không có sẵn ngoài chức năng. function(){ var foo = '5'; }
Pankaj

1
@Pankaj - Được thực hiện bởi chính nó, đó thậm chí không phải là mã hợp lệ về mặt cú pháp (nó là một biểu thức hàm nhưng không phải trong ngữ cảnh biểu thức nên được coi là một lỗi cú pháp).
Quentin

109

Nó chỉ là một chức năng ẩn danh được thực thi ngay sau khi nó được tạo.

Giống như bạn đã gán nó cho một biến và sử dụng nó ngay sau đó, chỉ khi không có biến:

var f = function () {
};
f();

Trong jQuery có một cấu trúc tương tự mà bạn có thể nghĩ đến:

$(function(){
});

Đó là hình thức ràng buộc ngắn của readysự kiện:

$(document).ready(function(){
});

Nhưng hai cấu trúc trên không phải là IIFE s.


83
Hai IIFE cuối cùng không thực sự là IIFE, vì chúng được gọi khi DOM sẵn sàng và không ngay lập tức
svvac

15
@swordofpain: Vâng, đúng vậy, họ không phải là IIFE.
Guffa

@swordofpain xem xét đoạn trích thứ hai; sẽ có bất kỳ giá trị nào trong add () vào cuối hàm bằng cách biến nó thành IIFE không?
timebandit

Là dấu chấm phẩy ở cuối cần thiết?
FrenkyB

@FrenkyB Không cần thiết, không, nhưng được khuyến khích (dấu chấm phẩy thường không thực sự cần thiết trong Javascript, nhưng đó là cách thực hành tốt). Mỗi trong số đó là các câu lệnh xảy ra bao gồm các hàm ẩn danh, thay vì là các khai báo hàm.
Ledivin

52

Một biểu thức hàm được gọi ngay lập tức (IIFE) ngay lập tức gọi một hàm. Điều này chỉ có nghĩa là hàm được thực thi ngay sau khi hoàn thành định nghĩa.

Ba từ phổ biến hơn:

// Crockford's preference - parens on the inside
(function() {
  console.log('Welcome to the Internet. Please follow me.');
}());

//The OPs example, parentheses on the outside
(function() {
  console.log('Welcome to the Internet. Please follow me.');
})();

//Using the exclamation mark operator
//https://stackoverflow.com/a/5654929/1175496
!function() {
  console.log('Welcome to the Internet. Please follow me.');
}();

Nếu không có yêu cầu đặc biệt cho giá trị trả về của nó, thì chúng ta có thể viết:

!function(){}();  // => true
~function(){}(); // => -1
+function(){}(); // => NaN
-function(){}();  // => NaN

Ngoài ra, nó có thể là:

~(function(){})();
void function(){}();
true && function(){ /* code */ }();
15.0, function(){ /* code */ }();

Bạn thậm chí có thể viết:

new function(){ /* code */ }
31.new function(){ /* code */ }() //If no parameters, the last () is not required

4
31.newcú cuối cùng 'là cú pháp không hợp lệ
cat

9
Tại sao có nhiều cách để viết cùng một thứ? !! > _ <Tôi không thích ngôn ngữ này
Awesome_girl

6
Người chiến thắng là;(function(){}());
Roko C. Buljan

Giải thích về sở thích của Crockford rất hữu ích - giải thích sự khác biệt mà tôi đã thấy trong tự nhiên, ví dụ, ý chính của quán rượu nhỏ jQuery chuyển từ phiên bản này sang phiên bản khác (bạn có thể thấy sự thay đổi ở cuối tệp) và tôi không thể t tìm hiểu tại sao.
icc97

1
@Awgie_girl: Không phải là có nhiều cách để viết cùng một thứ; đó là JS có một hệ thống loại lỏng lẻo với các toán tử có thể hoạt động trên bất kỳ loại giá trị nào. Bạn có thể làm 1 - 1và bạn có thể dễ dàng làm như vậy true - function(){}. Đó chỉ là một điều (một toán tử trừ infix) nhưng với các toán hạng khác nhau, thậm chí vô nghĩa.

31

Nó khai báo một hàm ẩn danh, sau đó gọi nó:

(function (local_arg) {
   // anonymous function
   console.log(local_arg);
})(arg);

Tôi đoán "đối số" là các biến ngoài được tham chiếu là "arg" sẽ được sử dụng trong ngữ cảnh cục bộ trong hàm?
Dalibor

@Dalibor argumentsđặc biệt ; Tôi đoán là người trả lời vừa lật nơi tên đi
mèo

29

Đó là nói thực thi ngay lập tức.

vì vậy nếu tôi làm:

var val = (function(){
     var a = 0;  // in the scope of this function
     return function(x){
         a += x;
         return a;
     };
})();

alert(val(10)); //10
alert(val(11)); //21

Fiddle: http://jsfiddle.net/manoder/LqvpQ/


Ví dụ thứ hai:

var val = (function(){
     return 13 + 5;
})();

alert(val); //18

1
Tôi không hiểu điều đó chứng tỏ điều gì tự nó?
Thoát khỏi

1
@Exitos vì nó trả về chức năng đó. Ill đưa ra một ví dụ thứ hai.
Naftali aka Neal

rất dễ hiểu +1
Adiii

24

Cấu trúc đó được gọi là Biểu thức hàm được gọi ngay lập tức (IIFE) có nghĩa là nó được thực thi ngay lập tức. Hãy nghĩ về nó như là một chức năng được gọi tự động khi trình thông dịch đạt đến chức năng đó.

Trường hợp sử dụng phổ biến nhất:

Một trong những trường hợp sử dụng phổ biến nhất của nó là giới hạn phạm vi của một biến được thực hiện thông qua var. Các biến được tạo thông quavar có phạm vi giới hạn trong một hàm nên cấu trúc này (là trình bao bọc hàm xung quanh mã nhất định) sẽ đảm bảo rằng phạm vi biến của bạn không bị rò rỉ ra khỏi hàm đó.

Trong ví dụ sau, countsẽ không có sẵn bên ngoài hàm được gọi ngay lập tức tức là phạm vi countsẽ không bị rò rỉ ra khỏi hàm. Bạn sẽ nhận được một ReferenceError, nếu bạn cố gắng truy cập nó bên ngoài chức năng được gọi ngay lập tức.

(function () { 
    var count = 10;
})();
console.log(count);  // Reference Error: count is not defined

Thay thế ES6 (Khuyến nghị)

Trong ES6, bây giờ chúng ta có thể có các biến được tạo thông qua letconst. Cả hai đều có phạm vi khối (không giống như varphạm vi chức năng).

Do đó, thay vì sử dụng cấu trúc IIFE phức tạp đó cho trường hợp sử dụng mà tôi đã đề cập ở trên, giờ đây bạn có thể viết mã đơn giản hơn nhiều để đảm bảo rằng phạm vi của một biến không bị rò rỉ ra khỏi khối mong muốn của bạn.

{ 
    let count = 10;
}
console.log(count);  // ReferenceError: count is not defined

Trong ví dụ này, chúng tôi đã sử dụng letđể xác định countbiến làm cho countgiới hạn trong khối mã, chúng tôi đã tạo bằng dấu ngoặc nhọn {...}.

Tôi gọi nó là một nhà tù xoăn xoăn.


10
Tôi thích cách đặt tên của nhà tù xoăn . Có lẽ nó sẽ dính :)
gion_13

15
(function () {
})();

Điều này được gọi là IIFE (Biểu thức chức năng được gọi ngay lập tức). Một trong những mẫu thiết kế JavaScript nổi tiếng, đó là trái tim và linh hồn của mẫu Mô-đun hiện đại. Như tên cho thấy nó thực thi ngay sau khi nó được tạo. Mẫu này tạo ra một phạm vi thực thi riêng biệt hoặc riêng tư.

JavaScript trước ECMAScript 6 đã sử dụng phạm vi từ vựng, vì vậy IIFE đã được sử dụng để mô phỏng phạm vi khối. (Với phạm vi khối ECMAScript 6 là có thể với việc giới thiệu các từ khóa letconst.) Tham khảo cho vấn đề với phạm vi từ vựng

Mô phỏng phạm vi khối với IIFE

Lợi ích của việc sử dụng hiệu suất IIFE là khả năng để vượt qua thường được sử dụng đối tượng toàn cầu như window, documentvv như một cuộc tranh cãi bằng cách giảm tra cứu phạm vi. (Hãy nhớ JavaScript tìm các thuộc tính trong phạm vi cục bộ và tăng chuỗi cho đến phạm vi toàn cầu). Vì vậy, truy cập các đối tượng toàn cầu trong phạm vi địa phương làm giảm thời gian tra cứu như dưới đây.

(function (globalObj) {
//Access the globalObj
})(window);

Cảm ơn bạn đã cung cấp ý chính để hiểu dấu ngoặc đơn thứ hai trong IIFE. Cũng để làm rõ lợi ích thời gian tra cứu của biến toàn cầu bằng cách định nghĩa chúng trong định nghĩa
Arsal

11

Không, cấu trúc này chỉ tạo ra một phạm vi để đặt tên. Nếu bạn phá vỡ nó trong các phần bạn có thể thấy rằng bạn có một bên ngoài

(...)();

Đó là một lời gọi hàm. Trong ngoặc đơn bạn có:

function() {}

Đó là một chức năng ẩn danh. Mọi thứ được khai báo với var bên trong cấu trúc sẽ chỉ hiển thị bên trong cùng một cấu trúc và sẽ không gây ô nhiễm không gian tên toàn cục.


11

Đây là một biểu thức chức năng được gọi ngay lập tức trong Javascript:

Để hiểu IIFE trong JS, hãy chia nhỏ nó:

  1. Biểu thức : Thứ gì đó trả về giá trị
    Ví dụ: Hãy thử theo dõi trong bảng điều khiển chrome. Đây là các biểu thức trong JS.
a = 10 
output = 10 
(1+3) 
output = 4
  1. Biểu thức hàm :
    Ví dụ:
// Function Expression 
var greet = function(name){
   return 'Namaste' + ' ' + name;
}

greet('Santosh');

Cách biểu thức chức năng hoạt động:
- Khi công cụ JS chạy lần đầu tiên (Bối cảnh thực thi - Tạo pha), chức năng này (ở phía bên phải của = ở trên) không được thực thi hoặc lưu trữ trong bộ nhớ. Biến 'lời chào' được gán bởi giá trị 'không xác định' bởi công cụ JS.
- Trong khi thực hiện (Bối cảnh thực thi - Giai đoạn thực thi), đối tượng funtion được tạo khi đang bay ( chưa được thực thi ), được gán cho biến 'hello' và nó có thể được gọi bằng 'hello (' somename ')'.

3. Biểu hiện Funtion ngay lập tức được viện dẫn:

Thí dụ:

// IIFE
var greeting = function(name) {
    return 'Namaste' + ' ' + name;
}('Santosh')

console.log(greeting)  // Namaste Santosh. 

Cách IIFE hoạt động :
- Lưu ý '()' ngay sau khi khai báo hàm. Mọi đối tượng funtion đều có thuộc tính 'CODE' được gắn vào nó có thể gọi được. Và chúng ta có thể gọi nó (hoặc gọi nó) bằng cách sử dụng dấu ngoặc '()'.
- Vì vậy, ở đây, trong quá trình thực thi (Bối cảnh thực thi - Giai đoạn thực thi), đối tượng hàm được tạo và được thực thi cùng lúc - Vì vậy, bây giờ, biến chào, thay vì có đối tượng funtion, có giá trị trả về (một chuỗi)

Usecase điển hình của IIFE trong JS:

Mẫu IIFE sau đây được sử dụng khá phổ biến.

// IIFE 
// Spelling of Function was not correct , result into error
(function (name) {
   var greeting = 'Namaste';
   console.log(greeting + ' ' + name);
})('Santosh');
  • chúng tôi đang làm hai việc ở đây a) Gói biểu thức chức năng của chúng ta bên trong dấu ngoặc (). Điều này nói với trình phân tích cú pháp, bất cứ thứ gì được đặt bên trong () là một biểu thức (biểu thức hàm trong trường hợp này) và là một mã hợp lệ.
    b) Chúng tôi đang gọi chức năng này cùng lúc bằng cách sử dụng () ở cuối của nó.

Vì vậy, chức năng này được tạo và thực hiện cùng một lúc (IIFE).

Usecase quan trọng cho IIFE:

IIFE giữ mã của chúng tôi an toàn.
- IIFE, là một hàm, có bối cảnh thực thi riêng, có nghĩa là tất cả các biến được tạo bên trong nó là cục bộ của hàm này và không được chia sẻ với bối cảnh thực thi toàn cục.

Giả sử tôi có một tệp JS khác (test1.js) được sử dụng trong applicaiton của tôi cùng với iife.js (xem bên dưới).

// test1.js

var greeting = 'Hello';

// iife.js
// Spelling of Function was not correct , result into error
(function (name) { 
   var greeting = 'Namaste';
   console.log(greeting + ' ' + name);
})('Santosh');

console.log(greeting)   // No collision happens here. It prints 'Hello'.

Vì vậy, IIFE giúp chúng tôi viết mã an toàn khi chúng tôi không va chạm với các đối tượng toàn cầu.


Nếu chúng ta tạo các hàm bên trong IIFE, làm thế nào chúng ta có thể truy cập chúng trong một số tệp js hoặc jsx khác, tức là trong thành phần phản ứng.
đá đá

Mặc dù chúng tôi không sử dụng IIFE, biến lời chào sẽ không va chạm vào biến chào toàn cầu. Vậy lợi thế ở đó là gì?
Willy David Jr

6

Đó là một chức năng ẩn danh tự gọi .

Kiểm tra giải thích của W3Schools về chức năng tự gọi .

Các biểu thức chức năng có thể được thực hiện "tự gọi".

Một biểu thức tự gọi được gọi tự động (bắt đầu) mà không được gọi.

Các biểu thức hàm sẽ thực thi tự động nếu biểu thức được theo sau bởi ().

Bạn không thể tự gọi một khai báo hàm.


3
(function named(){console.log("Hello");}());<- chức năng tự thực hiện có tên
bryc

@bryc tại sao bạn sẽ đặt tên cho một chức năng không cần tên.
RicardoGonzales

2
Tôi đoán là đệ quy @RicardoGonzales
bryc

5

Đây là chức năng ẩn danh tự gọi. Nó được thực thi trong khi nó được xác định. Có nghĩa là chức năng này được định nghĩa và gọi chính nó ngay sau định nghĩa.

Và giải thích của cú pháp là: Hàm trong ()ngoặc đơn đầu tiên là hàm không có tên và bằng ();dấu ngoặc đơn tiếp theo, bạn có thể hiểu rằng nó được gọi tại thời điểm được định nghĩa. Và bạn có thể vượt qua bất kỳ đối số nào trong ()ngoặc đơn thứ hai này sẽ được lấy trong hàm nằm trong ngoặc đơn đầu tiên. Xem ví dụ này:

(function(obj){
    // Do something with this obj
})(object);

Ở đây, 'đối tượng' bạn đang vượt qua sẽ có thể truy cập được trong hàm bằng 'obj', khi bạn đang lấy nó trong chữ ký hàm.


2
Câu hỏi này đã có câu trả lời được chấp nhận và câu trả lời của bạn không thêm bất cứ điều gì chưa được bao phủ bởi câu trả lời được chấp nhận. Do đó, hoàn toàn không cần phải viết câu trả lời này.
Aadit M Shah

3
Tôi thích đọc nhiều câu trả lời, đôi khi cụm từ của cái này hay cái kia tạo nên sự khác biệt.

Tôi nghĩ rằng nó được thêm vào bởi vì nó cho tôi biết bộ dấu ngoặc đơn thứ hai đó dùng để làm gì. Ít nhất nó đã rõ ràng hơn ở đây mà tôi thấy.
johnny

Fav ans của tôi. Cả hai đầu của IIFE mẫu đều có các tham số và ánh xạ giữa hai đầu được làm rõ.
Stephen W. Wright

4

Bắt đầu ở đây:

var b = 'bee';
console.log(b);  // global

Đặt nó trong một chức năng và nó không còn toàn cầu - mục tiêu chính của bạn.

function a() {
  var b = 'bee';
  console.log(b);
}
a();
console.log(b);  // ReferenceError: b is not defined -- *as desired*

Gọi chức năng ngay lập tức - rất tiếc:

function a() {
  var b = 'bee';
  console.log(b);
}();             // SyntaxError: Expected () to start arrow function, but got ';' instead of '=>'

Sử dụng dấu ngoặc đơn để tránh lỗi cú pháp:

(function a() {
  var b = 'bee';
  console.log(b);
})(); // OK now

Bạn có thể bỏ tên hàm:

(function () {    // no name required
  var b = 'bee';
  console.log(b);
})();

Nó không cần phải phức tạp hơn thế.


2
Lỗi cú pháp đang nói về các chức năng mũi tên. Theo tôi hiểu, đây là một tính năng mới của js và nó đã không tồn tại vài năm trước, nhưng IIFE đã làm được. Vì vậy, dấu ngoặc đơn có thể được sử dụng ban đầu để tránh lỗi cú pháp, nhưng khác nhau?
JCarlosR

Bạn có thể vui lòng trả lời câu hỏi @JCarlos không? Vì ông hoàn toàn chỉ ra rằng IIFE đã xuất hiện rất nhiều trước chức năng mũi tên, nó sẽ giúp hiểu lý do tại sao việc bọc lại là bắt buộc.
Script47

@ Script47 Tôi không có câu trả lời cho câu hỏi của JCarlos trong bình luận. Bạn có thể hình thành một câu hỏi mới và đăng nó, và tôi chắc chắn bạn sẽ nhận được một số câu trả lời hay.
Jim Flood

@JCarlos khi tôi thực thi lỗi gây ra lỗi, tôi thực sự nhận được Uncaught SyntaxError: Unexpected token )chứ không phải bất kỳ đề cập đến chức năng mũi tên. Bạn có thể chia sẻ một câu đố với nó ném lỗi chức năng mũi tên?
Script47

2

Chức năng ẩn danh tự thực hiện. Nó được thực hiện ngay khi nó được tạo ra.

Một ví dụ ngắn và giả trong đó hữu ích là:

function prepareList(el){
  var list = (function(){
    var l = []; 
    for(var i = 0; i < 9; i++){
     l.push(i);
    }
    return l;
  })();

  return function (el){
    for(var i = 0, l = list.length; i < l; i++){
      if(list[i] == el) return list[i];
    }
    return null;
  }; 
} 

var search = prepareList();
search(2);
search(3);

Vì vậy, thay vì tạo danh sách mỗi lần, bạn chỉ tạo một danh sách (ít chi phí hơn).


1
Như đã viết, tìm kiếm của bạn xây dựng lại danh sách trên mỗi lần gọi. Để tránh điều đó, bạn cần (1) tạo danh sách và (2) trả lại chức năng tìm kiếm dưới dạng đóng có quyền truy cập vào danh sách bạn vừa tạo. Điều này bạn có thể dễ dàng sử dụng mẫu tự gọi ẩn danh. Xem jsfiddle.net/BV4bT .
George

bạn có thể giải thích ... ít chi phí hơn không .. tôi không hiểu phần này
HIRA THAKUR

2
Trên cao có nghĩa là bất kỳ công việc được thực hiện mà không cần thiết. Việc điền một mảng trên mỗi lần gọi hàm là không cần thiết, đó là lý do tại sao một mảng trong ví dụ được tự thực hiện. chức năng ẩn danh lần đầu tiên. Tuy nhiên, có vẻ như tôi đã phạm sai lầm trong câu trả lời của riêng mình, hãy xem liên kết trong nhận xét của George để biết ví dụ thích hợp.
usoban

2

Các chức năng tự thực thi thường được sử dụng để đóng gói bối cảnh và tránh các thông đồng tên. Bất kỳ biến nào bạn xác định bên trong (function () {..}) () không phải là toàn cục.

Mật mã

var same_name = 1;

var myVar = (function() {
    var same_name = 2;
    console.log(same_name);
})();

console.log(same_name);

tạo đầu ra này:

2
1

Bằng cách sử dụng cú pháp này, bạn tránh va chạm với các biến toàn cục được khai báo ở nơi khác trong mã JavaScript của bạn.


1
Đúng, đầu ra sẽ là 2 và sau đó là 1 vì myVar sẽ được chạy trước
Dalibor

1
Giải thích của bạn không tốt trong việc giải thích phạm vi chức năng nhưng không giải thích được tại sao nó được thực thi ngay lập tức. Việc gán nó cho một biến là tự đánh bại và cũng có thể dự định rằng nó có thể được thực thi nhiều lần. var same_name = 1; var myVar = function() { var same_name = 2; console.log(same_name); }; myVar(); console.log(same_name); Sẽ có kết quả tương tự.
domenicr

2

Nó được gọi là IIFE - Biểu thức hàm được gọi ngay lập tức. Dưới đây là một ví dụ để hiển thị cú pháp và cách sử dụng. Nó được sử dụng để phạm vi sử dụng các biến chỉ cho đến hàm và không vượt quá.

(function () {
  function Question(q,a,c) {
    this.q = q;
    this.a = a;
    this.c = c;
  }

  Question.prototype.displayQuestion = function() {
    console.log(this.q);
    for (var i = 0; i < this.a.length; i++) {
      console.log(i+": "+this.a[i]);
    }
  }

  Question.prototype.checkAnswer = function(ans) {
    if (ans===this.c) {
      console.log("correct");
    } else {
      console.log("incorrect");
    }
  }

  var q1 = new Question('Is Javascript the coolest?', ['yes', 'no'], 0);
  var q2 = new Question('Is python better than Javascript?', ['yes', 'no', 'both are same'], 2);
  var q3 = new Question('Is Javascript the worst?', ['yes', 'no'], 1);

  var questions = [q1, q2, q3];

  var n = Math.floor(Math.random() * questions.length)

  var answer = parseInt(prompt(questions[n].displayQuestion()));
  questions[n].checkAnswer(answer);
})();

1

IIFE (Biểu thức hàm được gọi ngay lập tức) là một hàm thực thi ngay khi tập lệnh tải và biến mất.

Hãy xem xét hàm bên dưới được viết trong một tệp có tên iife.js

(function(){
       console.log("Hello Stackoverflow!");
   })();

Mã này ở trên sẽ thực thi ngay khi bạn tải iife.js và sẽ in ' Xin chào Stackoverflow! 'trên bảng điều khiển của công cụ dành cho nhà phát triển.

Để được giải thích chi tiết, hãy xem Biểu thức chức năng được gọi ngay lập tức (IIFE)


1

Một trường hợp sử dụng nữa là ghi nhớ trong đó một đối tượng bộ đệm không phải là toàn cục:

var calculate = (function() {
  var cache = {};
  return function(a) {

    if (cache[a]) {
      return cache[a];
    } else {
      // Calculate heavy operation
      cache[a] = heavyOperation(a);
      return cache[a];
    }
  }
})();

0

Một biểu thức hàm được gọi ngay lập tức (IIFE) là một hàm được thực thi ngay khi nó được tạo. Nó không có kết nối với bất kỳ sự kiện hoặc thực thi không đồng bộ. Bạn có thể định nghĩa IIFE như hình dưới đây:

(function() {
     // all your code here
     // ...
})();

Cặp dấu ngoặc đơn đầu tiên () {...} chuyển đổi mã bên trong dấu ngoặc đơn thành một biểu thức. Cặp dấu ngoặc đơn thứ hai gọi hàm kết quả từ biểu thức.

An IIFEcũng có thể được mô tả như là một hàm ẩn danh tự gọi. Cách sử dụng phổ biến nhất của nó là giới hạn phạm vi của một biến được thực hiện thông qua var hoặc đóng gói bối cảnh để tránh xung đột tên.


0

Lý do các hàm ẩn danh tự kích hoạt được sử dụng là chúng không bao giờ được gọi bởi mã khác vì chúng "thiết lập" mã mà IS có nghĩa là được gọi (cùng với việc đưa ra phạm vi cho các hàm và biến).

Nói cách khác, chúng giống như các chương trình "tạo lớp", ở đầu chương trình. Sau khi chúng được khởi tạo (tự động), các hàm duy nhất có sẵn là các hàm được trả về bởi hàm ẩn danh. Tuy nhiên, tất cả các hàm khác ' Các hàm 'ẩn' vẫn còn đó, cùng với bất kỳ trạng thái nào (các biến được đặt trong quá trình tạo phạm vi).

Rất tuyệt.


0

Các mã sau đây:

(function () {

})();

được gọi là biểu thức hàm được gọi ngay lập tức (IIFE).

Nó được gọi là biểu thức hàm vì ( yourcode )toán tử trong Javascript buộc nó thành biểu thức. Sự khác biệt giữa biểu thức hàmkhai báo hàm là như sau:

// declaration:
function declaredFunction () {}

// expressions:

// storing function into variable
const expressedFunction = function () {}

// Using () operator, which transforms the function into an expression
(function () {})

Một biểu thức chỉ đơn giản là một bó mã có thể được ước tính thành một giá trị duy nhất . Trong trường hợp các biểu thức trong ví dụ trên, giá trị này là một đối tượng hàm duy nhất .

Sau khi chúng ta có một biểu thức ước lượng cho một đối tượng hàm, sau đó chúng ta có thể gọi ngay đối tượng hàm với ()toán tử. Ví dụ:

(function() {

  const foo = 10;        // all variables inside here are scoped to the function block
  console.log(foo);

})();

console.log(foo);  // referenceError foo is scoped to the IIFE

Tại sao điều này hữu ích?

Khi chúng tôi đang xử lý một cơ sở mã lớn và / hoặc khi chúng tôi đang nhập các thư viện khác nhau, cơ hội đặt tên xung đột sẽ tăng lên. Khi chúng tôi viết một số phần nhất định của mã có liên quan (và do đó đang sử dụng cùng một biến) trong IIFE, tất cả các biến và tên hàm được đặt trong phạm vi dấu ngoặc của IIFE . Điều này làm giảm cơ hội đặt tên xung đột và cho phép bạn đặt tên cho chúng bất cẩn hơn (ví dụ: bạn không phải đặt tiền tố cho chúng).


0

Trong cú pháp ES6 (đăng bài cho chính tôi, khi tôi tiếp tục hạ cánh trên trang này để tìm ví dụ nhanh):

// simple
const simpleNumber = (() => {
  return true ? 1 : 2
})()

// with param
const isPositiveNumber = ((number) => {
  return number > 0 ? true : false
})(4)

0

Hàm này được gọi là hàm tự gọi. Hàm tự gọi (còn gọi là tự thực thi) là một hàm không tên (ẩn danh) được gọi (Gọi) ngay sau định nghĩa của nó.Đọc thêm tại đây

Những chức năng này làm là khi hàm được xác định, Hàm được gọi ngay lập tức, giúp tiết kiệm thời gian và các dòng mã bổ sung (so với việc gọi nó trên một dòng riêng biệt).

Đây là một ví dụ:

(function() {
    var x = 5 + 4;
    console.log(x);
})();


0

Đây là một lời giải thích sâu hơn về lý do tại sao bạn sẽ sử dụng điều này:

"Lý do chính để sử dụng IIFE là để có được quyền riêng tư dữ liệu. Bởi vì var var của JavaScript biến các hàm chứa của chúng, bất kỳ biến nào được khai báo trong IIFE đều không thể được truy cập bởi thế giới bên ngoài."

http://adripofjavascript.com/blog/drips/an-intributiontion-to-iffes-immediately-invoking-feft-expressions.html


0

Nó là một biểu thức hàm, nó là viết tắt của Biểu thức hàm được gọi ngay lập tức (IIFE). IIFE đơn giản là một chức năng được thực thi ngay sau khi nó được tạo. Vì vậy, do chức năng phải đợi cho đến khi nó được gọi để thực thi, IIFE được thực thi ngay lập tức. Hãy xây dựng IIFE bằng ví dụ. Giả sử chúng ta có một hàm add có hai số nguyên là arg và trả về tổng cho phép biến hàm add thành IIFE,

Bước 1: Xác định chức năng

function add (a, b){
    return a+b;
}
add(5,5);

Bước2: Gọi hàm bằng cách gói toàn bộ khai báo dấu chấm vào dấu ngoặc đơn

(function add (a, b){
    return a+b;
})
//add(5,5);

Bước 3: Để gọi hàm ngay lập tức, chỉ cần xóa văn bản 'thêm' khỏi cuộc gọi.

(function add (a, b){
    return a+b;
})(5,5);

Lý do chính để sử dụng IFFE là để duy trì phạm vi riêng tư trong chức năng của bạn. Bên trong mã javascript của bạn, bạn muốn đảm bảo rằng, bạn không ghi đè bất kỳ biến toàn cục nào. Đôi khi bạn có thể vô tình xác định một biến ghi đè lên một biến toàn cục. Hãy thử làm ví dụ. giả sử chúng ta có một tệp html có tên iffe.html và các mã bên trong thẻ body là-

<body>
    <div id = 'demo'></div>
    <script>
        document.getElementById("demo").innerHTML = "Hello JavaScript!";
    </script> 
</body>

Chà, đoạn mã trên sẽ thực thi với bất kỳ câu hỏi nào, bây giờ giả sử bạn tuyên bố một biến có tên là tài liệu vô tình hoặc cố ý.

<body>
    <div id = 'demo'></div>
    <script>
        document.getElementById("demo").innerHTML = "Hello JavaScript!";
        const document = "hi there";
        console.log(document);
    </script> 
</body>

bạn sẽ kết thúc bằng SyntaxError : khai báo lại tài liệu thuộc tính toàn cầu không thể cấu hình.

Nhưng nếu mong muốn của bạn là từ chối một tài liệu tên biến, bạn có thể thực hiện bằng cách sử dụng IFFE.

<body>
    <div id = 'demo'></div>
    <script>
        (function(){
            const document = "hi there";
            this.document.getElementById("demo").innerHTML = "Hello JavaScript!";
            console.log(document);
        })();
        document.getElementById("demo").innerHTML = "Hello JavaScript!";
    </script> 
</body>

Đầu ra:

nhập mô tả hình ảnh ở đây

Hãy thử một ví dụ khác, giả sử chúng ta có một đối tượng máy tính như dưới đây-

<body>
    <script>
        var calculator = {
            add:function(a,b){
                return a+b;
            },
            mul:function(a,b){
                return a*b;
            }
        }
        console.log(calculator.add(5,10));
    </script> 
</body>

Chà, nó hoạt động như một bùa mê, điều gì sẽ xảy ra nếu chúng ta vô tình gán lại giá trị của đối tượng máy tính.

<body>
    <script>
        var calculator = {
            add:function(a,b){
                return a+b;
            },
            mul:function(a,b){
                return a*b;
            }
        }
        console.log(calculator.add(5,10));
        calculator = "scientific calculator";
        console.log(calculator.mul(5,5));
    </script> 
</body>

vâng, bạn sẽ kết thúc với TypeError: Calculator.mul không phải là một hàm iffe.html

Nhưng với sự giúp đỡ của IFFE, chúng ta có thể tạo một phạm vi riêng tư nơi chúng ta có thể tạo một máy tính tên biến khác và sử dụng nó;

<body>
    <script>
        var calculator = {
            add:function(a,b){
                return a+b;
            },
            mul:function(a,b){
                return a*b;
            }
        }
        var cal = (function(){
            var calculator = {
                sub:function(a,b){
                    return a-b;
                },
                div:function(a,b){
                    return a/b;
                }
            }
            console.log(this.calculator.mul(5,10));
            console.log(calculator.sub(10,5));
            return calculator;
        })();
        console.log(calculator.add(5,10));
        console.log(cal.div(10,5));
    </script> 
</body>

Đầu ra: nhập mô tả hình ảnh ở đây


-1

Tôi nghĩ rằng 2 bộ dấu ngoặc làm cho nó hơi khó hiểu nhưng tôi đã thấy một cách sử dụng khác trong ví dụ về Google, họ đã sử dụng một cái gì đó tương tự, tôi hy vọng điều này sẽ giúp bạn hiểu rõ hơn:

var app = window.app || (window.app = {});
console.log(app);
console.log(window.app);

Vì vậy, nếu windows.appkhông được xác định, thì window.app = {}ngay lập tức được thực thi, do đó window.appđược gán {}trong quá trình đánh giá điều kiện, do đó, kết quả là cả hai appwindow.appbây giờ trở thành {}, vì vậy đầu ra của giao diện điều khiển là:

Object {}
Object {}

-1

Thông thường, chúng ta không gọi hàm ngay sau khi chúng ta viết nó trong chương trình. Nói một cách cực kỳ đơn giản, khi bạn gọi một hàm ngay sau khi tạo, nó được gọi là IIFE - một cái tên lạ mắt.


-1

Thông thường, mã JavaScript có phạm vi toàn cầu trong ứng dụng. Khi chúng ta khai báo biến toàn cục trong đó, có một cơ hội sử dụng cùng một biến trùng lặp trong một số lĩnh vực phát triển khác cho một số mục đích khác. Do sự trùng lặp này có thể xảy ra một số lỗi. Vì vậy, chúng ta có thể tránh các biến toàn cục này bằng cách sử dụng ngay biểu thức hàm, biểu thức này là biểu thức tự thực thi. Khi chúng ta tạo mã của mình trong IIFE này biến toàn cục biểu thức sẽ giống như phạm vi cục bộ và biến cục bộ.

Hai cách chúng ta có thể tạo IIFE

(function () {
    "use strict";
    var app = angular.module("myModule", []);
}());

HOẶC LÀ

(function () {
    "use strict";
    var app = angular.module("myModule", []);
})();

Trong đoạn mã trên, ngay bây giờ , ứng dụng var var là một biến cục bộ.

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.