Cái gì vậy !! Toán tử (không phải) trong JavaScript?


3106

Tôi thấy một số mã dường như sử dụng một toán tử mà tôi không nhận ra, dưới dạng hai dấu chấm than, như vậy : !!. Ai đó có thể vui lòng cho tôi biết nhà điều hành này làm gì?

Bối cảnh mà tôi thấy điều này là,

this.vertical = vertical !== undefined ? !!vertical : this.vertical;

945
Hãy nhớ nó bằng "bang, bang you boolean"
Gus

75
Chỉ để ghi lại, đừng làm những gì được trích dẫn ở đó. Làm if(vertical !== undefined) this.vertical = Boolean(vertical);- nó sạch hơn và rõ ràng hơn những gì đang diễn ra, không yêu cầu sự phân công không cần thiết, hoàn toàn tiêu chuẩn và cũng nhanh như vậy (trên FF và Chrome hiện tại) jsperf.com/boolean-conversion-speed .
Phil H

73
!! không phải là một nhà điều hành. Nó chỉ là! toán tử hai lần.
Vivek

11
Chỉ dành cho hồ sơ, Boolean(5/0)không giống như!!5/0
schabluk

63
@schabluk, đối với hồ sơ, thứ tự các hoạt động là lý do !!5/0sản xuất Infinitychứ không phải true, như được sản xuất bởi Boolean(5/0). !!5/0tương đương với (!!5)/0- aka true/0- do !toán tử có độ ưu tiên cao hơn /toán tử. Nếu bạn muốn Booleanize 5/0bằng cách sử dụng hai lần, bạn cần sử dụng !!(5/0).
matty

Câu trả lời:


2746

Chuyển đổi Objectsang boolean. Nếu nó là falsey (ví dụ 0, null, undefined, vv), nó sẽ được false, nếu không, true.

!oObject  // inverted boolean
!!oObject // non inverted boolean so true boolean representation

Vì vậy, !!không phải là một nhà điều hành, nó chỉ là !nhà điều hành hai lần.

Ví dụ thực tế "Phiên bản IE thử nghiệm":

const isIE8 = !! navigator.userAgent.match(/MSIE 8.0/);  
console.log(isIE8); // returns true or false 

Nếu bạn

console.log(navigator.userAgent.match(/MSIE 8.0/));  
// returns either an Array or null  

Nhưng nếu bạn

console.log(!!navigator.userAgent.match(/MSIE 8.0/));  
// returns either true or false

123
Nó chuyển đổi một nonboolean thành một boolean đảo ngược (ví dụ: 5 sẽ là sai, vì 5 là một giá trị không sai trong JS), sau đó chuyển đổi boolean để bạn có được giá trị ban đầu là boolean (vì vậy !! 5 sẽ đúng).
Chuck

111
Một cách dễ dàng để mô tả nó là: Boolean (5) === !! 5; Đúc giống nhau, ít nhân vật hơn.
Micah Snyder

39
Điều này được sử dụng để chuyển đổi các giá trị trung thực thành boolean true và các giá trị sai lệch quá boolean false.
thetoolman

13
@Micah Snyder hãy cẩn thận rằng trong JavaScript, tốt hơn là sử dụng các nguyên hàm boolean thay vì tạo các đối tượng đóng hộp booleans với Boolean () mới. Dưới đây là một ví dụ để thấy sự khác biệt: jsfiddle.net/eekbu
victorvartan

