Cấu trúc x = x | | ý bạn là sao


250

Tôi đang gỡ lỗi một số JavaScript và không thể giải thích điều này ||làm gì?

function (title, msg) {
  var title = title || 'Error';
  var msg   = msg || 'Error on Request';
}

Ai đó có thể cho tôi một gợi ý, tại sao anh chàng này đang sử dụng var title = title || 'ERROR'? Tôi đôi khi nhìn thấy nó mà không cần một vartuyên bố là tốt.


44
Mọi người đã trả lời điều này ... nhưng hãy cực kỳ nhận thức được thực tế rằng giá trị thứ hai được chọn nếu giá trị đầu tiên là falsy, chứ không phải CHỈ undefined. Số lần tôi đã thấy doWeDoIt = doWeDoIt || true, đủ để khiến tôi khóc. (tức là doWeDoItsẽ không bao giờ false)
Matt


4
Đối với những người có kinh nghiệm với C #, toán tử hai ống tương đương với toán tử hợp nhất null ??. Javascript đánh giá các đối tượng không null như true (hoặc tốt hơn các đối tượng null thành sai)
usr-local-ΕΨΗΕΛΩΝ

3
Đừng cảm thấy tồi tệ - JS là ngôn ngữ ngớ ngẩn duy nhất cho phép mã hóa khủng khiếp này .... và dạy rằng việc lồng mọi chức năng vào các dòng mã và ném chúng đi khiến chúng trở nên dùng một lần và không thể sử dụng được lần thứ hai. :) Tôi đã 30 năm viết mã và không thể chạm vào JS cho đến khi cách đây không lâu và tôi cảm thấy nỗi đau của bạn, tất cả những gì tôi có thể nói là, hãy "không có ý nghĩa gì, chỉ có trong JS" cheetsheet tiện dụng, đó là cách duy nhất tôi ' đã nhận được bởi! :)
Collin Chaffin

1
Hãy xem xét thay đổi câu trả lời được chấp nhận cho câu trả lời của tôi .
Michał Perłakowski

Câu trả lời:


210

Nó có nghĩa là titleđối số là tùy chọn. Vì vậy, nếu bạn gọi phương thức không có đối số, nó sẽ sử dụng giá trị mặc định là "Error".

Viết tắt của nó:

if (!title) {
  title = "Error";
}

Loại thủ thuật tốc ký này với các biểu thức boolean cũng phổ biến trong Perl. Với biểu thức:

a OR b

nó đánh giá truenếu một trong hai ahoặc btrue. Vì vậy, nếu alà sự thật, bạn không cần phải kiểm tra bgì cả. Điều này được gọi là đánh giá boolean ngắn mạch vì vậy:

var title = title || "Error";

về cơ bản kiểm tra nếu titleđánh giá false. Nếu có, nó "trả về" "Error", nếu không thì trả về title.


3
Xin lỗi vì đã kén chọn, nhưng đối số không phải là tùy chọn, đối số được chọn
themightybun

4
Đây KHÔNG phải là câu trả lời và tôi đồng ý với nhận xét cuối cùng, nó thậm chí không phải là tùy chọn. Không có phần nào của câu trả lời này là chính xác ngay cả tham chiếu Perl vì câu lệnh Perl thực sự tạo ra SENSE và được đánh giá theo một cách hoàn toàn khác. JS là eval trong một phương thức logic boolean "được chuyển đổi" nhiều hơn mà tôi cũng thấy khó hiểu hơn nhiều để đọc / ghi. Câu trả lời dưới đây có tiêu đề "Toán tử đường ống kép là gì" thực sự là một câu trả lời đúng.
Collin Chaffin

198

Toán tử ống đôi ( ||) là gì?

Toán tử ống đôi ( ||) là toán tử logicOR . Trong hầu hết các ngôn ngữ, nó hoạt động theo cách sau:

  • Nếu giá trị đầu tiên là false, nó sẽ kiểm tra giá trị thứ hai. Nếu nó true, nó trở lại truevà nếu nó false, nó trở lại false.
  • Nếu giá trị đầu tiên là true, nó luôn trả về true, bất kể giá trị thứ hai là gì.

