Là một Boolean JS có các thuộc tính tùy chỉnh là một thực tiễn xấu?


41

Trong JS, bạn có thể trả về một Boolean có các thuộc tính tùy chỉnh. Ví dụ. khi Modernizr kiểm tra video hỗ trợ, nó trả về truehoặc falseBoolean được trả về (Bool là đối tượng lớp đầu tiên trong JS) có các thuộc tính chỉ định định dạng nào được hỗ trợ. Lúc đầu, nó làm tôi ngạc nhiên một chút nhưng sau đó tôi bắt đầu thích ý tưởng này và bắt đầu tự hỏi tại sao nó dường như được sử dụng khá ít?

Nó trông giống như một cách xử lý thanh lịch với tất cả các kịch bản mà về cơ bản bạn muốn biết liệu điều gì đó đúng hay sai nhưng bạn có thể quan tâm đến một số thông tin bổ sung mà bạn có thể xác định mà không cần xác định đối tượng trả lại tùy chỉnh hoặc sử dụng chức năng gọi lại được chuẩn bị chấp nhận nhiều thông số hơn. Bằng cách này, bạn giữ lại một chữ ký hàm rất phổ quát mà không ảnh hưởng đến khả năng trả về dữ liệu phức tạp hơn.

Có 3 đối số chống lại nó mà tôi có thể tưởng tượng:

  1. Có một chút không phổ biến / bất ngờ khi có thể tốt hơn cho mọi giao diện rõ ràng và không khó khăn.
  2. Đây có thể là một đối số người rơm, nhưng với một chút trường hợp cạnh, tôi có thể tưởng tượng nó lặng lẽ tác động trở lại trong một số trình tối ưu hóa JS, uglifier, VM hoặc sau khi thay đổi đặc tả ngôn ngữ dọn dẹp nhỏ, v.v.
  3. Có cách tốt hơn - ngắn gọn, rõ ràng và phổ biến - giống hệt nhau.

Vì vậy, câu hỏi của tôi là có bất kỳ lý do mạnh mẽ để tránh sử dụng Booleans với các thuộc tính bổ sung? Họ là một mẹo hay một điều trị?


Âm mưu xoắn xuýt.

Trên đây là câu hỏi ban đầu trong vinh quang đầy đủ. Như Matthew Crumley và senevoldsen đều chỉ ra rằng nó dựa trên một tiền đề sai (giả?). Trong truyền thống JS tốt, những gì Modernizr làm là một trò lừa ngôn ngữ và một thứ bẩn thỉu. Nó hiểu được rằng JS có một bool nguyên thủy, nếu được đặt thành false sẽ vẫn sai ngay cả sau khi TRYING để thêm đạo cụ (không thành công) và một đối tượng Boolean có thể có đạo cụ tùy chỉnh nhưng là một đối tượng luôn luôn đúng. Modernizr trả về boolean false hoặc một đối tượng Boolean trung thực.

Câu hỏi ban đầu của tôi cho rằng thủ thuật hoạt động khác nhau và vì vậy hầu hết các câu trả lời phổ biến đều xử lý khía cạnh tiêu chuẩn mã hóa (hoàn toàn hợp lệ). Tuy nhiên, tôi thấy các câu trả lời gỡ rối toàn bộ thủ thuật hữu ích nhất (và cũng là lý lẽ cuối cùng chống lại việc sử dụng phương pháp này) vì vậy tôi chấp nhận một trong số chúng. Cảm ơn tất cả những người tham gia!


35
Mở rộng kiểu boolean là một wtf cổ điển .
hlovdal

7
Lưu ý rằng trong JS, họ có thể vừa trả về nullnếu không được hỗ trợ và một loạt các định dạng nếu có. Một danh sách được coi là trung thực trong JS và nulllà giả mạo.
jpmc26


3
Trước khi bạn trả lời câu hỏi này: trong javascript có sự khác biệt lớn giữa "boolean" và "Boolean". Chúng không giống nhau và bất kỳ câu trả lời nào không viết hoa Boolean đều không hợp lệ.
Pieter B

2
Đối với những người bị choáng váng khi nhìn thấy thứ gì đó như thế này trong tự nhiên, trong một thư viện phổ biến như Modernizr, đây là mã có liên quan từ GitHub của họ: github.com/Modernizr/Modernizr/blob/ tựa
Chris Nielsen

Câu trả lời:


38

Ngoài các nguyên tắc thiết kế chung, như trách nhiệm đơn lẻ và ít gây ngạc nhiên nhất, còn có một lý do cụ thể về JavaScript mà đó không phải là ý tưởng hay: có một sự khác biệt rất lớn giữa một booleanBooleantrong JavaScript ngăn nó hoạt động trong trường hợp chung.

