JavaScript OR (||) giải thích gán biến


351

Đưa ra đoạn mã JavaScript này ...

var a;
var b = null;
var c = undefined;
var d = 4;
var e = 'five';

var f = a || b || c || d || e;

alert(f); // 4

Ai đó có thể vui lòng giải thích cho tôi kỹ thuật này được gọi là gì (dự đoán tốt nhất của tôi là trong tiêu đề của câu hỏi này!)? Và làm thế nào / tại sao nó hoạt động chính xác?

Tôi hiểu rằng biến đó fsẽ được gán giá trị gần nhất (từ trái sang phải) của biến đầu tiên có giá trị không phải là null hoặc không xác định, nhưng tôi đã không tìm thấy nhiều tài liệu tham khảo về kỹ thuật này và có Thấy nó dùng nhiều.

Ngoài ra, kỹ thuật này có dành riêng cho JavaScript không? Tôi biết làm một cái gì đó tương tự trong PHP sẽ dẫn đến fviệc có một giá trị boolean thực sự, hơn là giá trị của dchính nó.


4
Câu hỏi cũ, nhưng liên quan đến PHP, có một cấu trúc bạn có thể sử dụng : $f=$a or $f=$b or $f=$c; // etc. PHP có cả ||toán tử và ortoán tử, thực hiện cùng một công việc; tuy nhiên orđược đánh giá sau khi gán trong khi ||được đánh giá trước. Điều này cũng mang đến cho bạn phong cách hoàn hảo của$a=getSomething() or die('oops');
Manngo

1
Trong PHP 5.3, bạn có thể bỏ phần giữa của toán tử ternary để dựa vào đó ... Bạn cũng có thể cắt ngắn hơn một chút thành một cái gì đó như thế này: $f = $a ?: $b ?: $c;
Rei

1
Kể từ PHP 7, bạn có thể sử dụng ??cho việc này. $a = $b ?? 'default'
Spencer Ruskin

@SpencerRuskin vì vậy $asẽ được gán giá trị $bnếu $blà đúng, khác 'default'?
oldboy

Đúng rồi. Nhìn vào phần toán tử kết hợp null trên trang này: php.net/manual/en/migration70.new-features.php
Spencer Ruskin

Câu trả lời:


212

Xem đánh giá ngắn mạch để giải thích. Đó là một cách phổ biến để thực hiện các toán tử này; nó không phải là duy nhất cho JavaScript.


57
Chỉ cần lưu ý 'gotcha', cái cuối cùng sẽ luôn được gán ngay cả khi tất cả chúng không được xác định, null hoặc false. Đặt thứ gì đó bạn biết không sai, không hoặc không xác định ở cuối chuỗi là một cách tốt để báo hiệu không tìm thấy gì.
Erik Reppen

Tôi đã thấy kỹ thuật này trong nhiều năm, nhưng điều khiến tôi ngạc nhiên khi tôi muốn sử dụng nó là kết quả của biểu thức không được chuyển sang boolean. Bạn không thể làm sau này if( true == f ). Nếu một số nguyên được lưu trữ trong f, thì kiểm tra này sẽ luôn trả về false.

9
Trên thực tế, bạn có thể làm if(true == f), điều này giống như if(f): bài kiểm tra sẽ vượt qua. Nếu bạn cũng muốn thử nghiệm các loại của f, sử dụng so sánh nghiêm ngặt: if(true === f), mà sẽ thất bại thực sự.
Alsciende

5
Có, đánh giá ngắn mạch là phổ biến. Nhưng điểm khác biệt ở đây nằm ở cách JavaScript trả về giá trị cuối cùng đã tạm dừng thực thi. Câu trả lời của @ Anurag làm tốt hơn nhiều việc giải thích điều này.
Ben.12

không chắc chắn nếu đó là lời giải thích tốt nhất cho người mới bắt đầu. Tôi muốn giới thiệu: javascript.info/logical-operators
csguy

198

Này được thực hiện để gán một giá trị mặc định , trong trường hợp này giá trị của y, nếu xbiến là falsy .

