Câu hỏi Thế nào là !! (không phải) toán tử trong JavaScript?


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

Ngữ cảnh mà tôi thấy đây là

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

2330
2018-04-24 08:13


gốc


Hãy nhớ nó bằng "bang, bang bạn boolean" - Gus
Chỉ cần cho các hồ sơ, khô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 đòi hỏi sự phân công không cần thiết, là hoàn toàn tiêu chuẩn, và chỉ là nhanh (trên FF và Chrome hiện tại) jsperf.com/boolean-conversion-speed . - Phil H
!! không phải là một nhà điều hành. Nó chỉ là! điều hành hai lần. - Vivek
Chỉ để cho bản ghi âm thôi, Boolean(5/0) không giống như !!5/0 - schabluk
@schabluk, để ghi lại, thứ tự các hoạt động Là lý do !!5/0 sản xuất Infinity thay vì true, được sản xuất bởi Boolean(5/0). !!5/0 tương đương với (!!5)/0 - a.k.a true/0 -- bởi vì ! nhà điều hành có ưu tiên cao hơn so với / nhà điều hành. Nếu bạn muốn Booleanize 5/0 sử dụng cú đúp, bạn cần sử dụng !!(5/0). - matty


Các câu trả lời:


Coerces oObject để boolean. Nếu nó là falsey (ví dụ: 0, null, undefined, vv), nó sẽ là false, nếu không thì, true.

!oObject  //Inverted boolean
!!oObject //Non inverted boolean so true boolean representation

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

Ví dụ thế giới thực "Thử nghiệm phiên bản IE":

let isIE8 = false;  
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 null  

nhưng nếu bạn ⇒

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

2076
2018-04-24 08:18



Nó chuyển đổi một nonboolean thành một boolean ngược (ví dụ,! 5 sẽ là sai, vì 5 là một giá trị không giả trong JS), sau đó boolean-inverts để bạn nhận được giá trị ban đầu như một boolean (vì vậy !! 5 sẽ đúng). - Chuck
Một cách dễ dàng để mô tả nó là: Boolean (5) === !! 5; Đúc cùng, ít ký tự hơn. - Micah Snyder
Điều này được sử dụng để chuyển đổi các giá trị trung thực thành giá trị boolean true và các giá trị sai quá sai boolean. - thetoolman
@Micah Snyder hãy cẩn thận rằng trong JavaScript thì tốt hơn nên sử dụng các boolean nguyên thủy thay vì tạo các đối tượng có boolean với Boolean () mới. Dưới đây là một ví dụ để xem sự khác biệt: jsfiddle.net/eekbu - victorvartan
Theo như tôi biết, mô hình bang-bang này không hữu ích bên trong câu lệnh if (… _; chỉ trong một câu lệnh trả về của một hàm trả về một boolean. - rds


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

! Là KHÔNG PHẢI. Vì thế !true Là false!false Là true. !0 Là true!1 Là false.

Vì vậy, bạn đang chuyển đổi một giá trị thành 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);

733
2017-09-10 17:28



!! false = false. !! true = true - roosteronacid
(userId == 0) ? false : true; làm tổn thương não của tôi ít nhất. - Andy Gaskell
Vô cùng mơ hồ .... đẹp mắt ngắn gọn đến mắt tôi .... - James Westgate
Biến thể "dễ hiểu hơn" có thực sự dễ hiểu hơn nhiều ở đây không? Việc kiểm tra với 0 không phải là một kiểm tra thực tế đối với 0, nhưng một kiểm tra đối với danh sách các giá trị hơi lạ mà Javascript xem xét bằng 0. userId ? true : false  làm rõ hơn là 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ành undefined - Ben Regenspan
Não của tôi không có bất kỳ vấn đề giải mã nào !!var vào Boolean(var) .. và !! nhanh hơn (ít hướng dẫn để xử lý) và ngắn hơn các giải pháp thay thế. - adamJLev


!!expr trả về một giá trị Boolean (true hoặc là false) tùy thuộc vào tính trung thực của biểu thức. Nó có ý nghĩa hơn khi được sử dụng trên các loại phi 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!

376
2018-05-15 09:06



Đáng chú ý: !!new Boolean(false) // true - Camilo Martin
...Nhưng cũng !!Boolean(false) // false - Camilo Martin
new Boolean(false) là một đối tượng và một đối tượng là sự thật ngay cả khi nó chứa một giá trị giả! - Salman A
Có, tôi biết, nhưng hãy xem xét thực tế là hầu hết các nhà xây dựng bản địa (String, Number, Date, vv) có nghĩa là để được gọi là chức năng quá, nhưng trong trường hợp này kết quả là khác nhau! - Camilo Martin
@SalmanA Tôi cũng hy vọng javascript có ý nghĩa đôi khi: D - Camilo Martin


