Czy Boolean JS mający niestandardowe właściwości jest złą praktyką?

41

W JS możesz zwrócić wartość logiczną o niestandardowych właściwościach. Na przykład. gdy Modernizr testuje obsługę wideo, zwraca truelub falseale zwrócony Boolean (Bool jest obiektem pierwszej klasy w JS) ma właściwości określające obsługiwane formaty. Z początku trochę mnie to zaskoczyło, ale potem spodobał mi się ten pomysł i zacząłem się zastanawiać, dlaczego wydaje się być stosowany raczej oszczędnie?

Wygląda to na elegancki sposób radzenia sobie ze wszystkimi scenariuszami, w których zasadniczo chcesz wiedzieć, czy coś jest prawdą czy fałszem, ale możesz być zainteresowany dodatkowymi informacjami, które możesz zdefiniować bez definiowania niestandardowego obiektu zwrotnego lub korzystania z funkcji wywołania zwrotnego przygotowanej do zaakceptuj więcej parametrów. W ten sposób zachowujesz bardzo uniwersalną sygnaturę funkcji bez uszczerbku dla możliwości zwracania bardziej złożonych danych.

Są 3 argumenty przeciwko temu, które mogę sobie wyobrazić:

  1. Jest to nieco rzadkie / nieoczekiwane, gdy prawdopodobnie lepiej jest, aby jakikolwiek interfejs był przejrzysty i nietrudny.
  2. Może to być argument o słomce, ale ponieważ jest to trochę skrajny przypadek, mogę sobie wyobrazić, że cicho odpiera niektóre optymalizatory JS, uglifier, VM lub po drobnej zmianie specyfikacji języka czyszczenia itp.
  3. Jest lepszy - zwięzły, jasny i powszechny - sposób robienia dokładnie tego samego.

Więc moje pytanie: czy są jakieś ważne powody, aby unikać używania booleanów z dodatkowymi właściwościami? Czy to podstęp, czy uczta?


Ostrzeżenie o zwrotach akcji.

Powyżej jest oryginalne pytanie w pełnej krasie. Jak zauważyli Matthew Crumley i senevoldsen, opiera się ono na fałszywej (falsy?) Przesłance. Zgodnie z tradycją JS Modernizr to sztuczka językowa i brudna. Sprowadza się to do tego, że JS ma prymitywną wartość bool, która jeśli ustawiona na false, pozostanie fałszywa nawet po próbie dodania rekwizytów (która kończy się niepowodzeniem) i obiekt logiczny, który może mieć niestandardowe rekwizyty, ale bycie obiektem jest zawsze zgodne z prawdą. Modernizr zwraca wartość logiczną false lub true Boolean.

Moje oryginalne pytanie zakładało, że sztuczka działa inaczej, więc najpopularniejsze odpowiedzi dotyczą (doskonale poprawnych) aspektów standardów kodowania. Jednak uważam, że odpowiedzi obalające całą sztuczkę są najbardziej pomocne (a także ostateczne argumenty przeciwko użyciu tej metody), więc akceptuję jedną z nich. Dziękujemy wszystkim uczestnikom!

konrad
źródło
35
Rozszerzanie typu logicznego jest klasycznym wtf .
hlovdal
7
Zauważ, że w JS mogliby po prostu powrócić, nulljeśli nie są obsługiwane, i tablicę formatów, jeśli tak. Lista jest uważana za prawdziwą w JS i nulljest fałszem.
jpmc26
3
Zanim odpowiesz na to pytanie: w javascript istnieje duża różnica między „boolean” a „Boolean”. Nie są tym samym, a każda odpowiedź, która nie wykorzystuje wartości logicznej, jest nieprawidłowa.
Pieter B
2
Dla tych z Was, którzy są oszołomieni, widząc coś takiego na wolności, w bibliotece tak popularnej jak Modernizr, oto odpowiedni kod z ich GitHub: github.com/Modernizr/Modernizr/blob/…
Chris Nielsen

Odpowiedzi:

38

Oprócz ogólnych zasad projektowania, takich jak pojedyncza odpowiedzialność i najmniej zaskakujące, istnieje specyficzny dla JavaScript przyczyna, dla której nie jest to dobry pomysł: istnieje ogromna różnica między a booleani BooleanJavaScript, która uniemożliwia działanie w ogólnym przypadku.