Về cơ bản, nó hoạt động như chức năng này:

function or(x, y) {
  if (x) {
    return true;
  } else if (y) {
    return true;
  } else {
    return false;
  }
}

Nếu bạn vẫn không hiểu, hãy nhìn vào bảng này:

      | true   false  
------+---------------
true  | true   true   
false | true   false  

Nói cách khác, nó chỉ sai khi cả hai giá trị đều sai.

JavaScript khác nhau như thế nào?

JavaScript hơi khác một chút, vì đó là ngôn ngữ được gõ lỏng lẻo . Trong trường hợp này, điều đó có nghĩa là bạn có thể sử dụng ||toán tử với các giá trị không phải là booleans. Mặc dù nó không có ý nghĩa gì, bạn có thể sử dụng toán tử này với ví dụ một hàm và một đối tượng:

(function(){}) || {}

Chuyện gì xảy ra ở đó?

Nếu các giá trị không phải là boolean, JavaScript thực hiện chuyển đổi ngầm định thành boolean . Nó có nghĩa là nếu giá trị là falsey (ví dụ 0, "", null, undefined(xem thêm caã caác giaá trõ falsey trong JavaScript )), nó sẽ được coi như false; nếu không thì nó được coi là true.

Vì vậy, ví dụ trên nên đưa ra true, bởi vì hàm rỗng là sự thật. Vâng, nó không. Nó trả về hàm rỗng. Đó là bởi vì ||toán tử của JavaScript không hoạt động như tôi đã viết lúc đầu. Nó hoạt động theo cách sau:

  • Nếu giá trị đầu tiên là falsey , nó sẽ trả về giá trị thứ hai .
  • Nếu giá trị đầu tiên là trung thực , nó sẽ trả về giá trị đầu tiên .

Ngạc nhiên? Trên thực tế, nó "tương thích" với ||toán tử truyền thống . Nó có thể được viết như sau:

function or(x, y) {
  if (x) {
    return x;
  } else {
    return y;
  }
}

Nếu bạn vượt qua một giá trị trung thực như x, nó trả về x, đó là một giá trị trung thực. Vì vậy, nếu bạn sử dụng nó sau này trong ifmệnh đề:

(function(x, y) {
  var eitherXorY = x || y;
  if (eitherXorY) {
    console.log("Either x or y is truthy.");
  } else {
    console.log("Neither x nor y is truthy");
  }
}(true/*, undefined*/));

bạn nhận được "Either x or y is truthy.".

Nếu xlà chim ưng, eitherXorYsẽ là y. Trong trường hợp này, bạn sẽ nhận được "Either x or y is truthy."nếu ylà sự thật; nếu không bạn sẽ nhận được "Neither x nor y is truthy".

Câu hỏi thực tế

Bây giờ, khi bạn biết cách thức ||vận hành, bạn có thể tự mình tìm ra x = x || yý nghĩa của nó. Nếu xlà sự thật, xđược giao cho x, vì vậy thực sự không có gì xảy ra; mặt khác yđược gán cho x. Nó thường được sử dụng để xác định các tham số mặc định trong các chức năng. Tuy nhiên, nó thường được coi là một thực tiễn lập trình xấu , bởi vì nó ngăn bạn truyền một giá trị falsey (không nhất thiết undefinedhoặc null) như một tham số. Xem xét ví dụ sau:

function badFunction(/* boolean */flagA) {
  flagA = flagA || true;
  console.log("flagA is set to " + (flagA ? "true" : "false"));
}

Nó có vẻ hợp lệ ngay từ cái nhìn đầu tiên. Tuy nhiên, điều gì sẽ xảy ra nếu bạn chuyển qua falselàm flagAtham số (vì nó là boolean, tức là có thể truehoặc false)? Nó sẽ trở thành true. Trong ví dụ này, không có cách nào để thiết lập flagAđể false.