booleanlà một kiểu nguyên thủy, không phải là một đối tượng và không thể có các thuộc tính tùy chỉnh. Biểu hiện như true.toString()công việc vì đằng sau hậu trường, nó biến thành (new Boolean(true)).toString().

Boolean(với số vốn B) một đối tượng, nhưng có rất ít công dụng tốt và được sử dụng như một mục tiêu booleanchắc chắn không phải là một trong số chúng. Lý do cho điều đó là, mọi thứ đều Boolean"đúng", bất kể giá trị của nó là gì , bởi vì tất cả các đối tượng được chuyển đổi thành truetrong bối cảnh boolean. Ví dụ: thử điều này:

var answer = new Boolean(false);
if (answer) {
  console.log("That was unexpected.");
}

Vì vậy, nói chung, không có cách nào để thêm các thuộc tính vào boolean trong JavaScript mà vẫn cho phép nó hoạt động theo cách logic. Modernizr có thể thoát khỏi nó bởi vì các thuộc tính duy nhất thêm vào các giá trị "true", loại công việc mà bạn mong đợi (nghĩa là chúng hoạt động trong các câu lệnh if). Nếu video hoàn toàn không được hỗ trợ, Modernizr.videosẽ là một thực tế boolean(có giá trị false) và không thể có các thuộc tính được thêm vào nó.


18
Tôi thấy cách tiếp cận của Modernizr khá kỳ quặc, vì cho rằng chỉ có một đối tượng với các thuộc tính đã được đánh giá truetrong một điều kiện. Tại sao rõ ràng sử dụng một Boolean?
Arturo Torres Sánchez

Cảm ơn rất nhiều cho một cuộc tranh luận kỹ thuật âm thanh. Có vẻ như bài kiểm tra nhanh của tôi đã bị lỗi: jsbin.com/hurebi/3/edit?js,console . Ngay cả sau khi thêm đạo cụ tùy chỉnh vào falsenó, cả 'sai' và giả ( =====hoạt động như) NHƯNG thực sự bạn không thể thêm đạo cụ vào bool nguyên thủy. Sự khác biệt giữa Bool và bool khiến tôi rõ ràng.
konrad

@ ArturoTorresSánchez vì cách họ làm điều đó, các giá trị trả về trên danh nghĩa cùng loại.
Jared Smith

1
@ ArturoTorresSánchez đó là lý do tại sao tôi đã thêm vòng loại "trên danh nghĩa": P
Jared Smith

1
@konrad Để tham khảo, theo mặc định, JavaScript sẽ giả vờ cho phép bạn thêm thuộc tính vào nguyên thủy bằng cách không phàn nàn khi bạn cố gắng thực hiện. Sử dụng chế độ nghiêm ngặt sẽ khắc phục điều đó và ném TypeErrornếu bạn cố thêm thuộc tính (xem jsbin.com/yovasafibo/edit?js,console ).
Matthew Crumley

59

Xin chúc mừng, bạn đã phát hiện ra các đối tượng. Lý do không làm điều này được gọi là nguyên tắc ít ngạc nhiên nhất . Bị bất ngờ bởi một thiết kế không phải là một điều tốt.

Không có gì sai khi kết hợp thông tin này với nhau nhưng tại sao bạn lại muốn giấu nó trong Bool? Đặt nó trong một cái gì đó bạn mong muốn có tất cả thông tin này. Bao gồm cả Bool.


1
LOL có tôi đã đề cập đến đối tượng như là một thay thế rõ ràng trong câu hỏi của tôi. Nguyên tắc ít gây ngạc nhiên là một điểm tốt mặc dù với các đối tượng gõ yếu của JS ít gây ngạc nhiên hơn nhưng vẫn khó hiểu và dù sao bạn cũng cần kiểm tra tài liệu. Về cách sử dụng, Modernizr là một ví dụ điển hình: bạn có một bộ thử nghiệm lớn với kết quả đúng / sai đồng nhất và chỉ bây giờ và sau đó bạn cần truyền thêm thông tin - thậm chí có thể cần những thứ đó đến sau để khi nào bạn có thể thực hiện các thay đổi đột phá cho toàn bộ thư viện tạo ra các trình bao bọc chủ yếu là dự phòng xung quanh booleans hoặc bạn tăng cường bool. IMO không quá ngu ngốc.
konrad

1
Thêm một chút về cách sử dụng. Nếu bạn muốn trả về một giá trị boolean, bạn có thể chuyển tất cả các hàm để liệt kê các hoạt động như bất kỳ (), all (), filter () một cách dễ dàng. Nó bao quanh việc thiếu kiểu gõ mạnh hoặc giao diện chính thức trong JS với chi phí hơi khác thường - dường như cho đến nay vẫn là đối số chính chống lại nó.
konrad

1
"Không thông thường" dường như không phải là một cuộc tranh cãi mạnh mẽ đối với tôi.
Robert Harvey

