Ưu tiên toán tử với toán tử bậc ba trong Javascript


116

Tôi dường như không thể quấn lấy phần đầu của mã này (+ =) kết hợp với toán tử bậc ba.

h.className += h.className ? ' error' : 'error'

Cách tôi nghĩ mã này hoạt động như sau:

h.className = h.className + h.className ? ' error' : 'error'

Nhưng điều đó không chính xác vì điều đó gây ra lỗi trong bảng điều khiển của tôi.

Vì vậy, câu hỏi của tôi là làm thế nào tôi nên xen kẽ mã này một cách chính xác?

Câu trả lời:


141
h.className = h.className + (h.className ? ' error' : 'error')

Bạn muốn nhà điều hành làm việc cho h.className, tốt hơn là hãy nói cụ thể về nó.
Tất nhiên, không có tác hại nào xảy ra h.className += ' error', nhưng đó là một vấn đề khác.

Ngoài ra, hãy lưu ý rằng nó được +ưu tiên hơn toán tử bậc ba: JavaScript Operator Precedence


3
Tôi nghĩ rằng cần lưu ý rằng, mặc dù không có tác hại nào có thể xảy ra h.className += ' error', nhưng nó cũng để lại một khoảng trống ở đầu chuỗi nếu ban đầu nó trống. Tôi tin rằng điểm của hoạt động bậc ba là tạo ra một chuỗi trông sạch sẽ.
JMTyler

@JMTyler - Đó chính xác là những gì tôi đã chỉ ra - Nếu tất cả đã hoàn thành chỉ để giữ một khoảng trống ngay từ đầu, tôi không đáng. (trường hợp cạnh bao gồm các bộ chọn jQuery hoặc XPath chính xác). Dù sao cũng cảm ơn.
Kobi

@Kobi +1 cho cảnh báo ưu tiên nhà điều hành một mình!
Ed Chapel

129

Nghĩ theo cách này:

<variable> = <expression> ? <true clause> : <false clause>

Cách câu lệnh được thực thi về cơ bản như sau:

  1. <expression>đánh giá đúng hay nó đánh giá sai?
  2. Nếu <expression>đánh giá là true, thì giá trị của <true clause>được gán cho <variable>, <false clause>bị bỏ qua và câu lệnh tiếp theo được thực thi.
  3. Nếu <expression>đánh giá là false, thì <true clause>sẽ bị bỏ qua và giá trị của <false clause>được gán cho <variable>.

Điều quan trọng cần nhận ra với toán tử bậc ba trong ngôn ngữ này và các ngôn ngữ khác là bất kỳ mã nào trong đó đều <expression>phải tạo ra kết quả boolean khi được đánh giá: true hoặc false.

Trong trường hợp ví dụ của bạn, hãy thay thế "được gán cho" trong phần giải thích của tôi bằng "được thêm vào", hoặc tương tự cho bất kỳ số học viết tắt nào bạn đang sử dụng, nếu có.


