Um JS Boolean tendo propriedades customizadas é uma prática ruim?

41

No JS, você pode retornar um Booleano com propriedades personalizadas. Por exemplo. quando os testes do Modernizr para suporte a vídeo retornam true ou false , mas o booleano retornado (Bool é um objeto de primeira classe no JS) possui propriedades que especificam quais formatos são suportados. No começo, me surpreendeu um pouco, mas depois comecei a gostar da ideia e comecei a me perguntar por que ela parece ser usada com parcimônia?

Parece uma maneira elegante de lidar com todos os cenários em que você basicamente quer saber se algo é verdadeiro ou falso, mas pode estar interessado em algumas informações adicionais que você pode definir sem definir um objeto de retorno personalizado ou usando um retorno de chamada função preparada para aceitar mais parâmetros. Dessa forma, você retém uma assinatura de função muito universal sem comprometer a capacidade de retornar dados mais complexos.

Existem 3 argumentos contra isso que eu posso imaginar:

  1. É um pouco incomum / inesperado quando provavelmente é melhor para qualquer interface ser clara e não complicada.
  2. Isso pode ser um argumento do tipo "homem de palha", mas com um pouco de margem de manobra, posso imaginar que ele sai silenciosamente em algum otimizador JS, uglifier, VM ou após uma pequena alteração na especificação de linguagem de limpeza, etc.
  3. Existe uma maneira melhor - concisa, clara e comum - de fazer exatamente o mesmo.

Então, minha pergunta é se existem razões strongs para evitar o uso de booleanos com propriedades adicionais? Eles são um truque ou um deleite?

O enredo distorce o aviso.

Acima está a pergunta original em toda a glória. Como Matthew Crumley e senevoldsen apontaram, é baseado em uma premissa falsa (falsamente?). Na boa tradição de JS, o que Modernizr faz é um truque de linguagem e um sujo. Tudo se resume a JS ter um bool primitivo que se definido como false permanecerá falso mesmo depois de tentar adicionar adereços (que falha silenciosamente) e um objeto booleano que pode ter adereços personalizados, mas ser um objeto é sempre verdadeiro. O Modernizr retorna um objeto booleano falso ou Booleano.

Minha pergunta original assumiu que o truque funciona de maneira diferente e, portanto, as respostas mais populares lidam com o aspecto dos padrões de codificação (perfeitamente válidos). No entanto, eu acho as respostas desmentindo todo o truque mais útil (e também os argumentos finais contra o uso do método), então estou aceitando um deles. Obrigado a todos os participantes!

    
por konrad 09.01.2017 / 05:57
fonte

9 respostas

38

Além dos princípios gerais de design, como responsabilidade única e, pelo menos, surpresa, há um motivo específico do JavaScript que não é uma boa ideia: há uma enorme diferença entre um boolean e Boolean no JavaScript que o impede de trabalhar no caso geral.

boolean é um tipo primitivo, não um objeto e não pode ter propriedades personalizadas. Expressões como true.toString() funcionam porque nos bastidores se transforma em (new Boolean(true)).toString() .

Boolean (com um B maiúsculo) é um objeto, mas tem pouquíssimos bons usos, e ser usado como boolean definitivamente não é um deles. A razão para isso é que todo Boolean é "verdadeiro", independentemente de seu valor , porque todos os objetos são convertidos em true em um contexto booleano. Por exemplo, tente isto:

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

Portanto, em geral, não há como adicionar propriedades a um booleano em JavaScript que ainda permita que ele se comporte de maneira lógica. O Modernizr pode se dar bem com isso, porque as únicas propriedades adicionais são adicionadas aos valores "verdadeiros", que funcionam como você esperaria (isto é, eles funcionam em instruções if). Se o vídeo não for compatível, Modernizr.video será um boolean real (com o valor false ) e não poderá ter propriedades adicionadas a ele.

    
por 09.01.2017 / 17:55
fonte
59

Parabéns, você descobriu objetos. O motivo para não fazer isso é chamado de princípio de menor espanto . Ser surpreendido por um design não é uma coisa boa.

Não há nada de errado em agrupar essas informações, mas por que você deseja ocultá-las em um Bool? Coloque em algo que você esperaria ter toda essa informação. Bool incluído.

    
por 09.01.2017 / 06:43
fonte
16

O principal argumento que tenho contra ele é o princípio de responsabilidade única , um booleano só deve dizer se algo é true ou false , não porque ou como ou qualquer outra coisa. É minha firme convicção e prática que outros objetos devem ser usados para comunicar essa ou qualquer outra informação.

    
por 09.01.2017 / 06:44
fonte
10