Tôi đã chỉnh sửa câu hỏi. Đây là nguyên tắc ít ngạc nhiên nhất. :-)
konrad

16

Đối số chính mà tôi chống lại nó là, nguyên tắc trách nhiệm duy nhất , một boolean chỉ nên nói nếu một cái gì đó là true, hoặc falsetại sao hoặc làm thế nào hoặc bất kỳ điều gì khác. Tôi tin tưởng và thực hành vững chắc rằng các đối tượng khác nên được sử dụng để truyền đạt thông tin đó hoặc bất kỳ thông tin nào khác.


bạn có nghĩa là boolean hoặc Boolean (có chữ B viết hoa) trong javascript có sự khác biệt.
Pieter B

Nhưng nếu bạn có một đối tượng xác định điều này và một số thứ khác thì nó có thể vi phạm các nguyên tắc tương tự không?
Casey

1
@Casey Không vì mục đích của đối tượng đó sẽ khác với boolean ban đầu. Và nó sẽ chỉ có một trách nhiệm, để truyền đạt trạng thái và lý do của một giao dịch, là một ví dụ.
J. Pichardo

1
@ Vấn đề không phải là bản thân việc chứa thông tin này là vi phạm SRP. Nó chỉ trở thành một vấn đề khi kết hợp với trách nhiệm mà một boolean đã có - đại diện cho đúng hay sai. BooleanMặc dù vậy, các shenanigans của JavaScript .
Jacob Raihle

10

Vì toàn bộ lý do nó được gọi là giá trị boolean là thực tế nó là đúng hoặc sai, tôi không thích ý tưởng này, vì bạn gần như làm suy yếu toàn bộ mục đích của nó từ wikipedia

Trong khoa học máy tính, kiểu dữ liệu Boolean là kiểu dữ liệu, có hai giá trị (thường được ký hiệu là đúng và sai), nhằm đại diện cho các giá trị thật của logic và đại số Boolean .

(khuôn của tôi)


1
đúng, nhưng sự cần thiết có thể ra lệnh khác
svarog

8
@svarog sự cần thiết duy nhất tôi có thể thấy là người thiết kế mã không có kỹ năng. Nếu bạn cần trả về bool một cái gì đó khác, hãy biến nó thành một lớp, hoặc tuple, hoặc danh sách, hoặc bất cứ thứ gì khác phù hợp với mã cụ thể.
MatthewRock

nếu bạn quay trở lại có
svarog

Tôi nghĩ rằng câu hỏi là về đối tượng Boolean không phải là nguyên thủy boolean. Đối tượng không phải là một giá trị.
Pieter B

1
Nếu nó có thể lấy một giá trị khác hơn là đúng hoặc sai, thì đó cũng không phải là giá trị boolean. Mà, cho tên, là ngớ ngẩn.
Vô dụng

2

Chỉ vì bạn không có nghĩa là bạn nên, trong JS, bạn có thể đính kèm khá nhiều thuộc tính vào bất kỳ đối tượng nào (Bao gồm cả Booleans)

Làm thế nào đó là một điều xấu?

Một mặt, bạn có thể đính kèm nhiều dữ liệu không liên quan hơn vào Boolean (theo ví dụ của bạn), điều mà một nhà phát triển khác sẽ không mong đợi vì tại sao nó phải ở đó?! bool chỉ cho đúng và sai.

Một điểm đối với nó là đính kèm một số thuộc tính hữu ích có liên quan có thể giúp bạn xử lý giá trị boolean ( Java thực hiện điều đó ).

Ví dụ: bạn có thể đính kèm một hàm chuyển đổi giá trị boolean thành một chuỗi, một dirtycờ biến thành đúng nếu giá trị được thay đổi, trình theo dõi và các cuộc gọi lại sự kiện có thể kích hoạt khi giá trị được thay đổi, v.v.

nhưng Boolean được trả về (Bool là đối tượng lớp đầu tiên trong JS) có các thuộc tính chỉ định định dạng nào được hỗ trợ

Nghe có vẻ như một thứ gì đó không nên được lưu trữ trong Boolean, mà là sử dụng một bộ booleans hoặc một bộ thuộc tính có booleans bên trong chúng. Tôi nghĩ rằng một cách tiếp cận tốt hơn sẽ là trả về một đối tượng với tất cả các định dạng và chi tiết hỗ trợ.

{
    isSomethingSupported: true,
    isSomethingElseSupported: false,
    ....
}

1
bạn có nghĩa là boolean hoặc Boolean (với vốn B)?
Pieter B

1

Bạn không thể tạo booleans với các thuộc tính tùy chỉnh trong JavaScript. Lỗi sau (ít nhất là trong FF):

    var x = false;
    x.foo = "bar";
    console.log(x.foo);

