Trong javascript, khi nào bạn muốn sử dụng cái này:
(function(){
//Bunch of code...
})();
về điều này:
//Bunch of code...
Trong javascript, khi nào bạn muốn sử dụng cái này:
(function(){
//Bunch of code...
})();
về điều này:
//Bunch of code...
Câu trả lời:
Đó là tất cả về phạm vi biến. Các biến được khai báo trong hàm tự thực thi, theo mặc định, chỉ có sẵn để mã trong hàm tự thực thi. Điều này cho phép mã được viết mà không cần quan tâm đến cách các biến được đặt tên trong các khối mã JavaScript khác.
Ví dụ, như được đề cập trong một bình luận của Alexander :
(function() {
var foo = 3;
console.log(foo);
})();
console.log(foo);
Điều này sẽ đăng nhập đầu tiên 3
và sau đó ném một lỗi tiếp theo console.log
vì foo
không được xác định.
var
, như thế này : ...function(){ foo=3;}
? Nó sẽ đặt biến toàn cục, phải không?
function(){ var foo = 3; alert(foo); }; alert(foo);
Vì vậy, tôi vẫn không hiểu được
Đơn giản. Nhìn rất bình thường, nó gần như an ủi:
var userName = "Sean";
console.log(name());
function name() {
return userName;
}
Tuy nhiên, điều gì sẽ xảy ra nếu tôi bao gồm một thư viện javascript thực sự tiện dụng vào trang của mình để dịch các ký tự nâng cao thành các biểu diễn cấp cơ sở của chúng?
Đợi ... cái gì?
Ý tôi là, nếu ai đó gõ một ký tự có một số điểm nhấn vào nó, nhưng tôi chỉ muốn các ký tự 'tiếng Anh' AZ trong chương trình của tôi? Chà ... các ký tự 'é' của Tây Ban Nha và tiếng Pháp có thể được dịch thành các ký tự cơ bản của 'n' và 'e'.
Vì vậy, một người tốt bụng đã viết một trình chuyển đổi nhân vật toàn diện ra khỏi đó mà tôi có thể đưa vào trang web của mình ... Tôi bao gồm nó.
Một vấn đề: nó có một chức năng trong đó gọi là 'name' giống như chức năng của tôi.
Đây là những gì được gọi là va chạm. Chúng ta có hai hàm được khai báo trong cùng một phạm vi có cùng tên. Chúng tôi muốn tránh điều này.
Vì vậy, chúng ta cần phải phạm vi mã của chúng tôi bằng cách nào đó.
Cách duy nhất để phạm vi mã trong javascript là bọc nó trong một hàm:
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;
}
}
Điều đó có thể giải quyết vấn đề của chúng tôi. Tất cả mọi thứ bây giờ được bao quanh và chỉ có thể được truy cập từ trong niềng răng mở và đóng của chúng tôi.
Chúng tôi có một chức năng trong một chức năng ... thật kỳ lạ khi xem xét, nhưng hoàn toàn hợp pháp.
Chỉ có một vấn đề. Mã của chúng tôi không hoạt động. Biến userName của chúng tôi không bao giờ được lặp lại trong bảng điều khiển!
Chúng tôi có thể giải quyết vấn đề này bằng cách thêm một cuộc gọi vào chức năng của chúng tôi sau khối mã hiện tại của chúng tôi ...
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();
Hoặc trước!
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;
}
}
Một mối quan tâm thứ yếu: cơ hội mà tên 'chính' chưa được sử dụng là gì? ... rất, rất mỏng
Chúng tôi cần phạm vi THÊM. Và một số cách để tự động thực hiện hàm main () của chúng tôi.
Bây giờ chúng ta đến với các chức năng tự động thực hiện (hoặc tự thực thi, tự chạy, bất cứ điều gì).
((){})();
Cú pháp lúng túng như tội lỗi. Tuy nhiên, nó hoạt động.
Khi bạn bọc một định nghĩa hàm trong ngoặc đơn và bao gồm một danh sách tham số (một tập hợp hoặc dấu ngoặc đơn khác!), Nó hoạt động như một lệnh gọi hàm .
Vì vậy, hãy xem lại mã của chúng tôi, với một số cú pháp tự thực hiện:
(function main() {
var userName = "Sean";
console.log(name());
function name() {
return userName;
}
}
)();
Vì vậy, trong hầu hết các hướng dẫn bạn đọc, giờ đây bạn sẽ bị bắn phá với thuật ngữ 'tự thực hiện ẩn danh' hoặc một cái gì đó tương tự.
Sau nhiều năm phát triển nghề nghiệp, tôi mạnh mẽ kêu gọi bạn để đặt tên mỗi chức năng bạn viết cho mục đích gỡ lỗi.
Khi có sự cố xảy ra (và nó sẽ xảy ra), bạn sẽ kiểm tra backtrace trong trình duyệt của mình. Việc thu hẹp các vấn đề về mã của bạn luôn dễ dàng hơn khi các mục trong theo dõi ngăn xếp có tên!
Rất dài và tôi hy vọng nó sẽ giúp!
:)
Tự gọi (còn được gọi là tự động gọi) là khi một hàm thực thi ngay lập tức theo định nghĩa của nó. Đây là một mẫu cốt lõi và đóng vai trò là nền tảng cho nhiều mẫu phát triển JavaScript khác.
Tôi là một fan hâm mộ lớn :) của nó bởi vì:
Rất nhiều - (Tại sao bạn nên nói nó tốt?)
Thêm ở đây .
Không gian tên. Phạm vi của JavaScript là cấp độ chức năng.
Tôi không thể tin rằng không có câu trả lời nào đề cập đến toàn cầu.
Cấu (function(){})()
trúc không bảo vệ chống lại toàn cầu ngụ ý, mà đối với tôi là mối quan tâm lớn hơn, xem http://yuiblog.com/blog/2006/06/01/global-domination/
Về cơ bản, khối chức năng đảm bảo tất cả các "vars toàn cầu" phụ thuộc mà bạn đã xác định được giới hạn trong chương trình của bạn, nó không bảo vệ bạn khỏi việc xác định các phần tử ẩn. Mã não hoặc tương tự có thể cung cấp các khuyến nghị về cách bảo vệ chống lại hành vi này.
var App = {}
Cú pháp ngắn gọn hơn cung cấp một mức độ bảo vệ tương tự và có thể được gói trong khối chức năng khi trên các trang 'công khai'. (xem Ember.js hoặc SproutCore để biết các ví dụ trong thế giới thực của các thư viện sử dụng cấu trúc này)
Theo như private
các thuộc tính, chúng là loại được đánh giá cao trừ khi bạn đang tạo một khung công khai hoặc thư viện, nhưng nếu bạn cần thực hiện chúng, Douglas Crockford có một số ý tưởng hay.
Tôi đã đọc tất cả các câu trả lời, một điều rất quan trọng đang thiếu ở đây , tôi sẽ HÔN. Có hai lý do chính, tại sao tôi cần Tự thực hiện các Hàm ẩn danh hoặc nói tốt hơn là " Biểu hiện chức năng được gọi ngay lập tức (IIFE) ":
Điều đầu tiên đã được giải thích rất tốt. Đối với cái thứ hai, xin vui lòng nghiên cứu ví dụ sau:
var MyClosureObject = (function (){
var MyName = 'Michael Jackson RIP';
return {
getMyName: function () { return MyName;},
setMyName: function (name) { MyName = name}
}
}());
Chú ý 1: Chúng tôi không chỉ định một chức năng MyClosureObject
, hơn nữa kết quả của việc gọi chức năng đó . Coi chừng()
trong dòng cuối cùng.
Chú ý 2: Ngoài ra, bạn cần biết gì về các hàm trong Javascript là các hàm bên trong có quyền truy cập vào các tham số và biến của các hàm, chúng được định nghĩa bên trong.
Hãy để chúng tôi thử một số thí nghiệm:
Tôi có thể MyName
sử dụng getMyName
và nó hoạt động:
console.log(MyClosureObject.getMyName());
// Michael Jackson RIP
Cách tiếp cận khéo léo sau đây sẽ không hoạt động:
console.log(MyClosureObject.MyName);
// undefined
Nhưng tôi có thể đặt tên khác và nhận được kết quả mong đợi:
MyClosureObject.setMyName('George Michael RIP');
console.log(MyClosureObject.getMyName());
// George Michael RIP
Chỉnh sửa: Trong ví dụ trên MyClosureObject
được thiết kế để được sử dụng mà không có new
tiền tố, do đó theo quy ước, nó không nên được viết hoa.
Có một tham số và "Bunch of code" trả về một hàm không?
var a = function(x) { return function() { document.write(x); } }(something);
Khép kín. Giá trị something
được sử dụng bởi hàm được gán cho a
. something
có thể có một số giá trị khác nhau (cho vòng lặp) và mỗi khi có một hàm mới.
var x = something;
hơn x
là tham số: imo nó dễ đọc hơn theo cách này ...
x
và phụ thuộc trực tiếp vào phạm vi từ vựng, tức là document.write(something)
...
Phạm vi cách ly, có thể. Vì vậy, các biến bên trong khai báo hàm không gây ô nhiễm không gian tên bên ngoài.
Tất nhiên, trên một nửa các triển khai JS ngoài kia, dù sao thì chúng cũng sẽ như vậy.
Đây là một ví dụ chắc chắn về cách một chức năng ẩn danh tự gọi có thể hữu ích.
for( var i = 0; i < 10; i++ ) {
setTimeout(function(){
console.log(i)
})
}
Đầu ra: 10, 10, 10, 10, 10...
for( var i = 0; i < 10; i++ ) {
(function(num){
setTimeout(function(){
console.log(num)
})
})(i)
}
Đầu ra: 0, 1, 2, 3, 4...
let
thay cho var
trường hợp đầu tiên sẽ ổn.
Vì các hàm trong Javascript là đối tượng hạng nhất, bằng cách định nghĩa nó theo cách đó, nó xác định một cách hiệu quả một "lớp" giống như C ++ hoặc C #.
Hàm đó có thể định nghĩa các biến cục bộ và có các hàm bên trong nó. Các hàm bên trong (phương thức thể hiện hiệu quả) sẽ có quyền truy cập vào các biến cục bộ (biến thể hiện hiệu quả), nhưng chúng sẽ được tách biệt khỏi phần còn lại của tập lệnh.
Chức năng tự gọi trong javascript:
Một biểu thức tự gọi được gọi tự động (bắt đầu) mà không được gọi. Một biểu thức tự gọi được gọi ngay sau khi nó được tạo. Điều này về cơ bản được sử dụng để tránh xung đột đặt tên cũng như để đạt được đóng gói. Các biến hoặc đối tượng khai báo không thể truy cập bên ngoài hàm này. Để tránh các vấn đề tối thiểu hóa (filename.min) luôn sử dụng chức năng tự thực hiện.
Chức năng tự thực thi được sử dụng để quản lý phạm vi của Biến.
Phạm vi của một biến là khu vực của chương trình mà nó được xác định.
Một biến toàn cầu có phạm vi toàn cầu; nó được định nghĩa ở mọi nơi trong mã JavaScript của bạn và có thể được truy cập từ bất kỳ đâu trong tập lệnh, ngay cả trong các chức năng của bạn. Mặt khác, các biến được khai báo trong một hàm chỉ được xác định trong phần thân của hàm. Chúng là các biến cục bộ, có phạm vi cục bộ và chỉ có thể được truy cập trong hàm đó. Các tham số hàm cũng được tính là các biến cục bộ và chỉ được xác định trong phần thân của hàm.
Như được hiển thị bên dưới, bạn có thể truy cập biến toàn cục bên trong hàm của mình và cũng lưu ý rằng trong phần thân của hàm, một biến cục bộ được ưu tiên hơn một biến toàn cục có cùng tên.
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();
Vì vậy, về cơ bản, một hàm tự thực thi cho phép mã được viết mà không cần quan tâm đến cách các biến được đặt tên trong các khối mã javascript khác.
(function(){
var foo = {
name: 'bob'
};
console.log(foo.name); // bob
})();
console.log(foo.name); // Reference error
Trên thực tế, hàm trên sẽ được coi là biểu thức hàm mà không có tên.
Mục đích chính của việc gói một hàm với dấu ngoặc đơn đóng và mở là để tránh gây ô nhiễm không gian toàn cầu.
Các biến và hàm bên trong biểu thức hàm trở thành riêng tư (nghĩa là) chúng sẽ không có sẵn bên ngoài hàm.
Câu trả lời ngắn gọn là: để ngăn ngừa ô nhiễm phạm vi Toàn cầu (hoặc cao hơn).
IIFE (Biểu thức chức năng được gọi ngay lập tức) là cách thực hành tốt nhất để viết tập lệnh dưới dạng trình cắm, tiện ích bổ sung, tập lệnh người dùng hoặc bất kỳ tập lệnh nào được mong đợi sẽ hoạt động với tập lệnh của người khác . Điều này đảm bảo rằng bất kỳ biến nào bạn xác định không cung cấp hiệu ứng không mong muốn trên các tập lệnh khác.
Đây là cách khác để viết biểu thức IIFE. Cá nhân tôi thích phương pháp sau:
void function() {
console.log('boo!');
// expected output: "boo!"
}();
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void
Từ ví dụ trên, rõ ràng IIFE cũng có thể ảnh hưởng đến hiệu quả và hiệu suất, bởi vì chức năng dự kiến chỉ được chạy một lần sẽ được thực hiện một lần và sau đó được bỏ vào khoảng trống . Điều này có nghĩa là khai báo hàm hoặc phương thức không còn trong bộ nhớ.
void
trước đây. Tôi thích nó.
Trước tiên, bạn phải truy cập MDN IIFE , Bây giờ một số điểm về điều này
Có vẻ như câu hỏi này đã được trả lời sẵn sàng, nhưng dù sao tôi cũng sẽ đăng đầu vào của mình.
Tôi biết khi tôi thích sử dụng các chức năng tự thực hiện.
var myObject = {
childObject: new function(){
// bunch of code
},
objVar1: <value>,
objVar2: <value>
}
Hàm cho phép tôi sử dụng một số mã bổ sung để xác định các thuộc tính và thuộc tính của childObjects cho mã sạch hơn, chẳng hạn như đặt các biến thường được sử dụng hoặc thực hiện các phương trình toán học; Oh! hoặc kiểm tra lỗi. trái ngược với việc bị giới hạn ở cú pháp khởi tạo đối tượng lồng nhau của ...
object: {
childObject: {
childObject: {<value>, <value>, <value>}
},
objVar1: <value>,
objVar2: <value>
}
Viết mã nói chung có rất nhiều cách tối nghĩa để làm nhiều việc giống nhau, khiến bạn tự hỏi, "Tại sao phải bận tâm?" Nhưng các tình huống mới tiếp tục xuất hiện khi bạn không còn chỉ dựa vào hiệu trưởng cơ bản / cốt lõi.
Đưa ra câu hỏi đơn giản của bạn: "Trong javascript, khi nào bạn muốn sử dụng cái này: ..."
Tôi thích câu trả lời của @ken_browning và @ sean_keeping, nhưng đây là một trường hợp sử dụng khác mà tôi không thấy được đề cập:
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());
trong đó Node.insert là một số hành động không đồng bộ.
Tôi không thể gọi chờ mà không có từ khóa async khi khai báo chức năng của mình và tôi không cần một chức năng được đặt tên để sử dụng sau này, nhưng cần chờ cuộc gọi chèn đó hoặc tôi cần một số tính năng phong phú khác (ai biết?) .
IIRC nó cho phép bạn tạo các thuộc tính và phương thức riêng tư.