booleanjest typem pierwotnym, a nie obiektem i nie może mieć właściwości niestandardowych. Wyrażenia lubią true.toString()pracę, ponieważ za kulisami, okazuje się (new Boolean(true)).toString().

Boolean(z dużą literą B) jest przedmiotem, ale ma bardzo niewiele dobrych zastosowań, a używanie go jako booleanzdecydowanie nie jest jednym z nich. Powodem tego jest to, że każdy Booleanjest „prawdziwy”, niezależnie od jego wartości , ponieważ wszystkie obiekty są konwertowane na truekontekst boolowski. Na przykład spróbuj tego:

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

Ogólnie rzecz biorąc, nie ma możliwości dodania właściwości do wartości logicznej w JavaScript, która nadal pozwala zachować się w logiczny sposób. Modernizr może sobie z tym poradzić, ponieważ tylko dodaje właściwości do „prawdziwych” wartości, które działają tak, jak byś się spodziewał (tj. Działają w instrukcjach if). Jeśli wideo nie jest w ogóle obsługiwane, Modernizr.videobędzie rzeczywiste boolean(z wartością false) i nie będzie można do niego dodawać właściwości.

Matthew Crumley
źródło
18
Uważam, że podejście Modernizra jest dość dziwne, biorąc pod uwagę, że posiadanie tylko obiektu o właściwościach jest już truewarunkowe. Po co jawnie używać Boolean?
Arturo Torres Sánchez
Wielkie dzięki za solidny argument techniczny. Wygląda na to, że mój szybki test był wadliwy: jsbin.com/hurebi/3/edit?js,console . Nawet po dodaniu niestandardowych rekwizytów jest falseto zarówno „fałszywe”, jak i fałszywe ( ===i ==działa jako) ALE tak naprawdę nie można dodawać rekwizytów do prymitywnego bool. Rozróżnienie między Boolem a boolem najwyraźniej mnie ucierpiało.
konrad
@ ArturoTorresSánchez, ponieważ sposób, w jaki to robią, wartości zwracane są nominalnie tego samego typu.
Jared Smith
1
@ ArturoTorresSánchez dlatego dodałem kwalifikator „nominalnie”: P
Jared Smith
1
@konrad Dla odniesienia, JavaScript domyślnie udaje, że pozwala dodawać właściwości do prymitywów, nie narzekając przy próbie zrobienia tego. Użycie trybu ścisłego to naprawi i wyrzuci, TypeErrorjeśli spróbujesz dodać właściwość (zobacz jsbin.com/yovasafibo/edit?js,console ).
Matthew Crumley,
59

Gratulacje, odkryłeś przedmioty. Powód, aby tego nie robić, nazywa się zasadą najmniejszego zdziwienia . Zaskoczenie projektem nie jest dobrą rzeczą.

Nie ma nic złego w łączeniu tych informacji, ale dlaczego chcesz ukryć je w Bool? Umieść to w czymś, czego można oczekiwać od wszystkich tych informacji. Bool w zestawie.

candied_orange
źródło
1
LOL tak Wspomniałem o obiekcie jako oczywistą alternatywę w moim pytaniu. Zasada najmniejszego zdziwienia jest słuszna, nawet jeśli przy słabych czcionkach JS obiekty są mniej zaskakujące, ale wciąż mylące i i tak trzeba sprawdzać dokumenty. Jeśli chodzi o użycie Modernizr jest dobrym przykładem: masz duży zestaw testów z jednolitym wynikiem prawda / fałsz i tylko od czasu do czasu musisz przekazać więcej informacji - być może nawet potrzeba tych później, więc kiedy to zrobisz, możesz albo dokonuj przełomowych zmian w całej bibliotece, tworząc głównie zbędne owijki wokół booleanów lub poprawiając bool. IMO nie takie głupie.
konrad
1
Trochę więcej na temat użytkowania. Jeśli trzymasz się zwracania wartości logicznej, możesz łatwo przekazać wszystkie funkcje do list operacji takich jak any (), all (), filter (). Omija brak silnego pisania lub formalnych interfejsów w JS kosztem bycia nieco niekonwencjonalnym - co do tej pory wydaje się być głównym argumentem przeciwko niemu.
konrad
1
„Niekonwencjonalny” nie wydaje mi się silnym argumentem.
Robert Harvey
Zredagowałem pytanie. Oto zasada najmniejszego zdziwienia. :-)
konrad
16