Brew một số 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ử logic "không".


Về lý thuyết:

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

  • Đó là sự thực false không phải là true (đó là lý do !false các kết quả trong true)

  • Đó là sự thực true không phải là false (đó là lý do !true các kết quả trong false)


!! xác định "chân lý" của giá trị không phải không phải:

  • Đó là sự thực true không phải là không phải  true (đó là lý do !!true kết quả trong true)

  • Đó là sự thực false không phải là không phải  false (đó là lý do !!false kết quả trong false)


Những gì chúng tôi muốn xác định trong so sánh là "sự thật" trong khoảng giá trị của tham chiếu, chứ không phải giá trị của bản thân tham chiếu. Có một trường hợp sử dụng mà 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ị được false (hoặc falsey), hoặc nếu chúng ta mong đợi giá trị không phải là typeof boolean.


Trong thực tế:

Hãy xem xét một hàm súc tích phát hiện chức năng của 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 nhập động (aka "vịt gõ"). Chúng tôi muốn viết một hàm trả về true nếu trình duyệt của người dùng hỗ trợ HTML5 <audio> nhưng chúng tôi không muốn chức năng báo lỗi nếu <audio> không định nghĩa được; 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ể (vì chúng là tổng); và cũng chúng tôi không muốn sử dụng dấu kiểm bên trong hàm 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 ra một phần tử được gọi là <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 một <tag> và một attribute để tìm kiếm, nhưng họ 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 nhiều người biểu diễn phương tiện kiểm tra xem đối tượng được đề cập  một tài sản. 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 ta tiêu hóa ...

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


130
2018-02-22 23:45



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() tuyên bố đã phôi biểu thức để boolean, rõ ràng đúc giá trị trả về của một hàm thử nghiệm để boolean là dư thừa - vì "truthiness" === true như xa như một if()tuyên bố đi anyway. Hoặc tôi thiếu một kịch bản mà bạn CẦN một biểu hiện trung thực để thực sự là boolean true? - Tom Auger
@TomAuger if() báo cáo làm boolean chống lại các giá trị falsey, nhưng nói rằng bạn muốn thực sự thiết lập một cờ boolean trên một đối tượng - nó sẽ không cast nó như một if() tuyên bố. Ví dụ object.hasTheThing = !!castTheReturnValToBoolNoMatterWhat() sẽ đặt true hoặc là false thay vì giá trị trả lại thực. Một ví dụ khác có thể là tất cả quản trị viên id của 0 và không phải quản trị viên là id 1 hoặc cao hơn. Để có được true nếu ai đó không phải là quản trị viên bạn có thể làm person.isNotAdmin = !!admin.id. Vài trường hợp sử dụng, nhưng nó ngắn gọn khi có. - Benny Schmidt


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


87
2017-09-10 17:26



Hoặc trong trường hợp giá trị boolean ở bên phải, nó không làm gì cả. - Daniel A. White
@Daniel: ! vẫn lật giá trị sang bên phải. Trong trường hợp của một boolean quyền nhất ! phủ nhận giá trị, trong khi bên trái ! phủ nhận nó một lần nữa. Hiệu ứng ròng là không có thay đổi, nhưng hầu hết các công cụ sẽ tạo ra mã op cho sự phủ định kép. - Crescent Fresh
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
vấn đề 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, vv Đây là một cách dễ dàng để kiểm tra sự tồn tại. - mix3d


!!foo áp dụng toán tử unary không hai lần và được sử dụng để truyền sang kiểu boolean tương tự như việc sử dụng cộng đơn +foo để đúc thành số và ghép một chuỗi rỗng ''+foo để đúc thành chuỗi.

Thay vì các hacks này, bạn cũng có thể sử dụng các hàm constructor tương ứng với các kiểu nguyên thủy (không có sử dụng new) để trích xuất một cách rõ ràng các giá trị, tức là

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

59
2017-09-10 21:15



