!function () {}();
!function () {}();
Câu trả lời:
Cú pháp JavaScript 101. Đây là một khai báo hàm :
function foo() {}
Lưu ý rằng không có dấu chấm phẩy: đây chỉ là một khai báo hàm . Bạn sẽ cần một lời gọi foo()
, để thực sự chạy chức năng.
Bây giờ, khi chúng ta thêm dấu chấm than dường như vô hại: !function foo() {}
nó biến nó thành một biểu thức . Bây giờ nó là một biểu thức chức năng .
Tất nhiên, !
một mình không gọi hàm, nhưng bây giờ chúng ta có thể đặt ()
ở cuối: !function foo() {}()
có độ ưu tiên cao hơn !
và gọi hàm ngay lập tức.
Vì vậy, những gì tác giả đang làm là lưu một byte cho mỗi biểu thức hàm; một cách dễ đọc hơn sẽ là thế này:
(function(){})();
Cuối cùng, !
làm cho biểu thức trở lại đúng. Điều này là do theo mặc định tất cả trở lại IIFE undefined
, mà lá chúng tôi với !undefined
đó là true
. Không đặc biệt hữu ích.
!
trả về boolean, tất cả chúng ta đều biết điều đó, nhưng điểm tuyệt vời mà bạn đưa ra là nó cũng chuyển đổi câu lệnh khai báo hàm thành biểu thức hàm để hàm có thể được gọi ngay lập tức mà không cần gói nó trong ngoặc đơn. Không rõ ràng, và rõ ràng ý định của lập trình viên.
var foo =
phá vỡ sự mơ hồ của câu lệnh / biểu thức và bạn có thể viết một cách đơn giản, var foo = function(bar){}("baz");
v.v.
Chức năng:
function () {}
trả về không có gì (hoặc không xác định).
Đôi khi chúng ta muốn gọi một chức năng ngay khi chúng ta tạo ra nó. Bạn có thể bị cám dỗ để thử điều này:
function () {}()
nhưng nó kết quả trong một SyntaxError
.
Sử dụng !
toán tử trước hàm làm cho nó được coi là một biểu thức, vì vậy chúng ta có thể gọi nó:
!function () {}()
Điều này cũng sẽ trở ngược lại boolean của giá trị trả về của hàm, trong trường hợp này true
, vì !undefined
là true
. Nếu bạn muốn giá trị trả về thực tế là kết quả của cuộc gọi, thì hãy thử thực hiện theo cách này:
(function () {})()
!
là biến khai báo hàm thành biểu thức hàm, chỉ vậy thôi.
!function
cú pháp
Có một điểm tốt để sử dụng !
cho việc gọi hàm được đánh dấu trên hướng dẫn JavaScript của airbnb
Nói chung ý tưởng cho việc sử dụng kỹ thuật này trên các tệp riêng biệt (còn gọi là mô-đun) mà sau này được nối lại. Thông báo trước ở đây là các tệp được cho là được nối bởi các công cụ đưa tệp mới vào dòng mới (đây là hành vi phổ biến đối với hầu hết các công cụ concat). Trong trường hợp đó, việc sử dụng !
sẽ giúp tránh lỗi nếu mô-đun được nối trước đó bỏ qua dấu chấm phẩy, và điều đó sẽ giúp bạn linh hoạt đặt chúng theo bất kỳ thứ tự nào mà không phải lo lắng.
!function abc(){}();
!function bca(){}();
Sẽ hoạt động giống như
!function abc(){}();
(function bca(){})();
nhưng lưu một ký tự và tùy ý trông tốt hơn.
Và bằng cách này bất kỳ +
, -
, ~
, void
khai thác có hiệu quả tương tự, về cách gọi các chức năng, chắc chắn nếu bạn phải sử dụng một cái gì đó để trở về từ chức năng rằng họ sẽ đóng vai trò khác nhau.
abcval = !function abc(){return true;}() // abcval equals false
bcaval = +function bca(){return true;}() // bcaval equals 1
zyxval = -function zyx(){return true;}() // zyxval equals -1
xyzval = ~function xyz(){return true;}() // your guess?
nhưng nếu bạn sử dụng các mẫu IIFE cho một tệp một mã tách mô-đun và sử dụng công cụ concat để tối ưu hóa (làm cho một dòng một công việc tệp), thì hãy xây dựng
!function abc(/*no returns*/) {}()
+function bca() {/*no returns*/}()
Sẽ thực hiện mã an toàn, giống như một mẫu mã đầu tiên.
Điều này sẽ gây ra lỗi vì JavaScript ASI sẽ không thể thực hiện công việc của nó.
!function abc(/*no returns*/) {}()
(function bca() {/*no returns*/})()
Một lưu ý liên quan đến các toán tử đơn nguyên, chúng sẽ thực hiện công việc tương tự, nhưng chỉ trong trường hợp, chúng không được sử dụng trong mô-đun đầu tiên. Vì vậy, chúng không an toàn nếu bạn không có toàn quyền kiểm soát thứ tự nối.
Những công việc này:
!function abc(/*no returns*/) {}()
^function bca() {/*no returns*/}()
Không phải cái này:
^function abc(/*no returns*/) {}()
!function bca() {/*no returns*/}()
Nó trả về việc tuyên bố có thể đánh giá thành sai. ví dụ:
!false // true
!true // false
!isValid() // is not valid
Bạn có thể sử dụng nó hai lần để ép buộc một giá trị thành boolean:
!!1 // true
!!0 // false
Vì vậy, để trả lời trực tiếp hơn câu hỏi của bạn:
var myVar = !function(){ return false; }(); // myVar contains true
Chỉnh sửa: Nó có tác dụng phụ là thay đổi khai báo hàm thành biểu thức hàm. Ví dụ: đoạn mã sau không hợp lệ vì nó được hiểu là một khai báo hàm thiếu định danh bắt buộc (hoặc tên hàm ):
function () { return false; }(); // syntax error
var myVar = !function(){ return false; }()
có thể bỏ qua lượt !
thích var myVar = function(){ return false; }()
và hàm sẽ thực thi chính xác và giá trị trả về sẽ không được chạm tới.
true
bằng !0
và false
bằng !1
. Nó tiết kiệm 2 hoặc 3 ký tự.
Nó chỉ để lưu một byte dữ liệu khi chúng tôi thực hiện thu nhỏ javascript.
xem xét chức năng ẩn danh dưới đây
function (){}
Để thực hiện chức năng tự gọi ở trên, chúng ta thường sẽ thay đổi mã ở trên là
(function (){}())
Bây giờ chúng tôi đã thêm hai ký tự (,)
ngoài việc thêm ()
vào cuối hàm cần gọi hàm. Trong quá trình thu nhỏ, chúng tôi thường tập trung để giảm kích thước tệp. Vì vậy, chúng ta cũng có thể viết các chức năng trên như
!function (){}()
Cả hai đều là các hàm tự gọi và chúng tôi cũng lưu một byte. Thay vì 2 ký tự, (,)
chúng tôi chỉ sử dụng một ký tự!
! là một toán tử KHÔNG logic , nó là một toán tử boolean sẽ đảo ngược một cái gì đó ngược lại.
Mặc dù bạn có thể bỏ qua dấu ngoặc đơn của hàm được gọi bằng cách sử dụng BANG (!) Trước hàm, nó vẫn sẽ đảo ngược trả về, có thể không phải là điều bạn muốn. Như trong trường hợp của IEFE, nó sẽ trả về không xác định , khi đảo ngược trở thành boolean true.
Thay vào đó, hãy sử dụng dấu ngoặc đơn đóng và BANG ( ! ) Nếu cần.
// I'm going to leave the closing () in all examples as invoking the function with just ! and () takes away from what's happening.
(function(){ return false; }());
=> false
!(function(){ return false; }());
=> true
!!(function(){ return false; }());
=> false
!!!(function(){ return false; }());
=> true
Các nhà khai thác khác làm việc ...
+(function(){ return false; }());
=> 0
-(function(){ return false; }());
=> -0
~(function(){ return false; }());
=> -1
Toán tử kết hợp ...
+!(function(){ return false; }());
=> 1
-!(function(){ return false; }());
=> -1
!+(function(){ return false; }());
=> true
!-(function(){ return false; }());
=> true
~!(function(){ return false; }());
=> -2
~!!(function(){ return false; }());
=> -1
+~(function(){ return false; }());
+> -1
Dấu chấm than làm cho bất kỳ chức năng nào luôn trả về một boolean.
Giá trị cuối cùng là phủ định giá trị được trả về bởi hàm.
!function bool() { return false; }() // true
!function bool() { return true; }() // false
Bỏ qua !
trong các ví dụ trên sẽ là một SyntaxError .
function bool() { return true; }() // SyntaxError
Tuy nhiên, một cách tốt hơn để đạt được điều này sẽ là:
(function bool() { return true; })() // true
!
thay đổi cách thời gian chạy phân tích hàm. Nó làm cho bộ thực thi coi hàm như một biểu thức hàm (và không phải là khai báo). Nó thực hiện điều này để cho phép nhà phát triển gọi hàm ngay lập tức bằng ()
cú pháp. !
cũng sẽ áp dụng chính nó (tức là phủ định) vào kết quả của việc gọi biểu thức hàm.
Một cách khác để viết IIFE (biểu thức hàm được gọi ngay lập tức).
Cách viết khác của nó -
(function( args ) {})()
giống như
!function ( args ) {}();
(function (args) {...})()
cú pháp rõ ràng hơn và để !function
biểu mẫu đó cho các công cụ thu nhỏ và mã hóa.
!
sẽ phủ nhận (ngược lại) bất cứ điều gì bạn mong đợi như kết quả, tức là nếu bạn có
var boy = true;
undefined
boy
true
!boy
false
Khi bạn gọi boy
, kết quả của bạn sẽ là true
, nhưng thời điểm bạn thêm !
khi gọi boy
, tức là !boy
kết quả của bạn sẽ có false
. Nói cách khác, ý bạn là NotBoy , nhưng lần này về cơ bản nó là kết quả boolean, true
hoặc false
.
Đó là điều tương tự xảy ra với !function () {}();
biểu thức, chỉ chạy function () {}();
sẽ đánh dấu lỗi của bạn, nhưng thêm !
ngay trước function () {}();
biểu thức của bạn , làm cho nó ngược lại với biểu thức function () {}();
sẽ trả về bạn true
. Ví dụ có thể được nhìn thấy dưới đây:
function () {}();
SyntaxError: function statement requires a name
!function () {}();
true