4
Theo như tôi biết, điều này mô hình bang-bang là không hữu ích bên trong một if (... _ tuyên bố;. Chỉ trong một tuyên bố trở lại của một hàm sẽ trả về một boolean
RDS

854

Đó là một cách tối nghĩa khủng khiếp để thực hiện chuyển đổi loại.

!KHÔNG . Vì vậy, !truefalse, và !falsetrue. !0true, và !1false.

Vì vậy, bạn đang chuyển đổi một giá trị thành một boolean, sau đó đảo ngược nó, sau đó đảo ngược nó một lần nữa.

// Maximum Obscurity:
val.enabled = !!userId;

// Partial Obscurity:
val.enabled = (userId != 0) ? true : false;

// And finally, much easier to understand:
val.enabled = (userId != 0);

74
!! sai = sai. !! true = true
cllpse

89
Là biến thể "dễ hiểu hơn nhiều" thực sự dễ hiểu hơn nhiều ở đây? Kiểm tra so với 0 không phải là kiểm tra thực tế so với 0, nhưng kiểm tra đối với danh sách giá trị hơi kỳ lạ mà Javascript coi là bằng 0. userId ? true : false làm rõ hơn rằng có chuyển đổi đang diễn ra và xử lý trường hợp giá trị của userId có thể được đặt rõ ràng thànhundefined
Ben Regenspan

54
Bộ não của tôi không có bất kỳ vấn đề nào khi giải mã !!varthành Boolean(var).. và !!nhanh hơn (ít hướng dẫn xử lý hơn) và ngắn hơn các giải pháp thay thế.
adamJLev

7
@RickyClarkson chủ yếu là để dễ đọc vì về mặt cú pháp thì không bắt buộc. Một số sử dụng quy ước luôn luôn gói một điều kiện trong ngoặc đơn để đặt nó tách biệt với phần còn lại của biểu thức.
Dave Rager

8
Tôi không đồng ý với điều này. userId != 0là đúng cho null, NaNundefined, nhưng sai cho false. Nếu bạn muốn chính xác hành vi đó, có lẽ bạn nên rõ ràng về nó. Nhưng ngay cả khi nó hoạt động chính xác như vậy !!userId, không rõ liệu bạn có muốn các giá trị đó xuất hiện sai ở đây hay không, hoặc bạn chỉ không xem xét các quy tắc chuyển đổi loại của Javascript.
philh

449

!!exprtrả về một giá trị Boolean ( truehoặc false) tùy thuộc vào truthiness của biểu thức. Nó có ý nghĩa hơn khi được sử dụng trên các loại không boolean. Xem xét các ví dụ này, đặc biệt là ví dụ thứ 3 trở đi:

          !!false === false
           !!true === true

              !!0 === false
!!parseInt("foo") === false // NaN is falsy
              !!1 === true
             !!-1 === true  // -1 is truthy

             !!"" === false // empty string is falsy
          !!"foo" === true  // non-empty string is truthy
        !!"false" === true  // ...even if it contains a falsy value

     !!window.foo === false // undefined is falsy
           !!null === false // null is falsy

             !!{} === true  // an (empty) object is truthy
             !![] === true  // an (empty) array is truthy; PHP programmers beware!

63
Đáng chú ý:!!new Boolean(false) // true
Camilo Martin

43
... Nhưng còn nữa!!Boolean(false) // false
Camilo Martin

97
new Boolean(false)là một đối tượng và một đối tượng là trung thực ngay cả khi nó chứa một giá trị giả!
Salman A

3
Có, tôi biết, nhưng xem xét thực tế là hầu hết các nhà xây dựng quê hương ( String, Number, Date, vv) có nghĩa là để được callable như các chức năng quá, tuy nhiên trong trường hợp này kết quả là khác nhau!
Camilo Martin

4
@CamiloMartin: chỉ nhận ra rằng new Boolean(false)trả về một objectthời gian Boolean(false)trả về nguyên thủy false . Hy vọng điều này có ý nghĩa.
Salman A

155

Pha một ít trà:

!!không phải là một nhà điều hành. Đó là việc sử dụng hai lần !- là toán tử "không" logic.


Về lý thuyết:

! xác định "sự thật" của giá trị không phải là:

  • Sự thật là falsekhông phải true(đó là lý do tại sao !falsekết quả true)

  • Sự thật là truekhông phải false(đó là lý do tại sao !truekết quả false)


!!xác định "sự thật" của giá trị không phải là không:

  • Sự thật là truekhông phải vậy true (đó là lý do tại sao !!truekết quả true)

  • Sự thật là falsekhông phải vậy false (đó là lý do tại sao !!falsekết quả false)


Điều chúng tôi muốn xác định trong so sánh là "sự thật" về giá trị của một tham chiếu, chứ không phải giá trị của chính tham chiếu đó. Có một trường hợp sử dụng trong đó chúng ta có thể muốn biết sự thật về một giá trị, ngay cả khi chúng ta mong đợi giá trị đó là false(hoặc falsey) hoặc nếu chúng ta mong đợi giá trị không phải là loại boolean.


Trong thực tế:

Hãy xem xét một chức năng ngắn gọn để phát hiện chức năng tính năng (và trong trường hợp này là khả năng tương thích nền tảng) bằng cách gõ động (còn gọi là "gõ vịt"). Chúng tôi muốn viết một hàm trả về truenếu trình duyệt của người dùng hỗ trợ <audio>phần tử HTML5 , nhưng chúng tôi không muốn hàm này gây ra lỗi nếu <audio>không được xác định; và chúng tôi không muốn sử dụng try ... catchđể xử lý bất kỳ lỗi nào có thể xảy ra (vì chúng là thô); chúng tôi cũng không muốn sử dụng kiểm tra bên trong chức năng sẽ không tiết lộ sự thật về tính năng này (ví dụ: document.createElement('audio')vẫn sẽ tạo một phần tử được gọi <audio>ngay cả khi HTML5 <audio>không được hỗ trợ).


Dưới đây là ba cách tiếp cận:

// this won't tell us anything about HTML5 `<audio>` as a feature
var foo = function(tag, atr) { return document.createElement(tag)[atr]; }

// this won't return true if the feature is detected (although it works just fine)
var bar = function(tag, atr) { return !document.createElement(tag)[atr]; }

// this is the concise, feature-detecting solution we want
var baz = function(tag, atr) { return !!document.createElement(tag)[atr]; }

foo('audio', 'preload'); // returns "auto"
bar('audio', 'preload'); // returns false
baz('audio', 'preload'); // returns true

Mỗi hàm chấp nhận một đối số cho a <tag>attributetìm kiếm, nhưng mỗi hàm trả về các giá trị khác nhau dựa trên những gì so sánh xác định.

Nhưng xin chờ chút nữa!

Một số bạn có thể nhận thấy rằng trong ví dụ cụ thể này, người ta có thể chỉ cần kiểm tra một thuộc tính bằng cách sử dụng các phương tiện kiểm tra hiệu quả hơn một chút nếu đối tượng trong câu hỏi có thuộc tính. Có hai cách để làm điều này:

// the native `hasOwnProperty` method
var qux = function(tag, atr) { return document.createElement(tag).hasOwnProperty(atr); }

// the `in` operator
var quux = function(tag, atr) { return atr in document.createElement(tag); }

qux('audio', 'preload');  // returns true
quux('audio', 'preload'); // returns true

Chúng tôi lạc đề ...

Tuy nhiên, hiếm khi xảy ra những tình huống này, có thể tồn tại một vài tình huống trong đó phương tiện ngắn gọn nhất, hiệu quả nhất và do đó, phương tiện được ưa thích nhất truetừ một giá trị không phải là boolean, có thể không xác định được thực sự bằng cách sử dụng !!. Hy vọng điều này vô lý xóa nó đi.


1
Câu trả lời hoàn toàn tuyệt vời, nhưng tôi không thấy tiện ích của !! xây dựng. Vì một if()câu lệnh đã chuyển biểu thức thành boolean, nên việc truyền rõ ràng giá trị trả về của hàm kiểm tra thành boolean là không cần thiết - vì "trueness" === đúng như một if()câu lệnh đi. Hay tôi đang thiếu một kịch bản mà bạn CẦN một biểu thức trung thực để thực sự là boolean true?
Tom Auger

1
Các if()câu lệnh @TomAuger thực hiện boolean chống lại các giá trị falsey, nhưng nói rằng bạn thực sự muốn đặt một cờ boolean trên một đối tượng - nó sẽ không tạo ra nó giống như một if()câu lệnh. Ví dụ: object.hasTheThing = !!castTheReturnValToBoolNoMatterWhat()sẽ đặt truehoặc falsethay vì giá trị trả về thực. Một ví dụ khác là có lẽ tất cả các quản trị viên là idcủa 0và không quản trị viên là id 1hoặc cao hơn. Để có được truenếu ai đó không phải là quản trị viên, bạn có thể làm person.isNotAdmin = !!admin.id. Ít trường hợp sử dụng, nhưng nó ngắn gọn khi có.
Benny

103

!!chuyển đổi giá trị ở bên phải của nó thành giá trị boolean tương đương của nó. (Nghĩ cách "đúc kiểu" của người nghèo). Nó ý định thường là để truyền đạt cho người đọc rằng mã không quan tâm những gì giá trị trong biến, nhưng những gì nó "thật" giá trị là.


4
Hoặc trong trường hợp giá trị boolean ở bên phải, nó không làm gì cả.
Daniel A. Trắng

3
@Daniel: !vẫn lật giá trị sang phải. Trong trường hợp boolean bên phải hầu hết !phủ nhận giá trị, trong khi bên trái hầu hết !phủ nhận nó một lần nữa. Hiệu quả ròng là không có thay đổi, nhưng hầu hết các công cụ sẽ tạo mã op cho phủ định kép.
Lưỡi liềm tươi

Nhưng vấn đề là gì? Nếu tôi làm if(0){...Javascript đã biết điều này là sai. Tại sao nói tốt hơn if(!!0){...?
CodyBugstein

điểm là cho các biến mà bạn có thể không biết nội dung của nó; nếu nó có thể là một số nguyên hoặc một chuỗi, một đối tượng hoặc null, không xác định, v.v ... Đây là một cách dễ dàng để kiểm tra sự tồn tại.
mix3d

71

!!fooáp dụng toán tử unary not hai lần và được sử dụng để chuyển sang kiểu boolean tương tự như việc sử dụng unary plus +foođể truyền vào số và nối chuỗi rỗng ''+foođể truyền thành chuỗi.

Thay vì các hack này, bạn cũng có thể sử dụng các hàm xây dựng tương ứng với các kiểu nguyên thủy ( không sử dụng new) để truyền các giá trị rõ ràng, tức là

Boolean(foo) === !!foo
Number(foo)  === +foo
String(foo)  === ''+foo

Nhưng sau đó bạn có thể gặp vấn đề với instanceof. đối tượng Boolean (1) mới -> đúng !! 1 đối tượng của đối tượng -> sai
Seamus

13
không, bạn không thể: lưu ý rằng các hàm tạo được gọi mà không có new- như được đề cập rõ ràng trong câu trả lời của tôi
Christoph

2
tuyệt diệu! Điều này hữu ích cho một chút hack khi bạn cần đánh giá các chuỗi có "0" là sai thay vì đúng. (tức là khi đọc các giá trị từ các lựa chọn, bởi vì chúng được đọc dưới dạng Chuỗi). Vì vậy, nếu bạn muốn coi "0" là âm (Boolean false), thì x="0"chỉ cần thực hiện: x=!!+x; //falsegiống như Boolean(Number(x))Số (hoặc + x) chuyển đổi chuỗi "0" thành 0, mà DOES đánh giá thành sai, rồi Boolean (!! x) đưa nó vào boolean trực tiếp. Dễ như ăn bánh!
DiegoDĐ

2
@DiegoDD tại sao bạn lại chọn !!+xvs x !== "0"?
Placeybordeaux

@placeybordeaux vì ví dụ bạn có thể muốn chuyển đổi giá trị và gán nó cho biến khác, bất kể bạn có muốn so sánh nó với thứ khác hay không.
DiegoDĐ

67

Vì vậy, nhiều câu trả lời làm một nửa công việc. Có, !!Xcó thể được đọc là "tính trung thực của X [được biểu thị dưới dạng boolean]". Nhưng !!thực tế không phải là như vậy, rất quan trọng để tìm ra liệu một biến duy nhất là (hoặc thậm chí nếu nhiều biến là) trung thực hoặc giả. !!myVar === truecũng giống như chỉ myVar. So sánh !!Xvới một boolean "thực" không thực sự hữu ích.

Những gì bạn đạt được !!là khả năng kiểm tra tính trung thực của nhiều biến số với nhau theo cách lặp lại, được chuẩn hóa (và thân thiện với JSLint).

Đơn giản chỉ cần đúc :(

Đó là...

  • 0 === falsefalse.
  • !!0 === falsetrue.

Ở trên không hữu ích lắm. if (!0)cho bạn kết quả tương tự như if (!!0 === false). Tôi không thể nghĩ ra một trường hợp tốt để chuyển một biến thành boolean và sau đó so sánh với một boolean "thật".

Xem "== và! =" Từ hướng dẫn của JSLint (lưu ý: Crockford đang di chuyển trang web của anh ấy một chút; liên kết đó có thể bị chết tại một số điểm) để biết một chút về lý do:

Các toán tử == và! = Thực hiện ép buộc trước khi so sánh. Điều này là xấu vì nó khiến '\ t \ r \ n' == 0 là đúng. Điều này có thể che dấu lỗi loại. JSLint không thể xác định một cách đáng tin cậy nếu == đang được sử dụng một cách chính xác, vì vậy tốt nhất là không nên sử dụng == và! = Và luôn luôn sử dụng các toán tử === và! == đáng tin cậy hơn.

Nếu bạn chỉ quan tâm rằng một giá trị là trung thực hoặc giả, thì hãy sử dụng mẫu ngắn. Thay vì
(foo != 0)

chỉ nói
(foo)

và thay vì
(foo == 0)

Nói
(!foo)

Lưu ý rằng có một số trường hợp không trực quan trong đó boolean sẽ được chuyển thành một số ( trueđược truyền tới 1falsetới 0) khi so sánh boolean với một số. Trong trường hợp này, !!có thể hữu ích về mặt tinh thần. Mặc dù, một lần nữa, đây là những trường hợp bạn đang so sánh một người không phải là boolean với một boolean khó đánh máy, đó là, imo, một sai lầm nghiêm trọng. if (-1)vẫn là con đường để đi đến đây

╔═══════════════════════════════════════╦═══════════════════╦═══════════╗
               Original                    Equivalent       Result   
╠═══════════════════════════════════════╬═══════════════════╬═══════════╣
 if (-1 == true) console.log("spam")    if (-1 == 1)       undefined 
 if (-1 == false) console.log("spam")   if (-1 == 0)       undefined 
   Order doesn't matter...                                           
 if (true == -1) console.log("spam")    if (1 == -1)       undefined 
╠═══════════════════════════════════════╬═══════════════════╬═══════════╣
 if (!!-1 == true) console.log("spam")  if (true == true)  spam       better
╠═══════════════════════════════════════╬═══════════════════╬═══════════╣
 if (-1) console.log("spam")            if (truthy)        spam       still best
╚═══════════════════════════════════════╩═══════════════════╩═══════════╝

Và mọi thứ thậm chí còn điên rồ hơn tùy thuộc vào động cơ của bạn. WScript, ví dụ, giành giải thưởng.

function test()
{
    return (1 === 1);
}
WScript.echo(test());

Do một số jive Windows lịch sử , nó sẽ xuất -1 trong một hộp thông báo! Hãy thử nó trong một dấu nhắc cmd.exe và xem! Nhưng WScript.echo(-1 == test())vẫn cung cấp cho bạn 0 hoặc WScript false. Nhìn đi chỗ khác Thật gớm ghiếc.

So sánh sự thật :)

Nhưng nếu tôi có hai giá trị tôi cần kiểm tra truthi / falsi-ness bằng nhau thì sao?

Giả vờ chúng ta có myVar1 = 0;myVar2 = undefined;.

  • myVar1 === myVar20 === undefinedvà rõ ràng là sai.
  • !!myVar1 === !!myVar2!!0 === !!undefinedvà là sự thật! Sự thật giống nhau! (Trong trường hợp này, cả hai "có một sự thật giả dối".)

Vì vậy, nơi duy nhất bạn thực sự cần sử dụng "biến boolean-cast" sẽ là nếu bạn gặp tình huống kiểm tra xem cả hai biến có cùng độ trung thực không? Đó là, sử dụng !!nếu bạn cần để xem nếu hai vars là cả truthy hoặc cả hai falsy (hay không), có nghĩa là, các bằng (hoặc không) truthiness .

Tôi không thể nghĩ ra một trường hợp sử dụng tuyệt vời, không giả tạo cho việc đó. Có lẽ bạn đã "liên kết" các trường trong một hình thức?

if (!!customerInput.spouseName !== !!customerInput.spouseAge ) {
    errorObjects.spouse = "Please either enter a valid name AND age " 
        + "for your spouse or leave all spouse fields blank.";
}

Vì vậy, bây giờ nếu bạn có một sự thật cho cả hai hoặc giả cho cả tên vợ và tuổi, bạn có thể tiếp tục. Nếu không, bạn chỉ có một lĩnh vực có giá trị (hoặc một cuộc hôn nhân được sắp xếp rất sớm) và cần tạo thêm một lỗi trên errorObjectsbộ sưu tập của bạn .


EDIT ngày 24 tháng 10 năm 2017, ngày 6 tháng 2 năm 19:

Thư viện bên thứ 3 mong đợi các giá trị Boolean rõ ràng

Đây là một trường hợp thú vị ... !!có thể hữu ích khi các lib của bên thứ 3 mong đợi các giá trị Boolean rõ ràng.

Chẳng hạn, Sai trong JSX (React) có một ý nghĩa đặc biệt không được kích hoạt trên sự giả dối đơn giản. Nếu bạn đã cố gắng trả lại một cái gì đó như sau trong JSX của mình, hãy chờ đợi một int trong messageCount...

{messageCount && <div>You have messages!</div>}

... Bạn có thể ngạc nhiên khi thấy React kết xuất 0khi bạn không có tin nhắn. Bạn phải trả về false một cách rõ ràng để JSX không hiển thị. Câu lệnh trên trả về 0, mà JSX vui vẻ biểu hiện, như nó nên. Nó không thể nói rằng bạn không có Count: {messageCount && <div>Get your count to zero!</div>}(hoặc một cái gì đó ít giả tạo hơn).

  • Một sửa chữa liên quan đến việc bangbang, mà cưỡng ép 0vào !!0, đó là false:
    {!!messageCount && <div>You have messages!</div>}

  • Các tài liệu của JSX đề nghị bạn rõ ràng hơn, viết mã tự nhận xét và sử dụng phép so sánh để buộc Boolean.
    {messageCount > 0 && <div>You have messages!</div>}

  • Tôi cảm thấy thoải mái hơn khi tự mình xử lý sự giả dối -
    {messageCount ? <div>You have messages!</div> : false}

Thỏa thuận tương tự trong Bản mô tả: Nếu bạn có hàm trả về giá trị boolean (hoặc bạn đang gán giá trị cho biến boolean), bạn [thường] không thể trả về / gán giá trị boolean-y; nó phải là một boolean được gõ mạnh. Điều này có nghĩa, iff myObjectđược gõ mạnh , return !myObject;hoạt động cho một hàm trả về boolean, nhưng return myObject;không. Bạn phải return !!myObjectphù hợp với mong đợi của Typecript.

Ngoại lệ cho Bản in? Nếu myObjectlà một any, bạn quay lại Wild West của JavaScript và có thể trả lại mà không cần !!, ngay cả khi kiểu trả về của bạn là boolean.

Hãy nhớ rằng đây là các quy ước về JSX & Typecript , không phải là các quy ước vốn có của JavaScript .

Nhưng nếu bạn thấy 0s lạ trong JSX được kết xuất của bạn, hãy nghĩ rằng quản lý giả mạo lỏng lẻo.


Lời giải thích hay. Vì vậy, bạn sẽ nói !! không thực sự cần thiết trong ví dụ phát hiện tính năng Công nhân này ? if (!!window.Worker)
jk7

2
Không, bạn sẽ không cần nó. Sự thật và true"bên ngoài" hoạt động giống hệt nhau trong một if. Tôi tiếp tục cố gắng, nhưng tôi không thể nghĩ ra lý do nào thích đưa tính trung thực vào giá trị boolean bên ngoài trường hợp "so sánh sự thật" phức tạp, ở trên, ngoại trừ khả năng đọc nếu bạn sử dụng lại giá trị sau này, như trong qví dụ về thư viện . Nhưng ngay cả khi đó, đó là một lối tắt mất thông tin và tôi cho rằng bạn tốt hơn nên đánh giá tính trung thực mỗi lần.
ruffin

Phản ứng là lý do chính khiến chúng tôi bắt đầu sử dụng !! mô hình, nhưng nó là một điều rất thuận tiện và lặp lại. Tôi chỉ phải lo lắng về tính trung thực hoặc không ổn định của một cái gì đó, không phải loại cơ bản là gì.

Downvote mà không có ý kiến ​​làm cho khó khăn để giải quyết mối quan tâm của bạn! Hãy cho tôi biết những gì có vẻ xấu, và tôi sẽ vui lòng giải quyết nó.
ruffin

55

Nó chỉ là toán tử KHÔNG logic, hai lần - nó được sử dụng để chuyển đổi một cái gì đó sang boolean, ví dụ:

true === !!10

false === !!0

3
Tại sao trên trái đất bạn sẽ làm điều đó? Sử dụng ! Toán tử để chuyển đổi sang boolean sau đó sử dụng === để so sánh loại? Chỉ cần chấp nhận bạn không có loại an toàn và làm val> 0 hoặc một cái gì đó.
Darren Clark

43
@Darren: Anh ấy không so sánh các loại; anh ấy nói cho bạn biết kết quả là gì, bằng cách viết những lời khẳng định trong câu trả lời của anh ấy.
Các cuộc đua nhẹ nhàng trong quỹ đạo


26

Đó là một nothoạt động kép . Cái đầu tiên !chuyển đổi giá trị thành boolean và đảo ngược giá trị logic của nó. Cái thứ hai !đảo ngược giá trị logic trở lại.


26

Có vẻ như các !!nhà điều hành dẫn đến một phủ định kép.

var foo = "Hello World!";

!foo // Result: false
!!foo // Result: true

23

Nó mô phỏng hành vi của Boolean()chức năng đúc. Cái đầu tiên NOTtrả về giá trị Boolean bất kể toán hạng nào được đưa ra. Thứ hai NOTphủ định Booleangiá trị đó và do đó cung cấp truegiá trị Boolean của một biến. Kết quả cuối cùng giống như sử dụng Boolean()hàm trên một giá trị.


20

! là "boolean not", về cơ bản là đánh giá giá trị của "enable" đối với boolean của nó. Thư hai ! lật giá trị này. Vì vậy, !!enablecó nghĩa là "không kích hoạt", mang lại cho bạn giá trị enablenhư là một boolean.


18

Tôi nghĩ điều đáng nói là, một điều kiện kết hợp với logic AND / OR sẽ không trả về giá trị boolean nhưng thành công cuối cùng hoặc thất bại đầu tiên trong trường hợp && và thành công đầu tiên hoặc thất bại cuối cùng trong trường hợp | | của chuỗi điều kiện.

res = (1 && 2); // res is 2
res = (true && alert) // res is function alert()
res = ('foo' || alert) // res is 'foo'

Để đưa điều kiện thành một chữ boolean thực sự, chúng ta có thể sử dụng phủ định kép:

res = !!(1 && 2); // res is true
res = !!(true && alert) // res is true
res = !!('foo' || alert) // res is true

17

!!đó là sử dụng NOTthao tác hai lần với nhau, !chuyển đổi giá trị thành a booleanvà đảo ngược nó, đây là một ví dụ đơn giản để xem cách !!hoạt động:

Lúc đầu, nơi bạn có:

var zero = 0;

Sau đó, bạn làm !0, nó sẽ được chuyển đổi thành boolean và được ước tính thành true0 falsy, vì vậy bạn nhận được giá trị đảo ngược và chuyển đổi thành boolean, do đó, nó được ước tính true.

!zero; //true

nhưng chúng tôi không muốn phiên bản boolean đảo ngược của giá trị, vì vậy chúng tôi có thể đảo ngược lại để có kết quả! Đó là lý do tại sao chúng tôi sử dụng một cái khác !.

Về cơ bản, !!hãy chắc chắn rằng, giá trị chúng tôi nhận được là boolean, không phải là giả, sự thật hay chuỗi, v.v ...

Vì vậy, nó giống như sử dụng Booleanchức năng trong javascript, nhưng cách dễ dàng và ngắn hơn để chuyển đổi một giá trị thành boolean:

var zero = 0;
!!zero; //false

15

Các !! trúc này là một cách đơn giản để biến bất kỳ biểu thức JavaScript nào thành tương đương Boolean của nó.

Ví dụ: !!"he shot me down" === true!!0 === false.


2
Rất gần với sự phân biệt quan trọng. Điều quan trọng là 0 === falsesai và !!0 === falseđúng.
ruffin

14

Đó không phải là một nhà điều hành duy nhất, đó là hai. Nó tương đương với những điều sau đây và là một cách nhanh chóng để đưa giá trị lên boolean.

val.enabled = !(!enable);

10

Tôi nghi ngờ đây là phần còn lại từ C ++, nơi mọi người ghi đè lên! toán tử nhưng không phải toán tử bool.

Vì vậy, để có được câu trả lời phủ định (hoặc tích cực) trong trường hợp đó trước tiên bạn cần sử dụng! toán tử để lấy boolean, nhưng nếu bạn muốn kiểm tra trường hợp dương sẽ sử dụng !!.


10

Các ifwhiletuyên bố và ?giá trị sử dụng thật hành để xác định chi nhánh của mã để chạy. Ví dụ, số 0 và NaN và chuỗi trống là sai, nhưng các số và chuỗi khác là đúng. Các đối tượng là đúng, nhưng giá trị không xác định và nullđều sai.

Toán tử phủ định kép !!tính giá trị thật của một giá trị. Đó thực sự là hai toán tử, !!xcó nghĩa là !(!x)và hành xử như sau:

  • Nếu xlà một giá trị sai, !xtrue, và !!xfalse.
  • Nếu xlà một giá trị thực, !xfalse, và !!xtrue.

Khi sử dụng ở cấp cao nhất của một bối cảnh Boolean ( if, whilehay ?), các !!nhà điều hành là tập tính một không-op. Ví dụ, if (x)if (!!x)có nghĩa là điều tương tự.

Sử dụng thực tế

Tuy nhiên nó có một số ứng dụng thực tế.

Một cách sử dụng là nén một cách mất mát một đối tượng vào giá trị thật của nó, để mã của bạn không giữ tham chiếu đến một đối tượng lớn và giữ cho nó tồn tại. Chỉ định !!some_big_objectcho một biến thay vì some_big_objectcho phép nó cho trình thu gom rác. Điều này hữu ích cho các trường hợp tạo ra một đối tượng hoặc giá trị sai, chẳng hạn nhưnull hoặc giá trị không xác định, chẳng hạn như phát hiện tính năng trình duyệt.

Một cách sử dụng khác, mà tôi đã đề cập trong câu trả lời về !!toán tử tương ứng của C , là với các công cụ "lint" tìm kiếm các lỗi chính tả và chẩn đoán in phổ biến. Ví dụ: trong cả C và JavaScript, một vài lỗi chính tả cho các hoạt động Boolean tạo ra các hành vi khác có đầu ra không hoàn toàn như Boolean:

  • if (a = b)là sự phân công theo sau là việc sử dụng giá trị thật của b; if (a == b)là một so sánh bình đẳng.
  • if (a & b)là một bit VÀ VÀ; if (a && b)là một logic VÀ. 2 & 50(một giá trị sai); 2 && 5là đúng.

Các !!nhà điều hành cam đoan với các công cụ lint rằng những gì bạn đã viết là những gì bạn có nghĩa là: làm hoạt động này, sau đó lấy giá trị thật của kết quả.

Việc sử dụng thứ ba là tạo XOR logic và XNOR logic. Trong cả C và JavaScript, a && bthực hiện AND logic (đúng nếu cả hai mặt đều đúng) và a & bthực hiện AND theo bit. a || bthực hiện OR logic (đúng nếu ít nhất một là đúng) và a | bthực hiện OR theo bit. Có một XOR bitwise (OR độc quyền) như a ^ b, nhưng không có toán tử tích hợp nào cho XOR logic (đúng nếu chính xác một bên là đúng). Ví dụ, bạn có thể muốn cho phép người dùng nhập văn bản vào đúng một trong hai trường. Những gì bạn có thể làm là chuyển đổi từng giá trị thành một giá trị thật và so sánh chúng : !!x !== !!y.


8

Phủ định boolean kép. Thường được sử dụng để kiểm tra nếu giá trị không được xác định.


8

Hàng tấn câu trả lời tuyệt vời ở đây, nhưng nếu bạn đã đọc đến đây, điều này đã giúp tôi 'hiểu được'. Mở bảng điều khiển trên Chrome (v.v.) và bắt đầu nhập:

!(!(1))
!(!(0))
!(!('truthy')) 
!(!(null))
!(!(''))
!(!(undefined))
!(!(new Object())
!(!({}))
woo = 'hoo'
!(!(woo))
...etc, etc, until the light goes on ;)

Đương nhiên, tất cả đều giống như chỉ đơn giản là gõ !! một số cách, nhưng các dấu ngoặc đơn được thêm vào có thể giúp làm cho nó dễ hiểu hơn.


8

!!x là tốc ký cho Boolean(x)

Tiếng nổ đầu tiên buộc động cơ js chạy Boolean(x)nhưng cũng có tác dụng phụ là đảo ngược giá trị. Vì vậy, tiếng nổ thứ hai hoàn tác tác dụng phụ.


8

Nó buộc tất cả mọi thứ để boolean.

Ví dụ:

console.log(undefined); // -> undefined
console.log(!undefined); // -> true
console.log(!!undefined); // -> false

console.log('abc'); // -> abc
console.log(!'abc'); // -> false
console.log(!!'abc'); // -> true

console.log(0 === false); // -> undefined
console.log(!0 === false); // -> false
console.log(!!0 === false); // -> true

7

Câu hỏi này đã được trả lời khá kỹ lưỡng, nhưng tôi muốn thêm một câu trả lời mà tôi hy vọng là đơn giản nhất có thể, làm cho ý nghĩa của !! càng đơn giản để nắm bắt càng tốt.

Bởi vì javascript có các giá trị được gọi là giá trị "trung thực" và "falsey", có những biểu thức mà khi được đánh giá trong các biểu thức khác sẽ dẫn đến một điều kiện đúng hoặc sai, mặc dù giá trị hoặc biểu thức được kiểm tra không thực sự truehoặc false.

Ví dụ:

if (document.getElementById('myElement')) {
    // code block
}

Nếu phần tử đó thực tế tồn tại, biểu thức sẽ đánh giá là đúng và khối mã sẽ được thực thi.

Tuy nhiên:

if (document.getElementById('myElement') == true) {
    // code block
}

... sẽ KHÔNG dẫn đến một điều kiện đúng và khối mã sẽ không được thực thi, ngay cả khi phần tử không tồn tại.

Tại sao? Bởi vì document.getElementById()biểu thức "trung thực" sẽ đánh giá là đúng trong if()tuyên bố này , nhưng nó không phải là giá trị boolean thực tế của true.

Việc "không" trong trường hợp này khá đơn giản. Nó chỉ đơn giản là hai nots trở lại.

Cái đầu tiên chỉ đơn giản là "đảo ngược" giá trị trung thực hoặc falsey, dẫn đến một kiểu boolean thực tế, và sau đó kiểu thứ hai "đảo ngược" nó trở lại trạng thái ban đầu, nhưng bây giờ ở giá trị boolean thực tế. Bằng cách đó bạn có sự nhất quán:

if (!!document.getElementById('myElement')) {}

if (!!document.getElementById('myElement') == true) {}

Cả hai sẽ trở lại đúng, như mong đợi.


7

Tôi chỉ muốn thêm rằng

if(variableThing){
  // do something
}

giống như

if(!!variableThing){
  // do something
}

Nhưng điều này có thể là một vấn đề khi một cái gì đó không được xác định.

// a === undefined, b is an empty object (eg. b.asdf === undefined)
var a, b = {};

// Both of these give error a.foo is not defined etc.
// you'd see the same behavior for !!a.foo and !!b.foo.bar

a.foo 
b.foo.bar

// This works -- these return undefined

a && a.foo
b.foo && b.foo.bar
b && b.foo && b.foo.bar

Thủ thuật ở đây là chuỗi &&s sẽ trả về giá trị falsey đầu tiên mà nó tìm thấy - và điều này có thể được đưa vào một câu lệnh if, v.v. Vì vậy, nếu b.foo không được xác định, nó sẽ trả về không xác định và bỏ quab.foo.bar câu lệnh, và chúng tôi không nhận được lỗi.

Trả về ở trên không xác định nhưng nếu bạn có một chuỗi rỗng, false, null, 0, các giá trị không xác định đó sẽ trả về và ngay khi chúng ta gặp chúng trong chuỗi - []{}cả hai đều là "sự thật" và chúng ta sẽ tiếp tục cái gọi là " && chuỗi "sang giá trị tiếp theo bên phải.

PS Một cách khác để làm điều tương tự là (b || {}).foobởi vì nếu b không được xác định thì b || {}sẽ {}và bạn sẽ truy cập một giá trị trong một đối tượng trống (không có lỗi) thay vì cố gắng truy cập một giá trị trong "không xác định" (gây ra lỗi ). Vì vậy, (b || {}).foolà giống như b && b.foo((b || {}).foo || {}).barlà giống như b && b.foo && b.foo.bar.


điểm tốt - thay đổi câu trả lời của tôi. Nó chỉ xảy ra trên một vật thể khi nó được lồng sâu ba cấp độ, bởi vì như bạn đã nói ({}).anythingsẽ choundefined
Ryan Taylor

5

Sau khi thấy tất cả những câu trả lời tuyệt vời này, tôi muốn thêm một lý do khác để sử dụng !!. Hiện tại tôi đang làm việc trong Angular 2-4 (TypeScript) và tôi muốn trả về một boolean như falsekhi người dùng của tôi không được xác thực. Nếu anh ta không được xác thực, chuỗi mã thông báo sẽ là nullhoặc "". Tôi có thể làm điều này bằng cách sử dụng khối mã tiếp theo:

public isAuthenticated(): boolean {
   return !!this.getToken();
}

4

đây là một đoạn mã từ js góc

var requestAnimationFrame = $window.requestAnimationFrame ||
                                $window.webkitRequestAnimationFrame ||
                                $window.mozRequestAnimationFrame;

 var rafSupported = !!requestAnimationFrame;

ý định của họ là đặt rafSupported thành đúng hoặc sai dựa trên tính khả dụng của hàm trong requestAnimationFrame

nó có thể đạt được bằng cách kiểm tra theo cách sau đây nói chung:

if(typeof  requestAnimationFrame === 'function')
rafSupported =true;
else
rafSupported =false;

con đường ngắn có thể được sử dụng !!

rafSupported = !!requestAnimationFrame ;

vì vậy nếu requestAnimationFrame được gán một hàm thì! requestAnimationFrame sẽ sai và thêm một lần nữa! nó sẽ là sự thật

nếu requestAnimationFrame được khẳng định không xác định thì! requestAnimationFrame sẽ là đúng và một nữa! của nó sẽ là sai


3

Một số toán tử trong JavaScript thực hiện chuyển đổi loại ngầm định và đôi khi được sử dụng để chuyển đổi loại.

!Toán tử đơn nguyên chuyển đổi toán hạng của nó thành boolean và phủ định nó.

Thực tế này dẫn đến thành ngữ sau mà bạn có thể thấy trong mã nguồn của mình:

!!x // Same as Boolean(x). Note double exclamation mark

3

Sử dụng logic không phải toán tử hai lần
có nghĩa là! True = false
và !! true = true


3

Trả về giá trị boolean của một biến.

Thay vào đó, Booleanlớp có thể được sử dụng.

(vui lòng đọc mô tả mã)

var X = "test"; // X value is "test" as a String value
var booleanX = !!X // booleanX is `true` as a Boolean value beacuse non-empty strings evaluates as `true` in boolean
var whatIsXValueInBoolean = Boolean(X) // whatIsXValueInBoolean is `true` again
console.log(Boolean(X) === !!X) // writes `true`

Cụ thể, Boolean(X) = !!Xtrong sử dụng.

Hãy mã kiểm tra đoạn mã dưới đây

let a = 0
console.log("a: ", a) // writes a value in its kind
console.log("!a: ", !a) // writes '0 is NOT true in boolean' value as boolean - So that's true.In boolean 0 means false and 1 means true.
console.log("!!a: ", !!a) // writes 0 value in boolean. 0 means false.
console.log("Boolean(a): ", Boolean(a)) // equals to `!!a`
console.log("\n") // newline

a = 1
console.log("a: ", a)
console.log("!a: ", !a)
console.log("!!a: ", !!a) // writes 1 value in boolean
console.log("\n") // newline

a = ""
console.log("a: ", a)
console.log("!a: ", !a) // writes '"" is NOT true in boolean' value as boolean - So that's true.In boolean empty strings, null and undefined values mean false and if there is a string it means true.
console.log("!!a: ", !!a) // writes "" value in boolean
console.log("\n") // newline

a = "test"
console.log("a: ", a) // writes a value in its kind
console.log("!a: ", !a)
console.log("!!a: ", !!a) // writes "test" value in boolean

console.log("Boolean(a) === !!a: ", Boolean(a) === !!a) // writes true

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.