Nhưng sau đó bạn có thể gặp vấn đề với instanceof. new Boolean (1) instanceof Object -> true !! 1 instanceof Object -> false - Seamus
không, bạn không thể: chú ý rằng hàm xây dựng được gọi mà không có new - như được đề cập một cách rõ ràng trong câu trả lời của tôi - Christoph
tuyệt diệu! Điều này rất hữu ích cho một chút hack khi bạn cần phải đánh giá chuỗi với "0" là sai thay vì đúng. (tức là khi đọc các giá trị từ các lựa chọn, vì chúng được đọc dưới dạng Chuỗi). Vì vậy, nếu bạn muốn xem xét "0" là âm (Boolean false), asuming x="0" cứ làm đi: x=!!+x; //false đó là giống như Boolean(Number(x)) Số (hoặc + x) chuyển đổi chuỗi "0" thành 0, mà DOES đánh giá thành false, và sau đó Boolean (!! x) chuyển nó thành boolean trực tiếp. Dễ như ăn bánh! - DiegoDD
@DiegoDD tại sao bạn lại chọn !!+x so với 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 sẽ so sánh nó với cái gì khác hay không. - DiegoDD


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

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

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

Đó là...

  • 0 === false Là false.
  • !!0 === false Là true.

Những điều trên không hữu ích lắm. if (!0) cung cấp 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 để đúc một biến để boolean và sau đó so sánh với một boolean "true".

Xem "== và! =" Từ Hướng của JSLint (lưu ý: Crockford đang di chuyển trang web của mình xung quanh một chút; liên kết đó có thể chết tại một số điểm) vì một chút lý do tại sao:

Các toán tử == và! = Gõ kiểu ép buộc trước khi so sánh. Điều này là xấu bởi vì nó gây ra '\ t \ r \ n' == 0 là đúng. Điều này có thể che dấu các 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 đúng cách, vì vậy tốt nhất là không nên sử dụng == và! = Ở tất cả và luôn sử dụng toán tử === và! == đáng tin cậy hơn thay thế.

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 biểu 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 nơi một boolean sẽ được đúc thành một số (true được truyền tới 1 và false đến 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 so sánh một boolean không với một boolean khó gõ, tức là, một lỗi nghiêm trọng.  if (-1) vẫn là con đường để đế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ứ trở nên điên rồ hơn tùy thuộc vào động cơ của bạn. WScript, ví dụ, thắng giải thưởng.

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

Bởi vì một số jive Windows lịch sử, điều đó sẽ xuất ra -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. Nó thật ghê gớm.

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?

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

  • myVar1 === myVar2 Là 0 === undefined và rõ ràng là sai.
  • !!myVar1 === !!myVar2 Là !!0 === !!undefined và là sự thật! Cùng một sự thật! (Trong trường hợp này, cả hai đều "có một sự thật về sự giả dối").

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

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

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 là một cái tên cho cả vợ / chồng và tuổi tác, bạn có thể tiếp tục. Nếu không, bạn chỉ có một trường có giá trị (hoặc một cuộc hôn nhân sắp xếp rất sớm) và cần tạo thêm lỗi trên errorObjects bộ sưu tập.


CHỈNH SỬA 24 tháng 10 năm 2017: 

Thư viện của bên thứ ba 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 libs của bên thứ ba mong đợi các giá trị Boolean rõ ràng.

Ví dụ, Sai trong JSX (React) có một ý nghĩa đặc biệt điều đó không được kích hoạt trên sự đơn giản. Nếu bạn đã thử trả về một thứ gì đó như sau trong JSX của bạn, hãy mong đợi một messageCount...

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

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

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

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

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

Hãy nhớ rằng điều này là một quy ước JSX, không phải là vốn có của JavaScript.

Nhưng nếu bạn thấy lạ 0trong JSX được trả lại của bạn, hãy nghĩ đến việc quản lý sai lệch.


47
2018-04-29 18:14



Lời giải thích hay. Vì vậy, bạn sẽ nói !! không cần thiết trong điều này Phát hiện tính năng công nhân thí dụ? if (!!window.Worker) - jk7
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 để đúc sự thật với 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, như trong q ví dụ 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 nên đánh giá sự thật mỗi lần. - ruffin
Phản ứng là lý do chính chúng tôi bắt đầu sử dụng !! mô hình, nhưng nó sẽ xảy ra 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ề sự thật hoặc sự bực dọc của một thứ gì đó, không phải loại cơ bản là gì. - Alexander Pritchard


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

true === !!10

false === !!0

44
2018-04-24 08:18



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
@ 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 các xác nhận trong câu trả lời của anh ta. - Lightness Races in Orbit


Nó chuyển đổi hậu tố thành giá trị Boolean.


28
2017-09-10 17:27





Đó là một đôi not hoạt động. Đầu tiên ! chuyển giá trị thành boolean và đảo ngược giá trị logic của nó. Thư hai ! đảo ngược giá trị logic trở lại.


21
2017-09-10 17:28





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


21
2018-03-23 11:53