Nó sẽ là một ý tưởng tốt hơn để kiểm tra rõ ràng liệu flagAundefined, như thế:

function goodFunction(/* boolean */flagA) {
  flagA = typeof flagA !== "undefined" ? flagA : true;
  console.log("flagA is set to " + (flagA ? "true" : "false"));
}

Mặc dù nó dài hơn, nó luôn hoạt động và dễ hiểu hơn.


Bạn cũng có thể sử dụng cú pháp ES6 cho các tham số chức năng mặc định , nhưng lưu ý rằng nó không hoạt động trong các trình duyệt cũ hơn (như IE). Nếu bạn muốn hỗ trợ các trình duyệt này, bạn nên dịch mã của mình bằng Babel .

Xem thêm Toán tử logic trên MDN .


13
+1 - cho đến nay câu trả lời đúng và đầy đủ nhất. Và, đối với những người có câu hỏi này (một số lập trình viên kỳ cựu mới sử dụng JS) chắc chắn nên tập trung nhiều nhất vào toàn bộ câu trả lời này trên dòng này: "Mặc dù nó không có ý nghĩa gì" bởi vì "loosley gõ" này sẽ không bao giờ có ý nghĩa cho những người trong chúng ta lớn lên mà không có nó Đối với chúng tôi, một toán tử boolean chỉ như vậy và CHỈ ...... và bất kỳ ai cũng nghĩ rằng sẽ là một ý tưởng tốt để dừng lại và suy nghĩ thông qua một số chuyển đổi kỳ quặc của các giá trị không boolean sang boolean trong khi đọc / viết mã , quên uống thuốc ngày hôm đó! :)
Collin Chaffin

2
+1, tóm lại: title = title || 'Error'có nghĩa làif (title) { title = title; } else { title = 'Error'; }
Andre Elrico

Tôi thực sự không đồng ý với dòng "mặc dù nó không có ý nghĩa". Tôi hiểu rằng dòng sẽ không biên dịch trong C, ví dụ, nhưng nó được hiểu rõ nếu bạn đến từ Ruby chẳng hạn, hoặc thậm chí Groovy. Trong Ruby bạn có thể diễn đạt nó thậm chí còn ngắn hơn, như title ||= 'Error'.
Elliot Nelson

28

Nếu tiêu đề không được đặt, sử dụng 'ERROR' làm giá trị mặc định.

Chung hơn:

var foobar = foo || default;

Đọc: Đặt foobar thành foohoặc default. Bạn thậm chí có thể xâu chuỗi này lên nhiều lần:

var foobar = foo || bar || something || 42;

1
Tôi thấy nó khó hiểu vì các biến có cùng tên. Dễ dàng hơn nhiều khi họ không.
Norbert Norbertson

14

Giải thích thêm một chút ...

Các ||nhà điều hành là logical orđiều hành. Kết quả là đúng nếu phần thứ nhất đúng và đúng nếu phần thứ hai đúng và đúng nếu cả hai phần đều đúng. Để rõ ràng, đây là trong một bảng:

 X | Y | X || Y 
---+---+--------
 F | F |   F    
---+---+--------
 F | T |   T    
---+---+--------
 T | F |   T    
---+---+--------
 T | T |   T    
---+---+--------

Bây giờ nhận thấy một cái gì đó ở đây? Nếu Xlà đúng, kết quả luôn luôn đúng. Vì vậy, nếu chúng tôi biết đó Xlà sự thật, chúng tôi không phải kiểm tra Ygì cả. Do đó, nhiều ngôn ngữ thực hiện các đánh giá "ngắn mạch" cho logic- or(và logic - andđến từ hướng khác). Họ kiểm tra yếu tố đầu tiên và nếu đó là sự thật thì họ không buồn kiểm tra yếu tố thứ hai. Kết quả (về mặt logic) là như nhau, nhưng về mặt thực thi có khả năng có một sự khác biệt rất lớn nếu yếu tố thứ hai đắt tiền để tính toán.

Vì vậy, điều này có liên quan gì đến ví dụ của bạn?