Các toán tử boolean trong JavaScript có thể trả về một toán hạng và không phải lúc nào cũng là kết quả boolean như trong các ngôn ngữ khác.

Toán tử logic OR ( ||) trả về giá trị của toán hạng thứ hai của nó, nếu toán tử thứ nhất là sai, nếu không thì giá trị của toán hạng thứ nhất được trả về.

Ví dụ:

"foo" || "bar"; // returns "foo"
false || "bar"; // returns "bar"

Falsy giá trị là những người ép buộc đến falsekhi được sử dụng trong bối cảnh boolean, và họ là 0, null, undefined, một chuỗi rỗng, NaNvà tất nhiên false.


1
+1 Có nhà điều hành nào khác như vậy không? Hoặc là ||độc quyền.
OscarRyz

9
@Support (@ Oscar): Các logic &&điều hành có hành vi tương tự, nó sẽ trả về giá trị của toán hạng đầu tiên nếu nó tự falsy và trả về giá trị của toán hạng thứ hai, chỉ khi một trong những đầu tiên là truthy , ví dụ ("foo" && "bar") == "bar"(0 && "bar") == 0
CMS

12
Falsy trong thực tế là thuật ngữ kỹ thuật.
ChaosPandion

8
Vì vậy, chúng tôi đã tìm hiểu về | |, &&, "Falsy" và "Truly" trong bài đăng này. Câu trả lời tốt nhất với quà tặng "ẩn".
Alex

4
@Alex NB: "Sự thật" (! "Thật sự")
Bumpy

183

Javacript sử dụng đánh giá ngắn mạch cho các toán tử logic ||&&. Tuy nhiên, nó khác với các ngôn ngữ khác ở chỗ nó trả về kết quả của giá trị cuối cùng đã tạm dừng thực thi, thay vì a truehoặc falsegiá trị.

Các giá trị sau được coi là giả trong JavaScript.

  • sai
  • vô giá trị
  • "" (chuỗi trống)
  • 0
  • Nan
  • chưa xác định

Bỏ qua các quy tắc ưu tiên toán tử và giữ cho mọi thứ đơn giản, các ví dụ sau đây cho thấy giá trị nào đã dừng đánh giá và được trả về kết quả.

false || null || "" || 0 || NaN || "Hello" || undefined // "Hello"

5 giá trị đầu tiên NaNtrở lên là sai lệch vì vậy tất cả chúng được đánh giá từ trái sang phải, cho đến khi nó đáp ứng giá trị trung thực đầu tiên - "Hello"làm cho toàn bộ biểu thức là đúng, do đó, mọi giá trị tiếp theo sẽ không được đánh giá và "Hello"được trả về do kết quả của biểu thức . Tương tự, trong trường hợp này:

1 && [] && {} && true && "World" && null && 2010 // null

5 giá trị đầu tiên đều là sự thật và được đánh giá cho đến khi nó đáp ứng giá trị nullgiả mạo đầu tiên ( ) làm cho biểu thức sai, do đó 2010không được đánh giá nữa và nullđược trả về do kết quả của biểu thức.

Ví dụ bạn đã đưa ra là sử dụng thuộc tính JavaScript này để thực hiện một bài tập. Nó có thể được sử dụng bất cứ nơi nào mà bạn cần để có được giá trị trung thực hoặc giả đầu tiên trong số các giá trị. Mã này dưới đây sẽ gán giá trị "Hello"đến bkhi nó làm cho nó dễ dàng hơn để gán một giá trị mặc định, thay vì làm if-else kiểm tra.

var a = false;
var b = a || "Hello";

Bạn có thể gọi ví dụ dưới đây là khai thác tính năng này và tôi tin rằng nó làm cho mã khó đọc hơn.

var messages = 0;
var newMessagesText = "You have " + messages + " messages.";
var noNewMessagesText = "Sorry, you have no new messages.";
alert((messages && newMessagesText) || noNewMessagesText);

Bên trong cảnh báo, chúng tôi kiểm tra xem có phải messageslà giả hay không, và nếu có, sau đó đánh giá và trả lại noNewMessagesText, nếu không thì đánh giá và trả lại newMessagesText. Vì nó sai trong ví dụ này, chúng tôi dừng lại ở noNewMessagesText và cảnh báo "Sorry, you have no new messages.".