Bạn có thể sử dụng hoặc thừa kế từ Boolean, nhưng như Matthew Crumley nói rằng nó mang lại kết quả khác nhau. Booleanloại Object . Khi JS cần giá trị boolean của một biểu thức, nó chuyển đổi bằng cách sử dụng hàm đặc tả ToBoolean, điều này bắt buộc Objectluôn luôn cho kết quả true. Do đó, giá trị new Boolean(false)ước tính true! Bạn có thể xác minh điều này trong ví dụ này: https://jsfiddle.net/md7abx5z/3/ .

Lý do duy nhất nó hoạt động cho Modernizr là ngẫu nhiên. Họ chỉ tạo ra một Booleanđối tượng khi điều kiện là đúng. Khi họ đánh giá sai họ chỉ trở lại bình thường false. Vì vậy, nó hoạt động bởi vì chúng chỉ trả về Boolean các đối tượng khi kết quả là đúng và không bao giờ khi nó là sai.


1

Tôi hiểu bối cảnh đã thay đổi, nhưng tôi muốn trả lời câu hỏi ban đầu mà tôi đọc là sử dụng JS làm ví dụ, nhưng không giới hạn ở chỉ JS.

Thêm thuộc tính vào boolean, sẽ không thành vấn đề NẾU các thuộc tính có liên quan đến true / false, không phải với biến giữ giá trị. Chẳng hạn, việc thêm phương thức toYesNoString sẽ ổn, việc thêm sốOfChildren vào giá trị hasChildren là không, và cũng không có câu hỏi nào Sinh viên bị lừa. Không có nhiều thứ bạn có thể thêm vào một boolean, ngoài các lần lặp chuỗi khác nhau, thuộc tính duy nhất mà tôi có thể nghĩ về điều đó sẽ có ý nghĩa là bản gốcExpression. Nhưng thêm vào đó không nhất thiết là một ý tưởng tồi trong lý thuyết.


0

Nếu tôi nhìn vào mã thì đây không thực sự là về việc cung cấp các thuộc tính tùy chỉnh Boolean mà là về một phương thức có các phương thức trả về với các chữ ký khác nhau.

Nếu nó sai thì bạn nhận được sai nguyên thủy và nếu nó đúng thì nó trả về một đối tượng mà theo định nghĩa sẽ được hiểu là đúng trong javascript.

Vì vậy, theo tôi, câu hỏi của bạn không nên là liệu có nên cung cấp các thuộc tính tùy chỉnh của Boolean hay không nhưng liệu có nên sử dụng các phương thức có nhiều chữ ký trả lại hay không.


0

Trong ví dụ đã cho, bạn không thể trả về một mảng của tất cả các định dạng video được hỗ trợ?

  • Mảng trống có nghĩa là "không hỗ trợ định dạng video ", theo nghĩa là "không hỗ trợ video ".
  • Mặt khác, nếu bất kỳ định dạng video nào được hỗ trợ, thì rõ ràng video nói chung được hỗ trợ.

Ít nhất tôi sẽ nói rằng việc sử dụng mảng ít gây ngạc nhiên hơn so với việc có "booleans tùy chỉnh".

Trong Javascript, một mảng trống thậm chí còn coi falsy , trong khi một mảng không có sản phẩm nào là truthy , vì vậy với một chút may mắn bạn chỉ có thể chuyển sang mảng và mọi thứ sẽ làm việc giống như trước chỉnh sửa Nope, ngớ ngẩn tôi nghĩ tôi có thể nhớ truthiness của các đối tượng trong JavaScript: P


Một mảng trống không đánh giá là sai trong câu lệnh if. if ([]) console.log ('không sai'); in 'không sai' trong Chrome chẳng hạn. typeof [] === 'object' để không có mảng trống nào không sai. Xem developer.mozilla.org/en-US/docs/Glossary/Truthy để tham khảo.
joshp

@joshp oops, bạn nói đúng, xấu của tôi. Cố định
daniero

Mặc dù, tôi không chắc chắn rằng loại hình này chứng minh bất cứ điều gì; ""có loại "string"nhưng nó thực sự là giả
daniero

1
Mặt khác, [].lengthlà falsey nếu chiều dài là 0, không gõ nhiều hơn, và theo tôi là một dấu hiệu tốt hơn về ý định hơn if([])là ngay cả khi điều đó có hiệu quả.
IllusiveBrian

@daniero Điểm về typeof [] === 'object' là mọi đối tượng đều là sự thật, thậm chí là Boolean mới (sai). Một số loại nguyên thủy (ví dụ: chuỗi "" và số 0) là giả mạo, nhưng chúng không phải là Đối tượng theo như liên quan đến loại. Đó chỉ là một cách khác để nhớ. Đó không phải là về việc chứng minh bất cứ điều gì. Bằng chứng là trong đặc điểm kỹ thuật hoặc các bài kiểm tra, tùy theo bạn thích.
joshp
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.