var title   = title || 'Error';

Hãy nhìn vào đó. Các titleyếu tố được truyền vào chức năng của bạn. Trong JavaScript nếu bạn không truyền tham số, nó sẽ mặc định là giá trị null. Ngoài ra trong JavaScript nếu biến của bạn là một giá trị null thì nó được coi là sai bởi các toán tử logic. Vì vậy, nếu hàm này được gọi với một tiêu đề đã cho, thì đó là một giá trị không sai và do đó được gán cho biến cục bộ. Tuy nhiên, nếu nó không được đưa ra một giá trị, thì đó là một giá trị null và do đó sai. Sau orđó, toán tử logic sẽ đánh giá biểu thức thứ hai và trả về 'Lỗi'. Vì vậy, bây giờ biến cục bộ được đưa ra giá trị 'Lỗi'.

Điều này hoạt động vì việc thực hiện các biểu thức logic trong JavaScript. Nó không trả về giá trị boolean thích hợp ( truehoặc false) mà thay vào đó trả về giá trị được đưa ra theo một số quy tắc như những gì được coi là tương đương truevà những gì được coi là tương đương false. Tra cứu tài liệu tham khảo JavaScript của bạn để tìm hiểu những gì JavaScript coi là đúng hoặc sai trong bối cảnh boolean.


8

Ống đôi là viết tắt của logic "HOẶC". Đây không thực sự là trường hợp khi "tham số không được đặt", vì hoàn toàn trong javascript nếu bạn có mã như thế này:

function foo(par) {
}

Sau đó gọi

foo()
foo("")
foo(null)
foo(undefined)
foo(0)

không tương đương.

Double pipe (||) sẽ chuyển đối số đầu tiên thành boolean và nếu kết quả boolean là đúng - hãy thực hiện phép gán nếu không nó sẽ gán đúng phần.

Điều này quan trọng nếu bạn kiểm tra tham số unset.

Giả sử, chúng ta có một hàm setSalary có một tham số tùy chọn. Nếu người dùng không cung cấp tham số thì nên sử dụng giá trị mặc định là 10.

nếu bạn làm kiểm tra như thế này:

function setSalary(dollars) {
    salary = dollars || 10
}

Điều này sẽ cho kết quả bất ngờ trong cuộc gọi như

setSalary(0) 

Nó vẫn sẽ đặt 10 theo luồng được mô tả ở trên.


8

Về cơ bản nó kiểm tra nếu giá trị trước | | đánh giá là đúng, nếu có, nó lấy giá trị này, nếu không, nó sẽ lấy giá trị sau | |.

Các giá trị mà nó sẽ lấy giá trị sau | | (càng xa tôi càng nhớ):

  • chưa xác định
  • sai
  • 0
  • '' (Chuỗi Null hoặc Null)

1
sai | | null | | không xác định | | 0 || '' || 'bạn đã quên null'
Dziamid

7

Trong khi câu trả lời của Cletus là chính xác, tôi cảm thấy cần thêm chi tiết liên quan đến "đánh giá thành sai" trong JavaScript.

var title = title || 'Error';
var msg   = msg || 'Error on Request';

Không chỉ kiểm tra xem tiêu đề / thông điệp đã được cung cấp chưa, mà còn nếu một trong số chúng là giả mạo . tức là một trong những điều sau đây:

  • sai.
  • 0 (không)
  • "" (Chuỗi trống)
  • vô giá trị.
  • chưa xác định.
  • NaN (giá trị Số đặc biệt có nghĩa là Không phải số!)

Vì vậy, trong dòng

var title = title || 'Error';

Nếu tiêu đề là trung thực (nghĩa là không phải giả mạo, vì vậy title = "titleMessage", v.v.) thì toán tử Boolean OR (||) đã tìm thấy một giá trị 'true', có nghĩa là nó đánh giá là đúng, do đó, nó bị đoản mạch và trả về giá trị thực (tiêu đề).