36
Đây là câu trả lời tốt nhất theo ý kiến ​​của tôi vì lời giải thích sau:However, it's different to other languages in that it returns the result of the last value that halted the execution, instead of a true, or false value.
mastazi

1
@mastazi Yep, nó nên đi bằng phông chữ đậm IMHO.
noober

6
Nên là câu trả lời, nó cho thấy các giá trị được chọn trong các trường hợp thử nghiệm.
Dadan

Đồng ý, đây là câu trả lời yêu thích của tôi vì nó đặc biệt giải quyết các mối quan tâm về gán biến JavaScript. Ngoài ra, nếu bạn chọn sử dụng một ternary làm một trong các biến tiếp theo để kiểm tra phân công (sau toán tử), bạn phải bọc ternary trong ngoặc đơn để đánh giá phân công hoạt động chính xác.
Joey T

đây phải là câu trả lời được chấp nhận
Alan

49

Các biến Javascript không được gõ, vì vậy f có thể được gán một giá trị số nguyên mặc dù nó được gán thông qua các toán tử boolean.

f được gán giá trị gần nhất không tương đương với false . Vì vậy, 0, false, null, không xác định, tất cả đều được chuyển qua:

alert(null || undefined || false || '' || 0 || 4 || 'bar'); // alerts '4'

13
Đừng quên ''cũng bằng sai trong trường hợp này.
Brigand

Upvote đã chỉ ra rằng f is assigned the NEAREST valueđó là một điểm khá quan trọng ở đây.
steviejay

3
"Gần nhất" không hoàn toàn đúng, mặc dù nó có vẻ ngoài đó. ||Toán tử boolean , là toán tử boolean có hai toán hạng: một bên trái và một bên phải. Nếu phía bên trái của ||truthy , các giải quyết hoạt động sang phía bên trái và bên phải được bỏ qua. Nếu phía bên trái là falsy , nó giải quyết về phía bên phải. Vì vậy, null || undefined || 4 || 0thực sự giải quyết để undefined || 4 || 0giải quyết 4 || 0mà giải quyết 4.
devios1

29

Không có phép thuật nào với nó. Biểu thức Boolean như a || b || c || dđược đánh giá lười biếng. Interpeter tìm kiếm giá trị của a, nó không được xác định vì vậy nó sai nên nó tiếp tục, sau đó nó thấy bcái nào là null, vẫn cho kết quả sai để nó tiếp tục, sau đó nó nhìn thấy c- cùng một câu chuyện. Cuối cùng, nó nhìn thấy dvà nói 'huh, nó không phải là null, vì vậy tôi có kết quả của mình' và nó gán nó cho biến cuối cùng.

Thủ thuật này sẽ hoạt động trong tất cả các ngôn ngữ động thực hiện đánh giá ngắn mạch các biểu thức boolean. Trong các ngôn ngữ tĩnh, nó sẽ không biên dịch (lỗi loại). Trong các ngôn ngữ mong muốn đánh giá các biểu thức boolean, nó sẽ trả về giá trị logic (nghĩa là đúng trong trường hợp này).


6
Trong ngôn ngữ khá tĩnh C # người ta có thể sử dụng ?? toán tử á la: object f = a ?? b ?? c ?? d ?? e;
herzmeister

2
herzmeister - cảm ơn! Tôi không biết điều đó ?? toán tử có thể bị xiềng xích trong C # và được sử dụng trong các kỹ thuật đánh giá lười biếng
Marek

3
Như đã đề cập ở nơi khác, cái cuối cùng dsẽ được chỉ định cho dù nó có rỗng / không xác định hay không.
BlackV Donable

Một điều chỉnh nhỏ: ||toán tử luôn giải quyết toàn bộ toán hạng bên phải khi bên trái bị sai. Là một toán tử boolean, nó chỉ nhìn thấy hai đầu vào: bên trái và bên phải. Trình phân tích cú pháp không xem chúng là một chuỗi các thuật ngữ, vì vậy nó không thực sự dừng khi tìm thấy giá trị trung thực đầu tiên trừ khi giá trị đó cũng là toán hạng bên trái của một thuật ngữ khác ||.
devios1

