JavaScript, typeof, tipos e classes. Identificação de tipo dinâmico Erros associados a zonas mortas temporárias

Identificação de tipo dinâmico

Identificação de tipo dinâmico (RTTI) permite determinar o tipo de um objeto em tempo de execução. Acaba sendo útil por vários motivos. Em particular, por referência à classe base, você pode determinar com bastante precisão o tipo do objeto acessível por essa referência. A identificação de tipo dinâmico também permite que você verifique antecipadamente o sucesso do resultado da conversão de tipo, evitando uma exceção devido à conversão de tipo incorreta. Além disso, a identificação de tipo dinâmico é um componente importante da reflexão.

Para dar suporte à identificação de tipo dinâmico, o C# fornece três palavras-chave a: é, como e typeof. Cada uma dessas palavras-chave é discutida mais adiante.

é operador

O tipo específico de um objeto pode ser determinado usando o operador is. Segue abaixo sua forma geral:

expressão é tipo

onde expressão denota uma única expressão que descreve o objeto cujo tipo está sendo testado. Se a expressão for compatível ou do mesmo tipo que o tipo que está sendo testado, o resultado dessa operação será verdadeiro, caso contrário, será falso. Assim, o resultado será verdadeiro se a expressão for do tipo que está sendo testado de uma forma ou de outra. No operador is, ambos os tipos são definidos como compatíveis se forem do mesmo tipo ou se a conversão de referência, boxing ou unboxing for fornecida.

Veja a seguir um exemplo de uso do operador is:

usando sistema; namespace ConsoleApplication1 ( class Add ( ) class Sum: Add ( ) class Program ( static void Main() ( Add a = new Add(); Sum s = new Sum(); if (a is Add) Console.WriteLine("Variable a é do tipo Add"); if (s é Sum) Console.WriteLine("O tipo de variável s é herdado da classe Add"); Console.ReadLine(); ) ) )

como operador

Às vezes, uma conversão de tipo precisa ser feita em tempo de execução, mas não lançada se a conversão falhar, o que é perfeitamente possível com uma conversão de tipo. O operador as serve para esse propósito e tem a seguinte forma geral:

expressão como tipo

onde expressão denota uma única expressão que é conversível para o tipo especificado.

Se o resultado de tal conversão for bem-sucedido, uma referência ao tipo será retornada, caso contrário, uma referência nula. O operador as só pode ser usado para conversão de referência, identidade, boxing, unboxing. Em alguns casos, o operador as pode ser uma alternativa conveniente ao operador is. Como exemplo, considere o seguinte programa:

usando sistema; namespace ConsoleApplication1 ( class Add ( ) class Sum: Add ( ) class Program ( static void Main() ( Add a = new Add(); Sum s = new Sum(); // Realiza cast a = s as Add; if ( a != null) Console.WriteLine("Conversão bem-sucedida"); else Console.WriteLine("Erro ao converter"); Console.ReadLine(); ) ) )

O resultado da execução deste programa será uma conversão bem-sucedida.

JavaScript ou JS(em breve) não é uma linguagem fácil e desenvolvedores iniciantes não aprenderão sobre isso imediatamente. No começo eles aprendem o básico e tudo parece colorido e bonito. Indo um pouco mais fundo, há Matrizes JavaScript, objetos, retornos de chamada e tudo mais que muitas vezes impressiona.

Em JavaScript, é importante verificar o tipo de uma variável corretamente. Digamos que você queira saber se variável de matriz ou um objeto? Como verificar isso corretamente? Neste caso em particular, existem truques durante a verificação e é sobre isso que este post vai tratar. Vamos começar imediatamente.

Verificando o tipo de uma variável

Por exemplo, você precisa verificar se uma variável é um objeto, uma matriz, uma string ou um número. Você pode usar typeof para isso, mas nem sempre vai dizer a verdade, e eu vou te mostrar o porquê no exemplo abaixo.

Eu escrevi este exemplo para ilustrar porque typeof nem sempre é a escolha certa.

Var _comparison = ( string: "string", int: 99, float: 13.555, object: (hello: "hello"), array: new Array(1, 2, 3) ); // Retorna um array com as chaves do objeto var _objKeys = Object. keys(_comparison); for(var i = 0; i<= _objKeys.length - 1; i++) { // выведем в консоль тип каждой переменной console.log(typeof _comparson[_objKeys[i]]); }

Resultado da execução do código:

Objeto de objeto de número de string

Certo? - Claro que não. Existem dois problemas. Cada um deles será descrito em detalhes e uma solução proposta.

Primeiro problema: número flutuante, saída como número

Comparison.float não é um número e deve ser um float em vez de um número. Para corrigir isso, você pode criar uma função com um check como no código abaixo.

Var_floatNumber = 9,22; var_notFloatNumber = 9; console.log(isFloat(_floatNumber)); console.log(isFloat(_notFloatNumber)); console.log(isFloat("")); function isFloat(n)( return Number(n) === n && n % 1 !== 0; )

A função isFloat() verifica todos os valores para números de ponto flutuante. Primeiro verifique se a variável é igual n number (Number(n) === n) e se sim, então mais uma verificação é feita para divisão com resto e se houver resto, então um booleano é retornado ( verdadeiro ou falso) resultado (n % 1 !== 0).

No exemplo acima, ele retorna verdadeiro, falso e falso. O primeiro significado é flutuador type, o segundo não é - este é um número regular e o último é apenas uma string vazia que não se encaixa nas regras.

Segundo problema: o array foi definido como um objeto

No primeiro exemplo, o array é renderizado como um objeto, o que não é muito bom, porque às vezes você precisa usar esse tipo e nada mais.

Existem várias maneiras de testar uma variável para um tipo de matriz.

A primeira opção (boa opção). Verifique se os dados pertencem a um array usando instanceof().

Var data = new Array("olá", "mundo"); var isArr = data instanceof Array;

A segunda opção (boa opção). O método Array.isArray() retorna um valor booleano que dependerá se a variável é um array ou não ().

Var data = new Array("olá", "mundo"); var isArr = Array.isArray(data);

A terceira opção (a melhor, mas longa). Por conveniência, você pode tornar esse método uma função. Usando Object nós fazemos . Se o resultado de Object.prototype.toString.call(data) não for igual, então a variável não é uma matriz ().

Var data = new Array("olá", "mundo"); var isArr = Object.prototype.toString.call(data) == ""; console.log(isArr);

O último resultado como uma função de conveniência:

Função isArray(data) ( return Object.prototype.toString.call(data) == "" )

Agora você pode chamar as funções isArray() e definir um array ou algo como um argumento e ver o resultado.

Posfácio

O registro acabou por ser bastante grande do que se pretendia originalmente. Mas estou feliz com isso porque é conciso e claro o suficiente para descrever as dificuldades de validar variáveis ​​em JavaScript e como contorná-las.

Se você tiver alguma dúvida, poste-a abaixo deste post. Ficarei feliz em ajudar.

a = (b > 0) && (c + 1 != d); sinalizador = !(status = 0);

Tabela 14.5. Operadores lógicos

Descrição do Operador

! NÃO (inversão lógica)

&& AND (multiplicação booleana)

|| OU (adição lógica)

Tabela 14.6. Resultados da execução dos operadores AND e OR

Operando 1

Operando 2

Tabela 14.7. Resultados da execução da instrução NOT

obter operador typeof

Obter operador de tipo typeof retorna uma string descrevendo o tipo de dados do operando. O operando cujo tipo deve ser encontrado é colocado após este operador e entre parênteses:

s = typeof("str");

Como resultado dessa expressão, a variável s conterá a string "string" , denotando o tipo de string.

Todos os valores que o operador typeof pode retornar estão listados na Tabela 1. 14.8.

Tabela 14.8. Valores retornados pelo operador typeof

Tipo de dados

Cadeia de retorno

Corda

Numérico

Tabela 14.8 (final)

Tipo de dados

Cadeia de retorno

Lógico

Compatibilidade e conversão de tipo de dados

É hora de considerar duas questões mais importantes: compatibilidade de tipo de dados e conversão de um tipo para outro.

O que acontece quando você soma dois números? Isso mesmo - outro valor numérico. E se você adicionar um número e uma string? É difícil dizer... Aqui o JavaScript se depara com o problema da incompatibilidade de tipos de dados e tenta tornar esses tipos compatíveis convertendo um deles em outro. Ele primeiro tenta converter a string em um número e, se for bem-sucedido, executa a adição. Se não for bem-sucedido, o número será convertido em uma string e as duas strings resultantes serão concatenadas. Por exemplo, o script da Web na Listagem 14.6 converteria o valor da variável b quando adicionado à variável a em um tipo numérico; assim a variável c conterá o valor 23.

Listagem 14.6

var a, b, c, d, e, f; a = 11;

b = "12"; c = a + b;

d="JavaScript"; e = 2;

Mas como o valor da variável d não pode ser convertido em um número, o valor de e será convertido em uma string, e o resultado - o valor de f - se tornará igual a

Os valores booleanos são convertidos em valores numéricos ou de string, conforme apropriado. True será convertido para o número 1 ou a string "1" e false para 0 ou "0" . Por outro lado, o número 1 será convertido em true e o número 0 em false . Além disso, false será convertido

somos nulos e indefinidos.

Parte III. Comportamento da página da Web. Scripts da Web

Pode-se ver que o JavaScript se esforça para executar corretamente até mesmo expressões escritas incorretamente. Às vezes funciona, mas na maioria das vezes, as coisas não funcionam como planejado e, eventualmente, o script da Web é abortado porque um erro é encontrado em um local completamente diferente no script, na instrução absolutamente correta. Portanto, é melhor evitar tais incidentes.

Operador precedente

A última questão com a qual trataremos aqui é a precedência do operador. Como lembramos, a precedência afeta a ordem na qual os operadores de uma expressão são executados.

Seja a seguinte expressão:

Neste caso, primeiro será adicionado o valor de c ao valor da variável b, e em seguida será subtraído da soma 10. Os operadores desta expressão têm a mesma precedência e, portanto, são executados estritamente da esquerda para a direita.

Agora considere esta expressão:

Aqui, primeiro, o valor c será multiplicado por 10, e só então o valor b será adicionado ao produto resultante. O operador de multiplicação tem maior precedência do que o operador de adição, então a ordem "estritamente da esquerda para a direita" será violada.

Os operadores de atribuição têm a precedência mais baixa. É por isso que a expressão em si é avaliada primeiro e, em seguida, seu resultado é atribuído a uma variável.

NO Em geral, o princípio básico de execução de todas as instruções é o seguinte: primeiro, instruções com mais de prioridade máxima, e só então - operadores com um menor. Os operadores com a mesma precedência são executados na ordem em que aparecem (da esquerda para a direita).

NO aba. 14.9 lista todos os operadores que estudamos em ordem decrescente de precedência.

Tabela 14.9. Precedência do operador (em ordem decrescente)

Operadores

Descrição

++ -- - ~ ! tipo de

Incremento, decremento, mudança de sinal, NÃO lógico, inferência de tipo

Multiplicação, divisão, resto

Adição e concatenação de strings, subtração

Operadores de comparação

E lógico

Capítulo 14. Introdução à Programação Web. Linguagem JavaScript

Tabela 14.9 (final)

Operadores

Descrição

OU lógico

Operador condicional (veja abaixo)

= <оператор>=

Atribuição, simples e complexa

ATENÇÃO!

Lembre-se desta tabela. A ordem incorreta de execução das instruções pode causar erros difíceis de detectar, nos quais uma expressão aparentemente absolutamente correta fornece um resultado incorreto.

Mas e se precisarmos quebrar a ordem normal de execução das instruções? Vamos usar colchetes. Nesta notação, as instruções entre parênteses são executadas primeiro:

a = (b + c) * 10;

Aqui, os valores das variáveis ​​b e c serão somados primeiro e, em seguida, a soma resultante será multiplicada por 10.

Os operadores entre parênteses também estão sujeitos a precedência. Portanto, vários parênteses aninhados são frequentemente usados:

a = ((b + c) * 10 - d) / 2 + 9;

Aqui, as instruções serão executadas na seguinte ordem:

1. Adicione b e c.

2. Multiplique o valor resultante por 10.

3. Subtraindo d do produto.

4. Divida a diferença por 2.

5. Adição de 9 ao quociente.

Se você remover os colchetes:

a = b + c * 10 - d / 2 + 9;

então a ordem de execução dos operadores será a seguinte:

1. Multiplique c e 10.

2. Divida d por 2.

3. Adicionando b e multiplicando c e 10.

4. Subtração da soma resultante do quociente da divisão d a 2.

5. Adicionando 9 à diferença resultante.

Acontece um resultado completamente diferente, certo?

  • indefinido Indefinido"
  • null: "objeto"
  • Booleano: "booleano"
  • Número: "número"
  • Cadeia: "cadeia"
  • Função: "função"
  • Todo o resto: "objeto"

As seguintes observações devem ser adicionadas a esta tabela:

1. typeof null === "objeto" .

Teoricamente, há um ponto sutil aqui. Em linguagens de tipagem estática, uma variável de tipo de objeto não pode conter um objeto (NULL, nil, ponteiro nulo).

Praticamente - em JavaScript é inconveniente. Então os desenvolvedores do ES 5.1 vão fazer algo mais intuitivo: typeof null === "null" .

Mas como ainda estamos no ES3, não se engane, por exemplo, sobre isso:

/* Função procura algum objeto e o retorna ou null se nada for encontrado */ function search() () var obj = search(); if (typeof obj === "object") ( // realmente encontramos o objeto (FAIL) obj.method(); )

2. Não se esqueça dos objetos wrapper (typeof new Number(5) === "object").

3. E não se esqueça do direito dos navegadores de fazer qualquer coisa com objetos de host.

Não se surpreenda que o Safari teimosamente trata HTMLCollection como um tipo de função, e o IE anterior ao 9º mantém nossa função alert() favorita como um objeto . Além disso, o Chrome costumava considerar RegExp como uma função , mas agora parece cair em si e responde a ela com um objeto .

para sequenciar()

Tentar descobrir o tipo de um valor a partir do resultado de seu método toString() é inútil. Em todas as "classes" este método é redefinido como próprio.

O método é bom para exibir informações de depuração, mas o tipo da variável não pode ser determinado a partir dele.

Object.prototype.toString()

Mesmo que toString seja substituído dentro de "classes" concretas, ainda temos sua implementação original de Object. Vamos tentar usar:

console.log ( Objeto .prototype .toString .call (valor) );

console.log(Object.prototype.toString.call(value));


Clinton dilui esse fardo

Curiosamente, esse método funciona surpreendentemente bem.

Por tipos escalares retorna , , , .

O engraçado é que mesmo o novo Number(5) em que typeof falhou aqui retorna .

Em null e undefined, o método falhará. Diferentes navegadores retornam o esperado e , ou , ou mesmo . No entanto, é fácil determinar o tipo desses dois valores sem isso.

O interessante começa quando chegamos aos objetos (aqueles com typeof === "object").

objetos embutidos funcionam, praticamente, com um estrondo:

  • {} —
  • encontro-
  • erro-
  • regexp-

A única coisa que sai da lista de argumentos, que é , ou .
Com objetos host, tudo é pior novamente.

No IE, os objetos DOM começaram a se tornar objetos "normais" apenas a partir da 8ª versão, e depois não até o fim. Portanto, no IE 6-8 todos esses objetos (HTMLCOllection, DOMElement, TextNode , bem como document e window) são simplesmente convertidos para .

Em todos os outros navegadores (incluindo o IE9), você já pode fazer algo com o resultado toString. Embora tudo também não seja fácil: HTMLCollection lá , então . janela - então, então, então. Mas você já pode tentar tirar algo disso.

É mais difícil com DOMElement: ele é exibido como , um formato diferente para cada tag. Mas aqui a temporada regular nos ajudará.

Com outros objetos hospedeiros (nos testes de localização e navegador), a história é quase a mesma. Em todos os lugares, exceto no IE, eles podem ser identificados por uma string.

Das desvantagens de usar Object.prototype.toString():

1. Esta possibilidade não é consagrada pela norma. E aqui devemos nos alegrar por tudo estar funcionando tão bem, e não lamentar algumas falhas.

2. Determinar o tipo analisando a string retornada pelo método, que não serve para determinar o tipo, e até mesmo chamar um objeto ao qual não se aplica, deixa algum sedimento na alma.

3. No IE antigo, como você pode ver, os objetos host não são normalmente identificados.

No entanto, é bastante funcional quando usado em conjunto com outras ferramentas.


Construtores

E finalmente, construtores. Quem melhor para falar sobre a "classe" de um objeto em JS do que seu construtor?

null e undefined não possuem objetos wrapper nem construtores.

O resto dos tipos escalares tem wrappers, então você pode obter um construtor:

(5) .construtor === Número ; (Número .NaN ) .construtor === Número ; (true ) .constructor === Boolean ; ("string") .constructor === String ;

(5).construtor === Número; (Número.NaN).construtor === Número; (true).construtor === Boolean; ("string").construtor === String;

Mas instanceof não funcionará aqui:

5 instância de Número ; // false Number .NaN instanceof Number ; // false true instanceof Boolean ; // false "string" instanceof String ; // falso

5 instância de Número; // false Number.NaN instanceof Number; // false true instanceof Boolean; // false "string" instanceof String; // falso

(instanceof funcionará para o novo Number(5))

Com funções (que também são objetos), instanceof fará:

console.log((function()()) instanceof Function); // true console. log ( (function () ( ) ) .constructor === Function ) ; // verdadeiro

console.log((função () ()) instanceof Função); // true console.log((function () ()).constructor === Function); // verdadeiro

Todos os objetos de classes internas também são facilmente identificados pelos construtores: Array , Date , RegExp , Error .

Um problema surge aqui com argumentos, cujo construtor é Object.

E a segunda com o próprio Object, ou melhor, como se referir a ele um objeto criado através de um construtor customizado.

Apenas o objeto base pode ser definido assim:

obj instanceofObject;

Como uma das opções de definição, itere sobre todos os outros tipos possíveis (Array , Error ...) e se nenhum deles se enquadrar em - "objeto".

Construtores e objetos hospedeiros

As coisas pioram com objetos host.

Vamos começar com o fato de que o IE até a 7ª versão inclusive não os considera objetos normais. Eles simplesmente não têm construtores e protótipos lá (de qualquer forma, o programador não pode alcançá-los).

As coisas são melhores em outros navegadores. Existem construtores e você pode determinar a classe de valor deles. Só que eles são chamados de forma diferente em diferentes navegadores. Por exemplo, para um HTMLCollection o construtor será um HTMLCollection ou um NodeList , ou mesmo um NodeListConstructor .

Você também deve definir um construtor base para DOMElement. Em FF, isso é, por exemplo, HTMLElement , do qual HTMLDivElement e outros já herdam.

O truque é lançado pelo FireFox abaixo da versão 10 e Opera abaixo da versão 11. Lá, o construtor da coleção é Object .

construtor.nome

Os construtores também têm uma propriedade de nome que pode ser útil.

Ele contém o nome da função construtora, por exemplo, (5).constructor.name === "Number" .

No entanto:
1. No IE não é nada, mesmo na 9ª.
2. Em Host-objects, os navegadores novamente moldam tudo o que é muito (e muitas vezes eles não têm essa propriedade). No Opera, DOMElement tem um nome de construtor em geral Function.prototype .
3. argumentos novamente "objeto".

conclusões

Nenhum dos métodos apresentados dá uma definição 100% do tipo/classe do valor em todos os navegadores. No entanto, juntos, eles permitem que você faça isso.

Em um futuro próximo, tentarei coletar todos os dados em tabelas e dar um exemplo de uma função definidora.

Operador tipo de retorna uma string indicando o tipo do operando.

Sintaxe

O operando segue o operador typeof:

tipo de operando

Opções

operandoé uma expressão que representa o objeto ou primitivo cujo tipo deve ser retornado.

Descrição

A tabela a seguir lista os possíveis valores de retorno de typeof . informação adicional sobre tipos e primitivos está na página.

Exemplos

// Numbers typeof 37 === "number"; typeof 3.14 === "número"; typeof(42) === "número"; typeof Math.LN2 === "número"; typeof Infinito === "número"; typeof NaN === "número"; // mesmo que seja "Not-A-Number" typeof Number(1) === "number"; // nunca use esta notação! // Strings typeof "" === "string"; typeof "bla" === "string"; typeof "1" === "string"; // note que o número dentro da string ainda é do tipo string typeof (typeof 1) === "string"; // typeof sempre retornará uma string neste caso typeof String("abc") === "string"; // nunca use esta notação! // Boolean typeof true === "boolean"; typeof false === "boolean"; typeof Boolean(true) === "boolean"; // nunca use esta notação! // Símbolos typeof Symbol() === "symbol" typeof Symbol("foo") === "symbol" typeof Symbol.iterator === "symbol" // Tipo indefinido de undefined === "undefined"; typeof declaradoButUndefinedVariable === "indefinido"; typeof undeclaredVariable === "undefined"; // Objetos typeof(a: 1) === "objeto"; // use Array.isArray ou Object.prototype.toString.call // para distinguir entre objetos regulares e arrays typeof === "object"; typeof new Date() === "objeto"; // Qualquer coisa abaixo leva a erros e problemas. Não use! typeof new Boolean(true) === "objeto"; typeof new Number(1) === "objeto"; typeof new String("abc") === "objeto"; // Funções typeof function() () === "function"; typeof class C() === "função"; typeof Math.sin === "função";

nulo

// Isso foi definido desde o nascimento do JavaScript typeof null === "object";

Na primeira implementação do JavaScript, os valores eram representados por um tipo de tag e um par de valores. O tipo de tag para objetos era 0. null era representado como um ponteiro nulo (0x00 na maioria das plataformas). Portanto, o tipo da tag para null era null, então o valor de retorno de typeof é falso. ()

Uma correção foi proposta no ECMAScript (via desativação), mas foi rejeitada. Isso resultaria em typeof null === "null" .

Usando o novo operador

// Todas as funções construtoras criadas com "new" serão do tipo "object" var str = new String("String"); var num = new Number(100); typeofstr; // Retorna "objeto" typeof num; // Retorna "object" // Mas há uma exceção para o construtor Function var func = new Function(); tipo de função; // Retorna "função"

Expressões regulares

As expressões regulares chamadas foram uma adição não padrão em alguns navegadores.

Typeof /s/ === "função"; // Chrome 1-12 não compatível com ECMAScript 5.1 typeof /s/ === "object"; // Firefox 5+ em conformidade com ECMAScript 5.1

Bugs relacionados a zonas mortas temporárias

Antes do ECMAScript 2015, o operador typeof tinha a garantia de retornar uma string para qualquer operando com o qual fosse chamado. Isso mudou com a adição de declarações let e const com escopo de bloco sem içamento. Agora, se as variáveis ​​forem declaradas com let e const e typeof for chamado nelas no bloco de declaração de variável, mas antes da declaração, um ReferenceError será lançado. O comportamento é diferente das variáveis ​​não declaradas, para as quais typeof retornará "undefined". As variáveis ​​com escopo de bloco estão em uma "zona morta temporária", que dura desde o início do bloco até o momento em que as variáveis ​​são declaradas. Nesta zona, uma tentativa de acessar variáveis ​​gera uma exceção.

Typeof undeclaredVariable === "undefined"; typeof newLetVariable; deixe newLetVariable; // ReferenceError typeof newConstVariable; const newConstVariable = "olá"; //ReferenceError

Exceções

Em todos os navegadores atuais, existe um objeto host document.all não padrão, que é do tipo Undefined.

Typeof document.all === "undefined";

Embora a especificação permita nomes de tipo personalizados para objetos exóticos não padrão, esses nomes devem ser diferentes dos predefinidos. A situação em que document.all é do tipo undefined deve ser considerada uma violação excepcional das regras.

Especificações

Especificação Status Comentários
Esboço mais recente do ECMAScript (ECMA-262)
Rascunho
ECMAScript 2015 (6ª edição, ECMA-262)
Definição de "The typeof Operator" nesta especificação.
Padrão
ECMAScript 5.1 (ECMA-262)
Definição de "The typeof Operator" nesta especificação.
Padrão
ECMAScript 3ª Edição (ECMA-262)
Definição de "The typeof Operator" nesta especificação.
Padrão
ECMAScript 1ª Edição (ECMA-262)
Definição de "The typeof Operator" nesta especificação.
Padrão Definição inicial. Implementado em JavaScript 1.1

Compatibilidade do navegador

Atualizar dados de compatibilidade no GitHub

ComputadoresMóvelservidor
cromadabordaRaposa de fogoInternet ExplorerÓperasafárivisualização da web androidChrome para AndroidFirefox para AndroidÓpera para AndroidSafari no iOSInternet SamsungNode.js
tipo decromada Apoio total 1 borda Apoio total 12 Raposa de fogo Apoio total 1 IE Apoio total 3 Ópera Apoio total Simsafári Apoio total Simwebview android Apoio total 1 Chrome Android Apoio total 18 Firefox Android Apoio total 4 OperaAndroid Apoio total SimSafari iOS Apoio total SimSamsung Internet Android Apoio total 1.0 nodejs Apoio total Sim

Lenda

Apoio total Apoio total

Notas Específicas do IE

No IE 6, 7 e 8, muitos objetos de host são objetos, não funções. Por exemplo.