Como toda a razão de ser chamado de valor booleano é o fato de ser verdadeiro ou falso, eu não gosto da idéia, já que você praticamente prejudica todo o seu propósito. de wikipedia

In computer science, the Boolean data type is a data type, having two values (usually denoted true and false), intended to represent the truth values of logic and Boolean algebra.

(meu negrito)

    
por 09.01.2017 / 11:51
fonte
2

Só porque você pode não significa que você deve, em JS você pode muito bem anexar propriedades a qualquer objeto (booleanos incluídos)

Como isso é ruim?

Por um lado, você pode anexar dados mais irrelevantes a um booleano (por exemplo), algo que outro desenvolvedor não esperaria porque, por que deveria estar lá ?! Os bools são apenas verdadeiros e falsos.

Um ponto de contraponto para isso é anexar algumas propriedades úteis relevantes que podem ajudá-lo a lidar com o valor booleano ( Java faz isso ).

Por exemplo, você pode anexar uma função que converte o valor booleano em uma string, um sinal dirty que se tornou true se o valor foi alterado, watchers e callbacks de eventos que podem disparar quando o valor é alterado, etc. / p>

but the returned Boolean (Bool is first class object in JS) has properties specifying what formats are supported

Parece algo que não deve ser armazenado em um booleano, mas sim usando um conjunto de booleanos ou um conjunto de propriedades com booleanos dentro deles. Acho que uma abordagem melhor seria retornar um objeto com todos os formatos e detalhes de suporte.

{
    isSomethingSupported: true,
    isSomethingElseSupported: false,
    ....
}
    
por 09.01.2017 / 11:18
fonte
1

Você não pode fazer booleanos com propriedades personalizadas em JavaScript. O seguinte falha (pelo menos em FF):

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

Você pode usar ou herdar de Boolean, mas, como Matthew Crumley diz, isso dá resultados diferentes. Boolean é do tipo Object . Quando JS precisar do valor booleano de uma expressão, ele converterá usando a função de especificação ToBoolean , que exige que, para Object s, o resultado seja sempre true . Assim, o valor new Boolean(false) é avaliado como true ! Você pode verificar isso neste exemplo: link .

A única razão pela qual funciona para Modernizr é incidental. Eles criam apenas um objeto Boolean quando a condição é verdadeira. Quando eles avaliam false, eles retornam apenas false . Então funciona porque eles só retornam Boolean objetos quando o resultado é verdadeiro de qualquer maneira, e nunca quando é falso.

    
por 09.01.2017 / 18:39
fonte
1

Eu entendo que o contexto mudou, mas gostaria de responder à pergunta original que eu li usando JS como exemplo, mas não limitada a apenas JS.

Adicionar propriedades a um booleano, não seria um problema SE as propriedades tivessem algo a ver com o verdadeiro / falso, não com a variável mantendo o valor. Por exemplo, adicionar um método toYesNoString seria bom, adicionando um numberOfChildren a um valor hasChildren não, e nem questionariaMessed studentPassed. Não há muito que você possa adicionar a um booleano, a não ser por várias representações de string, a única propriedade que eu posso pensar que faria sentido é o originalExpression. Mas adicionar a isso não é necessariamente uma má ideia em teoria.

    
por 20.01.2017 / 03:17
fonte
0

Se eu olhar para o código, não se trata realmente de dar propriedades customizadas booleanas, mas de um método com métodos de retorno com assinaturas diferentes.

Se for falso, você obtém um falso primitivo e, se for verdade, ele retorna um objeto que, por definição, é interpretado como verdadeiro em javascript.

Então, na minha opinião, sua pergunta não deve ser se é uma boa ideia fornecer propriedades personalizadas booleanas, mas se é uma boa ideia ter métodos com várias assinaturas de retorno.

    
por 09.01.2017 / 19:06
fonte
0

No exemplo dado, você não poderia apenas retornar uma matriz de todos os formatos de vídeo suportados?

  • Uma matriz vazia significa "nenhum formato de vídeo suportado", o que significa "nenhum vídeo suportado".
  • Caso contrário, se qualquer vídeo formato for suportado, então, obviamente, vídeo é suportado em geral.

Eu diria, pelo menos, que usar array é um pouco menos surpreendente do que ter "booleans personalizados".

Em Javascript, uma matriz vazia é considerada falsy , enquanto uma matriz não-vazia é truthy , então com alguma sorte você pode simplesmente mudar para matrizes e tudo estaria funcionando como antes edite Não, boba eu por pensar que eu poderia lembrar da autenticidade dos objetos em JavaScript: P

    
por 09.01.2017 / 18:22
fonte