8

Câu hỏi này đã nhận được một số câu trả lời tốt.

Tóm lại, kỹ thuật này đang tận dụng một tính năng về cách ngôn ngữ được biên dịch. Nghĩa là, JavaScript "đoản mạch" việc đánh giá các toán tử Boolean và sẽ trả về giá trị được liên kết với giá trị biến không sai đầu tiên hoặc bất cứ biến nào cuối cùng chứa. Xem giải thích của Anurag về những giá trị sẽ đánh giá là sai.

Sử dụng kỹ thuật này không phải là thực hành tốt vì nhiều lý do; Tuy nhiên.

  1. Khả năng đọc mã: Đây là sử dụng các toán tử Boolean và nếu hành vi về cách biên dịch này không được hiểu, thì kết quả mong đợi sẽ là giá trị Boolean.
  2. Tính ổn định: Đây là cách sử dụng một tính năng về cách ngôn ngữ được biên dịch không nhất quán trên nhiều ngôn ngữ và do đó, đây là thứ có khả năng được nhắm mục tiêu thay đổi trong tương lai.
  3. Các tính năng tài liệu: Có một giải pháp thay thế hiện có đáp ứng nhu cầu này và phù hợp với nhiều ngôn ngữ hơn. Đây sẽ là toán tử ternary:

    ()? giá trị 1: Giá trị 2.

Sử dụng toán tử ternary đòi hỏi phải gõ nhiều hơn một chút, nhưng nó phân biệt rõ ràng giữa biểu thức Boolean được đánh giá và giá trị được gán. Ngoài ra, nó có thể được xâu chuỗi, vì vậy các loại bài tập mặc định đang được thực hiện ở trên có thể được tạo lại.

var a;
var b = null;
var c = undefined;
var d = 4;
var e = 'five';

var f =  ( a ) ? a : 
                ( b ) ? b :
                       ( c ) ? c :
                              ( d ) ? d :
                                      e;

alert(f); // 4

potentially be targeted for change in the future.có, nhưng tôi không áp dụng cho javascript.
Dadan

Đến đây và thấy tất cả các câu trả lời ở trên và đang nghĩ với bản thân mình rằng một cái gì đó chỉ nhìn ra về bài tập. Tôi vừa đọc Mã sạch của Robert C Martin và loại chuyển nhượng này chắc chắn vi phạm quy tắc "Không có tác dụng phụ" ... trong khi chính tác giả nói rằng cuốn sách của anh ta chỉ là một trong nhiều kỹ thuật để tạo mã tốt, tôi vẫn còn ngạc nhiên khi không ai phản đối loại bài tập này. +1
Albert Rothman

Cảm ơn bạn đã phản hồi. Tôi nghĩ rằng nhiều người cần xem xét các tác dụng phụ khi viết mã, nhưng cho đến khi ai đó đã dành nhiều thời gian để duy trì mã của người khác. Họ thường không xem xét nó.
WSimpson

1
Bạn thực sự nghĩ rằng sự quái dị rõ ràng hơn a || b || c || d || e ?
devios1

1
@AlbertRothman Tôi không thấy bất kỳ tác dụng phụ nào. Không có gì đang bị đột biến. Nó chỉ đơn giản là một tốc ký cho việc kết hợp null, đây là một tính năng khá phổ biến trong nhiều ngôn ngữ.
devios1

7

Trả lại đầu ra giá trị thực đầu tiên .

Nếu tất cả đều trả về giá trị sai cuối cùng.

Thí dụ:-

  null || undefined || false || 0 || 'apple'  // Return apple

4

Nó đặt biến mới ( z) thành giá trị của xnếu đó là "sự thật" (khác không, một đối tượng / mảng / hàm hợp lệ / bất cứ điều gì) hoặc ynếu không. Đó là một cách tương đối phổ biến để cung cấp một giá trị mặc định trong trường hợpx không tồn tại.