Lưu ý chắc chắn nếu nhận xét hoàn hảo là phù hợp :) Nó bỏ qua bất kỳ giải thích nào về lý do tại sao các biểu thức bên trái "được nhóm lại với nhau" trước (nghĩa là vì +có mức độ ưu tiên lớn hơn toán tử điều kiện / bậc ba (trên thực tế, toán tử điều kiện hầu như luôn là cuối cùng được đánh giá trong bất kỳ biểu thức nào).
Gone Coding

10

+=không làm những gì bạn muốn, nhưng trong câu lệnh bậc ba ở bên phải của nó, nó sẽ kiểm tra nếu h.classNamelà falsey, nó sẽ là gì nếu nó không được xác định. Nếu nó đúng (nghĩa là nếu tên lớp đã được chỉ định), thì lỗi sẽ được thêm vào một khoảng trắng (tức là thêm một lớp mới ), nếu không thì nó được thêm vào mà không có khoảng trắng.

Mã có thể được viết lại như bạn đề xuất, nhưng bạn cần chỉ định rằng h.classNamenó sẽ được sử dụng để so sánh độ trung thực, thay vì sử dụng giá trị thực của nó, trong toán tử bậc ba, vì vậy hãy đảm bảo rằng bạn không bận tâm đến việc nối các giá trị đồng thời khi thực hiện hoạt động bậc ba của bạn:

h.className = h.className + (h.className ? ' error' : 'error');

13
cũng yeah, undefinedkhông phải là sai nó chỉ xử lý như thể nó là
David Hedlund

4

Bên phải của người =điều khiển được đánh giá từ trái sang phải. Vì thế,

g.className = h.className + h.className ? ' error' : 'error';`

tương đương với

h.className = (h.className + h.className) ? ' error' : 'error';

Tương đương với

h.className += h.className ? ' error' : 'error';

bạn phải tách câu lệnh bậc ba trong ngoặc đơn

h.className = h.className + (h.className ? ' error' : 'error');

3
if (h.className) {
    h.className = h.className + ' error';
} else {
    h.className = h.className + 'error';
}

phải tương đương với:

h.className += h.className ? ' error' : 'error';

1

Tôi biết đây là một câu hỏi rất cũ, nhưng tôi không hài lòng 100% với bất kỳ câu trả lời nào vì tất cả chúng đều có vẻ không đầy đủ. Vì vậy, ở đây chúng tôi đi lại từ các hiệu trưởng đầu tiên:

Mục tiêu chung của người dùng:

Tóm tắt đoạn mã: "Tôi muốn thêm errortên lớp vào một chuỗi, tùy chọn với khoảng trắng ở đầu nếu đã có tên lớp trong chuỗi."

Giải pháp đơn giản nhất

Như Kobi đã chỉ ra, cách đây 5 năm, việc có khoảng trắng hàng đầu trong tên lớp sẽ không gây ra bất kỳ vấn đề nào với bất kỳ trình duyệt đã biết nào, vì vậy giải pháp chính xác ngắn nhất thực sự sẽ là:

h.className += ' error';

Đó là cần phải có được những câu trả lời thực tế để các vấn đề thực tế .


Có thể như vậy, các câu hỏi được đặt ra là ...

1) Tại sao nó hoạt động?

h.className += h.className ? ' error' : 'error'

Toán tử có điều kiện / bậc ba hoạt động giống như một câu lệnh if, gán kết quả của nó truehoặc falsecác đường dẫn đến một biến.

Vì vậy, mã đó đã hoạt động vì nó được đánh giá đơn giản là:

if (h.className IS NOT null AND IS NOT undefined AND IS NOT '') 
    h.className += ' error'
else
    h.className += 'error'

2) và tại sao điều này bị phá vỡ?

h.className = h.className + h.className ? ' error' : 'error'

Câu hỏi nêu rõ "lỗi [n] trong bảng điều khiển của tôi", điều này có thể khiến bạn hiểu nhầm rằng mã không hoạt động . Trong thực tế các mã sau đây không chạy, không lỗi , nhưng nó chỉ đơn giản là lợi nhuận 'lỗi' nếu chuỗi không trống rỗng và 'lỗi' nếu chuỗi rỗng và do đó chưa đáp ứng được yêu cầu .

Mã đó luôn dẫn đến một chuỗi chỉ chứa ' error'hoặc 'error'vì nó đánh giá thành mã giả này:

if ((h.className + h.className) IS NOT null AND IS NOT undefined AND IS NOT '')
    h.className = ' error'
else
    h.className = 'error'

Lý do cho điều này là toán tử cộng ( +dân gian thông thường) có "mức độ ưu tiên" cao hơn (6) so với toán tử điều kiện / bậc ba (15). Tôi biết những con số xuất hiện ngược lại

Ưu tiên đơn giản có nghĩa là mỗi loại toán tử trong một ngôn ngữ được đánh giá theo một thứ tự xác định trước cụ thể (và không chỉ từ trái sang phải).

Tham khảo: Ưu tiên toán tử Javascript

Cách thay đổi thứ tự đánh giá:

Bây giờ chúng ta biết tại sao nó không thành công, bạn cần biết cách làm cho nó hoạt động.

Một số câu trả lời khác nói về việc thay đổi mức độ ưu tiên , nhưng bạn không thể . Ưu tiên là ngôn ngữ khó có. Đó chỉ là một bộ quy tắc cố định ... Tuy nhiên, bạn có thể thay đổi thứ tự đánh giá ...

Công cụ trong hộp công cụ của chúng tôi có thể thay đổi thứ tự đánh giá là toán tử nhóm (còn gọi là dấu ngoặc). Nó thực hiện điều này bằng cách đảm bảo các biểu thức trong ngoặc được đánh giá trước các hoạt động bên ngoài ngoặc. Đó là tất cả những gì họ làm, nhưng như vậy là đủ.

Dấu ngoặc hoạt động đơn giản vì chúng (toán tử nhóm) có mức độ ưu tiên cao hơn tất cả các toán tử khác ("bây giờ có mức 0").

Chỉ cần thêm dấu ngoặc, bạn sẽ thay đổi thứ tự đánh giá để đảm bảo kiểm tra điều kiện được thực hiện trước, trước khi nối chuỗi đơn giản:

h.className = h.className + (h.className ? ' error' : 'error')

Bây giờ tôi sẽ để câu trả lời này để rỉ sét trong số những người khác :)


1

Tôi muốn chọn giải thích về wayne:

<variable> = <expression> ? <true clause> : <false clause>

Hãy xem xét cả hai trường hợp:

case 1:
h.className += h.className ? 'true' : 'false'     
  • toán tử gán hoạt động tốt và giá trị được thêm vào
  • khi chạy lần đầu tiên, o / p: false
  • Lần 2. o / p: falsetrue - các giá trị tiếp tục tăng thêm

case2: h.className = h.className + h.className? 'đúng sai'

  • kết quả không giống như trường hợp 1
  • khi chạy lần đầu tiên, o / p: false
  • Lần 2. o / p: false - các giá trị không tiếp tục nối với nhau

explanation

Trong đoạn mã trên, trường hợp 1 hoạt động tốt

trong khi case2:

h.className = h.className + h.className ? 'true' : 'false'
is executed as 
 h.className = (h.className + h.className) ? 'true' : 'false'

h.className + h.className=> được coi là biểu thức cho toán tử bậc ba vì toán tử bậc ba được ưu tiên cao hơn. vì vậy, luôn luôn kết quả của biểu thức bậc ba chỉ được gán

Bạn cần xác định mức độ ưu tiên bằng cách sử dụng dấu ngoặc

Bạn cần xác định thứ tự đánh giá được xem xét với sự trợ giúp của dấu ngoặc để trường hợp 2 hoạt động như trường hợp 1

h.className = h.className + (h.className ? ' error' : 'error') 

1
Thuật ngữ ở đây không hoàn toàn đúng. Quyền ưu tiên vốn có trong ngôn ngữ, bạn không định nghĩa nó . Thay vào đó, bạn xác định thứ tự đánh giá bằng cách giới thiệu các dấu ngoặc (có mức độ ưu tiên cao hơn tất cả các toán tử khác).
Gone Coding

@TrueBlueAussie Tôi chấp nhận nó. tôi đánh giá cao cho việc đọc của bạn ý 1
angelin Nadar
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.