Głównym argumentem przeciwko trzymam to znaczy, że zasada jednej odpowiedzialności , logiczną powinien mówić tylko wtedy, gdy coś jest truealbo falsenie, dlaczego i w jaki sposób lub innych rzeczy. Jestem głęboko przekonany i praktykuję, że do przekazywania tej lub innych informacji należy używać innych przedmiotów.

J. Pichardo
źródło
masz na myśli boolean lub Boolean (z wielką literą B) w javascript?
Pieter B
Ale jeśli masz obiekt definiujący to i inne rzeczy, czy nie narusza to prawdopodobnie tych samych zasad?
Casey
1
@Casey Nie, ponieważ cel tego obiektu byłby inny niż oryginalny boolean. I miałby tylko jeden obowiązek, na przykład podać stan i przyczynę transakcji.
J. Pichardo,
1
@Casey problemem nie jest to, że samo zawieranie tych informacji stanowi naruszenie zasad SRP. Staje się to problemem tylko w połączeniu z odpowiedzialnością, którą ma już boolean - reprezentować prawdę lub fałsz. BooleanNiezależnie od shenaniganów JavaScript .
Jacob Raihle,
10

Ponieważ jedynym powodem, dla którego nazywa się to wartością logiczną, jest fakt, że jest to prawda lub fałsz, nie podoba mi się ten pomysł, ponieważ podważasz cały jego cel z wikipedii

W informatyce typ danych boolowskich to typ danych posiadający dwie wartości (zwykle oznaczane jako prawda i fałsz), przeznaczony do reprezentowania wartości prawdy logiki i algebry boolowskiej .

(moje pogrubienie)

Wyświetlana nazwa
źródło
1
słusznie, ale konieczność może dyktować inaczej
svarog
8
@svarog jedyną koniecznością, którą widzę, jest niewykwalifikowany projektant kodu. Jeśli chcesz zwrócić bool i coś innego, uczyń go klasą, krotką, listą lub czymkolwiek innym, co mieści się w danym kodzie.
MatthewRock,
jeśli wracasz tak
svarog
Myślę, że pytanie dotyczy obiektu logicznego, a nie prymitywów boolowskich. Obiekt nie jest wartością.
Pieter B
1
Jeśli może przyjmować wartość inną niż prawda lub fałsz, nie jest też wartością logiczną. Co, biorąc pod uwagę nazwę, jest głupie.
Bezużyteczne
2

Tylko dlatego, że nie oznacza to, że powinieneś, w JS możesz praktycznie dołączyć właściwości do dowolnego obiektu (w tym booleany)

Jak to źle?

Z jednej strony możesz dołączyć do Boolean więcej nieistotnych danych (na przykład), czego nie spodziewa się inny programista, ponieważ dlaczego miałby tam być ?! boole są tylko dla prawdy i fałszu.

Kontrapunktem jest dołączenie pewnych przydatnych przydatnych właściwości, które mogą pomóc ci poradzić sobie z wartością logiczną ( Java to robi ).

Na przykład możesz dołączyć funkcję, która konwertuje wartość logiczną na ciąg, dirtyflagę, która okazała się prawdą, jeśli wartość została zmieniona, obserwatory i wywołania zwrotne zdarzeń, które mogą zostać uruchomione, gdy wartość zostanie zmieniona itp.

ale zwrócony Boolean (Bool jest obiektem pierwszej klasy w JS) ma właściwości określające obsługiwane formaty

To brzmi jak coś, co nie powinno być przechowywane w logicznej wartości logicznej, ale raczej przy użyciu zestawu wartości logicznych lub zestawu właściwości z wartościami logicznymi wewnątrz nich. Myślę, że lepszym rozwiązaniem byłoby zwrócenie obiektu ze wszystkimi formatami i szczegółami wsparcia.

{
    isSomethingSupported: true,
    isSomethingElseSupported: false,
    ....
}
svarog
źródło
1
masz na myśli boolean lub boolean (z dużą literą B)?
Pieter B
1

Nie można tworzyć boolanów z własnymi właściwościami w JavaScript. Następujące błędy (przynajmniej w FF):

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

Możesz użyć lub odziedziczyć po Boolean, ale jak mówi Matthew Crumley, daje to inne wyniki. Booleanjest typu Object . Gdy JS potrzebuje wartości logicznej wyrażenia, konwertuje za pomocą funkcji specyfikacji ToBoolean, która nakazuje, aby dla Objects zawsze wynik był zawsze true. Tak więc wartość new Boolean(false)ocenia się na true! Możesz to sprawdzić w tym przykładzie: https://jsfiddle.net/md7abx5z/3/ .