Ví dụ: nếu bạn có một hàm lấy tham số gọi lại tùy chọn, bạn có thể cung cấp một cuộc gọi lại mặc định không làm gì cả:

function doSomething(data, callback) {
    callback = callback || function() {};
    // do stuff with data
    callback(); // callback will always exist
}

1

Điều đó có nghĩa là nếu xđược đặt, giá trị cho zsẽ là x, nếu không, nếu yđược đặt thì giá trị của nó sẽ được đặt thành zgiá trị của.

nó giống như

if(x)
  z = x;
else
  z = y;

Có thể bởi vì các toán tử logic trong JavaScript không trả về các giá trị boolean nhưng giá trị của phần tử cuối cùng cần thiết để hoàn thành thao tác (trong câu OR nó sẽ là giá trị không sai đầu tiên, trong câu AND sẽ là giá trị cuối cùng ). Nếu hoạt động thất bại, sau đó falseđược trả lại.


5
cái này sai! if (x) {z = x; } other {z = y;} nếu giá trị đầu tiên là sai, giá trị thứ hai luôn được gán không phụ thuộc vào giá trị thực sự là gì.
evilpie

Ngoại trừ việc tôi nghĩ nó chỉ gán y cho z nếu x sai . Đó là cách nó hoạt động với tôi trong FF, tất nhiên, điều đó cũng có thể phụ thuộc vào việc thực hiện.
tvanfosson

7
Phần cuối cùng về việc trả lại sai không đúng (không có ý định chơi chữ). Nếu giá trị đầu tiên là falsey, ||toán tử chỉ trả về giá trị thứ hai, bất kể đó có phải là sự thật hay không.
Matthew Crumley

-1. Đoạn mã tương đương của bạn là chính xác, nhưng điểm quan trọng là zđược đặt thành giá trị xnếu giá trị đó là trung thực . Nếu không, nó được đặt thành giá trị của y. Điều này có nghĩa là nếu xđược đặt thành, ví dụ, 0hoặc chuỗi trống "", thì điều này không thực hiện được những gì bạn nói, vì các giá trị đó là sai lệch .
Daniel Cassidy

1

Nó được gọi là toán tử ngắn mạch.

Đánh giá ngắn mạch cho biết, đối số thứ hai chỉ được thực hiện hoặc đánh giá nếu đối số thứ nhất không đủ để xác định giá trị của biểu thức. khi đối số đầu tiên của hàm OR (||) ước tính là true, giá trị tổng thể phải là true.

Nó cũng có thể được sử dụng để đặt giá trị mặc định cho đối số hàm .`

function theSameOldFoo(name){ 
  name = name || 'Bar' ;
  console.log("My best friend's name is " + name);
}
theSameOldFoo();  // My best friend's name is Bar
theSameOldFoo('Bhaskar');  // My best friend's name is Bhaskar`

0

Nó sẽ đánh giá X và, nếu X không phải là null, chuỗi rỗng hoặc 0 (logic sai), thì nó sẽ gán nó cho z. Nếu X là null, chuỗi rỗng hoặc 0 (logic sai), thì nó sẽ gán y cho z.

var x = '';
var y = 'bob';
var z = x || y;
alert(z);

Sẽ xuất 'bob';


Bạn nên làm rõ những gì bạn có nghĩa là 'trống rỗng'. Chuỗi rỗng ép buộc false, nhưng mảng trống hoặc đối tượng cưỡng chế true.
Daniel Cassidy

@Daniel "null, trống hoặc 0" - null sẽ áp dụng cho các mảng và đối tượng. Điểm lấy, mặc dù.
tvanfosson

0

Theo bài đăng trên Blog của Bill Higgins ; thành ngữ logic OR OR gán (tháng 2 năm 2007), hành vi này đúng với v1.2 (ít nhất)

Ông cũng gợi ý một cách sử dụng khác cho nó (trích dẫn): " bình thường hóa nhẹ sự khác biệt giữa các trình duyệt "

// determine upon which element a Javascript event (e) occurred
var target = /*w3c*/ e.target || /*IE*/ e.srcElement;
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.