Por que essa linha é válida em javascript?
var a = 0[0];
Depois disso, a
é undefined
.
javascript
Michael M.
fonte
fonte
true[0]
ou""[0]
"0"
de umnew Number(0)
objeto.0[0]
retornar um valor0["toString"]
Isso é incrível, obrigado por apontar.Respostas:
Quando você faz isso
0[0]
, o interpretador JS transforma o primeiro0
em umNumber
objeto e tenta acessar a[0]
propriedade desse objeto que éundefined
.Não há erro de sintaxe porque a sintaxe de acesso à propriedade
0[0]
é permitida pela gramática do idioma neste contexto. Essa estrutura (usando termos da gramática Javascript) éNumericLiteral[NumericLiteral]
.A parte relevante da gramática de idiomas da seção A.3 da especificação ES5 ECMAScript é a seguinte:
Assim, pode-se seguir a gramática através desta progressão:
E, da mesma forma, também
Expression
pode eventualmente acontecerNumericLiteral
depois de seguir a gramática, vemos que isso é permitido:O que significa que
0[0]
é uma parte permitida da gramática e, portanto, nenhum SyntaxError.Em seguida, no tempo de execução, você poderá ler uma propriedade que não existe (ela será lida apenas
undefined
) desde que a fonte da qual você está lendo seja um objeto ou tenha uma conversão implícita em um objeto. E, um literal numérico realmente tem uma conversão implícita em um objeto (um objeto Number).Esse é um desses recursos frequentemente desconhecidos do Javascript. Os tipos
Number
,Boolean
eString
em Javascript são normalmente armazenados internamente como primitivos (não objetos full-blown). Trata-se de uma representação de armazenamento compacta e imutável (provavelmente feita dessa maneira para a eficiência da implementação). Mas, o Javascript deseja que você possa tratar essas primitivas como objetos com propriedades e métodos. Portanto, se você tentar acessar uma propriedade ou método que não seja diretamente suportado na primitiva, o Javascript coagirá temporariamente a primitiva em um tipo de objeto apropriado com o valor definido como o valor da primitiva.Quando você usa uma sintaxe semelhante a objeto em uma primitiva como
0[0]
, por exemplo , o intérprete reconhece isso como um acesso à propriedade em uma primitiva. Sua resposta a isso é pegar a primeira0
primitiva numérica e coagi-la em umNumber
objeto completo no qual ele pode acessar a[0]
propriedade. Nesse caso específico, a[0]
propriedade em um objeto Numberundefined
é por isso que esse é o valor que você obtém0[0]
.Aqui está um artigo sobre a conversão automática de uma primitiva em um objeto para fins de lidar com propriedades:
A Vida Secreta das Primitivas Javascript
Aqui estão as partes relevantes da especificação do ECMAScript 5.1:
9.10 CheckObjectCoercible
Lança TypeError se o valor for
undefined
ounull
, caso contrário, retornatrue
.11.2.1 Acessadores de propriedades
Uma parte operacional para esta pergunta é a etapa 5 acima.
8.7.1 GetValue (V)
Isso descreve como quando o valor que está sendo acessado é uma referência de propriedade, ele chama
ToObject(base)
para obter a versão do objeto de qualquer primitiva.9.9 ToObject
Este descreve como
Boolean
,Number
eString
primitivas são convertidos para uma forma de objecto com o [[PrimitiveValue]] propriedade interno conjunto em conformidade.Como um teste interessante, se o código fosse assim:
Ainda não jogaria um SyntaxError no momento da análise, pois isso é tecnicamente sintaxe legal, mas seria jogar um TypeError em tempo de execução quando você executar o código, pois quando o acima da lógica Propriedade Accessors é aplicada ao valor de
x
, ele irá chamarCheckObjectCoercible(x)
ou chamadaToObject(x)
que ambos lançarão um TypeError sex
fornull
ouundefined
.fonte
0[1,2]
também é válido, o que isso significa? (I atualizar a questão)null
ouundefined
esteja totalmente correta, mesmo que essas propriedades não existam.0[2]
1,2
mas retorna 2. #Como a maioria das linguagens de programação, o JS usa uma gramática para analisar seu código e convertê-lo em um formato executável. Se não houver uma regra na gramática que possa ser aplicada a um pedaço específico de código, ele lançará um SyntaxError. Caso contrário, o código é considerado válido, não importa se faz sentido ou não.
As partes relevantes da gramática JS são
Como
0[0]
está em conformidade com essas regras, é considerada uma expressão válida . Se está correto (por exemplo, não gera um erro no tempo de execução) é outra história, mas sim. É assim que o JS avalia expressões comosomeLiteral[someExpression]
:someExpression
(que pode ser complexo arbitrário)Number
, strings =>String
etc)get property
operação no resultado (2) com o nome da propriedade resultado (1)Então
0[0]
é interpretado comoAqui está um exemplo de uma expressão válida , mas incorreta :
É analisado corretamente, mas no tempo de execução, o intérprete falha na etapa 2 (porque
null
não pode ser convertido em um objeto) e gera um erro em tempo de execução.fonte
var x = null; var a = x[0];
não gera um erro de sintaxe, mas gera um TypeError em tempo de execução.0[0]
para devolver um valor em vez de indefinidaHá situações em que você pode subscrever validamente um número em Javascript:
Embora não seja imediatamente aparente o motivo pelo qual você deseja fazer isso, a inscrição em Javascript é equivalente ao uso de notação pontilhada (embora a notação de ponto limite o uso de identificadores como chaves).
fonte
(0).toString
(sem chamar a função). É uma propriedade do tipo de número.0
propriedade ser acessada e, uma vez que não existe,undefined
é mais correto, conforme explicado em jfriend00.0[0]
retornará indefinida. É provável que ele vai, mas ele não tem que ser o casoGostaria apenas de observar que essa sintaxe válida não é de forma alguma exclusiva do Javascript. A maioria dos idiomas terá um erro de tempo de execução ou um erro de tipo, mas isso não é o mesmo que um erro de sintaxe. O Javascript escolhe retornar indefinido em muitas situações em que outro idioma pode gerar uma exceção, inclusive ao inscrever um objeto que não possui uma propriedade com o nome fornecido.
A sintaxe não conhece o tipo de uma expressão (mesmo uma expressão simples como um literal numérico) e permitirá que você aplique qualquer operador a qualquer expressão. Por exemplo, tentar subscrever
undefined
ounull
causar umTypeError
em Javascript. Não é um erro de sintaxe - se isso nunca for executado (estando no lado errado de uma instrução if), não causará problemas, enquanto um erro de sintaxe é, por definição, sempre capturado no tempo de compilação (eval, Function, etc. , todos contam como compilação).fonte
Porque é uma sintaxe válida e até mesmo um código válido para ser interpretado. Você pode tentar acessar qualquer propriedade de qualquer objeto (e, neste caso, 0 será convertido em um objeto Number) e fornecerá o valor, se existir, caso contrário, indefinido. Tentar acessar uma propriedade de undefined não funciona, no entanto, 0 [0] [0] resultaria em um erro de tempo de execução. Isso ainda seria classificado como sintaxe válida. Há uma diferença entre o que é sintaxe válida e o que não causará erros de tempo de execução / compilação.
fonte
Não apenas a sintaxe é válida, mas o resultado não precisa ser o
undefined
mesmo na maioria, se não em todos os casos sãos. JS é uma das linguagens orientadas a objetos mais puras. A maioria das linguagens OO são orientadas a classes, no sentido de que você não pode alterar a forma (está ligada à classe) do objeto uma vez criado, apenas o estado do objeto. Em JS, você pode alterar o estado e a forma do objeto, e isso é feito com mais frequência do que você pensa. Essa capacidade cria um código bastante obscuro, se você o usar incorretamente. Os numerais são imutáveis, então você não pode alterar o objeto em si, nem o estado nem a forma, para que você possa fazerque é uma expressão de atribuição válida que retorna 1, mas na verdade não atribui nada. O numeral
0
é imutável. O que por si só é um tanto estranho. Você pode ter uma expressão de avaliação válida e correta (executável), que não atribua nada (*). No entanto, o tipo do numeral é um objeto mutável, para que você possa alterar o tipo, e as alterações entrarão em cascata na cadeia de protótipos.é claro que está muito longe da categoria de uso racional, mas o idioma é especificado para permitir isso, porque em outros cenários, estender os recursos dos objetos faz muito sentido. É como os plugins do jQuery se conectam ao objeto jQuery para dar um exemplo.
(*) Na verdade, atribui o valor 1 à propriedade de um objeto, no entanto, não há como referenciar esse objeto (transcendente) e, portanto, ele será coletado na passagem do GC da nexx
fonte
No JavaScript, tudo é objeto; portanto, quando o intérprete o analisa, ele trata 0 como um objeto e tenta retornar 0 como uma propriedade. O mesmo acontece quando você tenta acessar o 0º elemento de true ou "" (string vazia).
Mesmo se você definir 0 [0] = 1, ele definirá a propriedade e seu valor na memória, mas enquanto você acessa 0, ele trata como um número (não se confunda entre tratar como Objeto e número aqui.)
fonte