Jedyny powód, dla którego działa on dla Modernizr, jest przypadkowy. Tworzą obiekt tylko Booleanwtedy, gdy warunek jest spełniony. Kiedy oceniają fałsz, po prostu powracają false. To działa, ponieważ zwracają Boolean obiekty tylko wtedy, gdy wynik był i tak prawdziwy, a nigdy, gdy jest to fałsz.

senevoldsen
źródło
1

Rozumiem, że kontekst się zmienił, ale chciałbym odpowiedzieć na oryginalne pytanie, które przeczytałem jako przykład JS, ale nie tylko JS.

Dodanie właściwości do wartości logicznej nie stanowiłoby problemu, JEŻELI właściwości miałyby coś wspólnego z wartością prawda / fałsz, a nie ze zmienną przechowującą wartość. Na przykład dodanie metody toYesNoString byłoby w porządku, dodanie wartości numberOfChildren do wartości hasChildren nie jest, i żadne z nich nie zadałoby pytań Missed studentPassed. Nie ma wiele rzeczy, które można dodać do wartości logicznej, oprócz różnych powtórzeń ciągów, jedyną właściwością, o której myślę, że ma sens, jest originalExpression. Ale dodanie do tego niekoniecznie jest złym pomysłem w teorii.

jmoreno
źródło
0

Jeśli spojrzę na kod, tak naprawdę nie chodzi tu o podanie niestandardowych właściwości Boolean, ale o metodę, która ma metody zwracania z różnymi podpisami.

Jeśli jest to fałsz, to otrzymujesz prymitywny fałsz, a jeśli to prawda, zwraca obiekt, który z definicji jest interpretowany jako prawda w javascript.

Moim zdaniem Twoim pytaniem nie powinno być to, czy warto nadać logiczne właściwości niestandardowe, ale czy warto mieć metody z wieloma podpisami zwrotnymi.

Pieter B.
źródło
0

Czy w podanym przykładzie nie można po prostu zwrócić tablicy wszystkich obsługiwanych formatów wideo?

  • Pusta tablica oznacza „brak obsługiwanych formatów wideo ”, co w kolejności oznacza „brak obsługiwanych filmów ”.
  • W przeciwnym razie, jeśli obsługiwany jest jakikolwiek format wideo , to oczywiście wideo w ogóle jest obsługiwane.

Powiedziałbym przynajmniej, że użycie tablicy jest nieco mniej zaskakujące niż posiadanie „niestandardowych booleanów”.

W Javascripcie pusta tablica jest nawet uważana za fałsz , podczas gdy niepusta tablica jest prawdziwa , więc przy odrobinie szczęścia możesz po prostu przełączyć się na tablice i wszystko działałoby tak jak przed edycją Nie, głupio, że myślałem, że pamiętam prawdę obiektów w JavaScript: P

daniero
źródło
Pusta tablica nie jest oceniana jako fałsz w instrukcji if. if ([]) console.log („nie fałsz”); na przykład drukuje „nie fałsz” w Chrome. typeof [] === „obiekt”, więc żadna pusta tablica nie jest fałszem. Więcej informacji można znaleźć na stronie developer.mozilla.org/en-US/docs/Glossary/Truthy .
joshp
@joshp ups, masz rację, mój zły. Naprawiono
daniero
Chociaż nie jestem pewien, czy coś takiego dowodzi czegokolwiek; ""ma typof, "string"ale tak naprawdę jest fałszem
daniero
1
Z drugiej strony, [].lengthjest falsey, jeśli długość jest 0, nie jest dużo więcej pisania, i moim zdaniem jest lepszym wskazaniem intencji niż if([])byłoby nawet, gdyby to zadziałało.
IllusiveBrian
@daniero Chodzi o typof [] === „obiekt”, że każdy obiekt jest zgodny z prawdą, nawet nowy logiczny (fałszywy). Niektóre typy pierwotne (np. Łańcuch „” i liczba 0) są fałszem, ale nie są obiektami, jeśli chodzi o typof. To tylko kolejny sposób na zapamiętanie. Nie chodzi o udowodnienie czegokolwiek. Dowód znajduje się w specyfikacji lub testach, w zależności od preferencji.
joshp