O importante a ser observado aqui é que, como o Javascript é uma linguagem dinâmica , todo objeto é, essencialmente, apenas um mapa de hash glorificado ( com algumas exceções ). E tudo em um objeto Javascript pode ser acessado de duas maneiras - notação entre colchetes e notação de ponto.
Analisarei rapidamente as duas anotações que respondem à primeira parte da sua pergunta e depois chegarei à segunda parte.
Notação de colchete
Este modo é mais semelhante ao acesso a hashmaps e matrizes em outras linguagens de programação. Você pode acessar qualquer componente (dados (incluindo outros objetos) ou função) usando esta sintaxe.
É exatamente isso que você está fazendo no seu exemplo. Você tem 'a'
, que é uma string (e não um caractere literal, como seria em uma linguagem como C ++).
Usando a notação de colchete, você acessa seu toUpperCase
método. Mas acessá-lo ainda não é suficiente; simplesmente digitar alert
, por exemplo, em Javascript, não chama o método É apenas uma afirmação simples. Para chamar a função, é necessário adicionar o parêntese: alert()
mostra uma caixa de diálogo simples contendo undefined
, pois não recebeu parâmetros. Agora podemos usar esse conhecimento para decifrar seu código, que se torna:
alert('a'.toUpperCase());
O que é muito mais legível.
Na verdade, uma boa maneira de entender isso um pouco melhor é executar o seguinte Javascript:
alert(alert)
Isso chama alert
passando um objeto de função, também alert
, sem também executar o segundo alerta. O que é mostrado (no Chrome 26, pelo menos) é o seguinte:
function alert() { [native code] }
A ligar:
alert(alert())
mostra duas caixas de mensagens consecutivas contendo undefined
. Isso é fácil de explicar: o interior alert()
é executado primeiro, mostra undefined
(porque não tinha nenhum parâmetro) e não retorna nada. O alerta externo recebe o valor de retorno do alerta interno - o que não é nada e também é exibido undefined
em uma caixa de mensagem.
Experimente todos os casos no jsFiddle!
Notação de ponto
Essa é a abordagem mais padrão, que permite que membros de um objeto sejam acessados usando o .
operador dot ( ). É assim que seu código ficaria na notação de ponto:
alert('a'.toUpperCase())
Muito mais legível. Então, quando devemos usar a notação de ponto e quando devemos usar a notação entre colchetes?
Comparação
A principal diferença entre os dois métodos é semântica. Há também outros detalhes, mas chegarei a esses em um segundo. O mais importante é o que você realmente deseja fazer - uma regra geral é que você use notação de ponto para campos e métodos bem estabelecidos que um objeto possui e a notação de colchete para quando você estiver realmente usando seu objeto como um mapa de hash .
Um ótimo exemplo de por que essa regra é tão importante pode ser mostrado em seu exemplo - como o código está usando a notação de colchete em um local onde a notação de pontos teria sido muito mais sensata, torna o código mais difícil de ler. E isso é uma coisa ruim, porque o código é lido muito mais vezes do que está escrito .
Em alguns casos, você deve usar a notação de colchete, mesmo que a notação de ponto seja mais sensata:
se um membro de um objeto tiver um nome contendo um ou mais espaços ou qualquer outro caractere especial, você não poderá usar a notação de ponto: foo.some method()
não funciona, mas foo["some method"]()
funciona;
se você precisar acessar dinamicamente os membros de um objeto, também ficará preso usando a notação de colchete;
Exemplo:
for(var i = 0; i < 10; ++i) {
foo["method" + i]();
}
A linha inferior é que você deve usar a sintaxe de colchete ao usar o objeto como um mapa de hash ( foods["burger"].eat()
) e a sintaxe de ponto ao trabalhar com campos e métodos "reais" ( enemy.kill()
). Com o Javascript sendo uma linguagem dinâmica, a linha entre os campos e métodos "reais" de um objeto e "outros" dados armazenados pode ficar bastante embaçada. Mas contanto que você não os misture de maneiras confusas, você ficará bem.
Agora, vamos ao resto da sua pergunta (finalmente!: P).
como posso ter certeza de que o método sempre será um membro da obj
Você não pode. Tente. Tente chamar derp
uma string. Você receberá um erro nas linhas de:
Uncaught TypeError: Object a has no method 'derp'
É meio que uma função genérica chamar QUALQUER método em QUALQUER objeto. Mas isso significa que o método especificado já será um membro implícito do objeto especificado?
Sim, no seu caso, teria que ser. Caso contrário, você terminará com o erro mencionado acima. No entanto, você não precisa usar return obj[method]();
a callMethod()
função Você pode adicionar sua própria funcionalidade que depois será usada pela função de mapa. Aqui está um método codificado que transforma todas as letras em uma letra maiúscula:
function makeCap()
{
return function(obj) {
return obj.toUpperCase();
}
}
var caps2 = map(['a', 'b', 'c'], makeCap()); // ['A','B','C']
console.log(caps2)
O código no tutorial ao qual você vinculou usa funções parciais . Eles são um conceito complicado por si mesmos. Ler mais sobre esse assunto deve ajudar a tornar as coisas mais claras do que eu jamais poderia torná-las.
Nota: este é o código da função de mapa usado pelo código na pergunta, fonte aqui .
function map(arr, iterator) {
var narr = [];
for (var i = 0; i < arr.length; i++) narr.push(iterator(arr[i], i));
return narr;
}
arr[5]
. Se os números de onde os nomes de identificador válido que você poderia usar a notação de ponto:arr.5
.