Nếu tiêu đề là sai (tức là một trong danh sách ở trên), thì toán tử Boolean OR (||) đã tìm thấy giá trị 'false' và bây giờ cần đánh giá phần khác của toán tử, 'Error', đánh giá là đúng , và do đó được trả lại.

Nó cũng có vẻ (sau một số thử nghiệm bảng điều khiển firebird nhanh) nếu cả hai bên của toán tử đánh giá là sai, nó sẽ trả về toán tử 'giả' thứ hai.

I E

return ("" || undefined)

trả về không xác định, điều này có thể cho phép bạn sử dụng hành vi được hỏi trong câu hỏi này khi cố gắng đặt tiêu đề / thông báo mặc định thành "". tức là sau khi chạy

var foo = undefined
foo = foo || ""

foo sẽ được đặt thành ""


5

vận hành ống đôi

ví dụ này có hữu ích không?

var section = document.getElementById('special');
if(!section){
     section = document.getElementById('main');
}

cũng có thể là

var section = document.getElementById('special') || document.getElementById('main');

4

Để thêm một số lời giải thích cho tất cả đã nói trước tôi, tôi nên cung cấp cho bạn một số ví dụ để hiểu các khái niệm logic.

var name = false || "Mohsen"; # name equals to Mohsen
var family = true || "Alizadeh" # family equals to true

Nó có nghĩa là nếu phía bên trái được đánh giá là một tuyên bố đúng thì nó sẽ được hoàn thành và phía bên trái sẽ được trả về và gán cho biến. trong các trường hợp khác, phía bên phải sẽ được trả lại và được chỉ định.

toán tử có cấu trúc ngược lại như dưới đây.

var name = false && "Mohsen" # name equals to false
var family = true && "Alizadeh" # family equals to Alizadeh

3

| | là toán tử boolean OR. Như trong javascript, undefined, null, 0, false được coi là falsy giá trị.

Nó đơn giản có nghĩa là

true || true = true
false || true = true
true || false = true
false || false = false

undefined || "value" = "value"
"value" || undefined = "value"
null || "value" = "value"
"value" || null = "value"
0 || "value" = "value"
"value" || 0 = "value"
false || "value" = "value"
"value" || false = "value"

2

Trích dẫn: "Cấu trúc x = x || y nghĩa là gì?"

Gán một giá trị mặc định.

Điều này có nghĩa là cung cấp giá trị mặc định của y cho x , trong trường hợp x vẫn đang chờ giá trị của nó nhưng chưa nhận được hoặc bị bỏ qua một cách có chủ ý để trở về mặc định.


Đó là ý nghĩa chính xác của cấu trúc và ý nghĩa duy nhất của nó. Và nó là một chương trình con trong các hàm viết có thể được tìm nạp dưới dạng nguyên mẫu, hàm độc lập và cũng như các phương thức mượn để áp dụng cho một phần tử khác. Trong đó nhiệm vụ chính và duy nhất của nó là sửa đổi tham chiếu của mục tiêu. Ví dụ: function getKeys(x) { x = x || this ; .... }có thể được sử dụng mà không cần sửa đổi như một hàm độc lập, như một phương thức thuộc tính trong các nguyên mẫu và như một phương thức của một phần tử có thể lấy một phần tử khác làm đối số của nó là `[phần tử] .getKeys (AnotherEuity);`
Bekim Bacaj

-5

Và tôi phải thêm một điều nữa: đoạn tốc ký này là một điều kinh tởm. Nó lạm dụng tối ưu hóa trình thông dịch tình cờ (không bận tâm đến thao tác thứ hai nếu lần đầu tiên là trung thực) để kiểm soát một nhiệm vụ. Việc sử dụng đó không liên quan gì đến mục đích của nhà điều hành. Tôi không tin nó nên được sử dụng.

Tôi thích toán tử ternary cho khởi tạo, ví dụ,

var title = title?title:'Error';

Điều này sử dụng một hoạt động có điều kiện một dòng cho mục đích chính xác của nó. Nó vẫn chơi các trò chơi khó coi với tính trung thực nhưng, đó là Javascript dành cho bạn.

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.