JavaScript me sigue sorprendiendo y esta es otra instancia. Acabo de encontrar un código que no entendí al principio. Así que lo depuré y llegué a este hallazgo:
alert('a'['toUpperCase']()); //alerts 'A'
Ahora, esto debe ser obvio si toUpperCase()
se define como un miembro del tipo de cadena, pero no tenía sentido para mí inicialmente.
De todas formas,
- ¿funciona esto porque
toUpperCase
es miembro de 'a'? ¿O hay algo más sucediendo detrás de escena? El código que estaba leyendo tiene la siguiente función:
function callMethod(method) { return function (obj) { return obj[method](); //**how can I be sure method will always be a member of obj** } } var caps2 = map(['a', 'b', 'c'], callMethod('toUpperCase')); // ['A','B','C'] // ignoring details of map() function which essentially calls methods on every // element of the array and forms another array of result and returns it
Es una función genérica llamar a CUALQUIER método en CUALQUIER objeto. ¿Pero eso significa que el método especificado ya será un miembro implícito del objeto especificado?
Estoy seguro de que me falta una comprensión seria del concepto básico de las funciones de JavaScript. Por favor, ayúdame a entender esto.
javascript
function
Mahesha999
fuente
fuente
arr[5]
. Si los números en los nombres de identificadores válidos que podrían utilizar la notación de puntos:arr.5
.5['toString']()
.Respuestas:
Para descomponerlo.
.toUpperCase()
es un método deString.prototype
'a'
es un valor primitivo, pero se convierte en su representación de ObjetoEntonces
es el acceso mediante notación de paréntesis en la propiedad
toUpperCase
, desdeString.prototype
. Como esta propiedad hace referencia a un método , podemos invocarlo adjuntando()
fuente
foo.bar
yfoo['bar']
son iguales, por lo que el código que publicaste es el mismo queCuando usas
foo[bar]
(tenga en cuenta la falta de comillas) no se usa el nombre literalbar
sino el valor quebar
contenga la variable . Entonces, usar lafoo[]
notación en lugar de lefoo.
permite usar un nombre de propiedad dinámico.Echemos un vistazo a
callMethod
:En primer lugar, devuelve una función que toma
obj
como argumento. Cuando se ejecuta esa función, llamarámethod
a ese objeto. Entonces, el método dado solo necesita existir enobj
sí mismo o en algún lugar de su cadena de prototipos.En el caso de
toUpperCase
que ese método provengaString.prototype.toUpperCase
, sería bastante estúpido tener una copia separada del método para cada cadena que exista.fuente
Puede acceder a los miembros de cualquier objeto con
.propertyName
notación o["propertyName"]
notación. Esa es la característica del lenguaje JavaScript. Para asegurarse de que ese miembro esté en el objeto, simplemente verifique si está definido:fuente
Básicamente, JavaScript trata todo como un Objeto, o más bien, cada objeto puede verse como un diccionario / matriz asociativa. Y las funciones / métodos se definen exactamente de la misma manera para el objeto, como una entrada en esta matriz asociativa.
Entonces, esencialmente, estás haciendo referencia / llamando (nota el ' () propiedad ') 'toUpperCase', del objeto 'a' (que es un tipo de cadena, en este caso).
Aquí hay un código de la parte superior de mi cabeza:
fuente
anyObject['anyPropertyName']
es lo mismo queanyObject.anyPropertyName
cuandoanyPropertyName
no tiene caracteres problemáticos.Consulte Trabajar con objetos , de MDN.
El
toUpperCase
método se adjunta al tipo String. Cuando llama a una función en un valor primitivo, aquí'a'
, se promueve automáticamente a un objeto, aquí una Cadena :Puede ver que la función existe al iniciar sesión
String.prototype.toUpperCase
.fuente
Entonces, en Javascript,
objects
sonobjects
. Es decir, son de esta naturaleza{}
. Las propiedades de los objetos se pueden establecer usando uno de estos:a.greeting = 'hello';
oa['greeting'] = 'hello';
. Ambas formas funcionan.La recuperación funciona igual.
a.greeting
(sin comillas) es'hello'
,a['greeting']
es'hello'
. Excepción: si la propiedad es un número, solo funciona el método de paréntesis. El método de puntos no.Entonces,
'a'
es un objeto con'toUpperCase'
propiedad que en realidad es una función. Puede recuperar la función y llamarla posteriormente de cualquier manera:'a'.toUpperCase()
o'a'['toUpperCase']()
.Pero en mi opinión, la mejor manera de escribir la función del mapa sería como
var caps = ['a','b','c'].map( function(char) { return char.toUpperCase(); } )
¿Quién necesita la
callMethod
función entonces?fuente
Cada objeto de JavaScript es una tabla hash, por lo que puede acceder a sus miembros especificando una clave. por ejemplo, si una variable es una cadena, entonces debería tener la función toUpperCase. Entonces, podrías invocarlo
entonces, por str en línea, podrías tener abajo
fuente
toUpperCase es un método estándar de JavaScript: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/toUpperCase
La razón por la que funciona
'a'['toUpperCase']()
es que la función toUpperCase es una propiedad del objeto de cadena'a'
. Puede hacer referencia a las propiedades de un objeto utilizandoobject[property]
oobject.property
. La sintaxis 'a''toUpperCase' indica que hace referencia a la propiedad 'toUppercase' del objeto de cadena 'a' y luego lo llama ().fuente
No. Alguien podría pasar un objeto que
toUpperCase
; otoUpperCase
que no es una funciónEn el primer caso, se generará un error porque acceder a una propiedad que no existe devuelve
undefined
, y no podemos invocarundefined
como función.En el segundo caso, se generará un error porque, de nuevo, no podemos invocar una no función como función.
Recuerde que JavaScript es un lenguaje muy poco tipado. Se produce poca o ninguna verificación de tipo a menos que sea necesario. El código que mostró funciona en ciertos casos porque, en esos casos, el objeto pasado tiene una propiedad llamada
toUpperCase
, que es una función.El hecho de que
obj
no se garantice que el argumento tenga los tipos correctos de propiedades no molesta en absoluto a JavaScript, por así decirlo. Adopta una actitud de "esperar y ver", y no arroja un error hasta que se produce un problema real en el tiempo de ejecución.fuente
Casi todo en javascript se puede tratar como un objeto. En su caso, el alfabeto mismo actúa como un objeto de cadena y
toUpperCase
puede invocarse como método. Los corchetes son solo una forma alternativa de acceder a las propiedades de los objetos y, dado quetoUpperCase
es un método, el corchete simple()
se necesita al lado de la['toUpperCase']
formación['toUpperCase']()
.'a'['toUpperCase']()
es equivalente a'a'.toUpperCase()
fuente
Lo importante a tener en cuenta aquí es que, dado que Javascript es un lenguaje dinámico , cada objeto es, esencialmente, solo un hash-map glorificado ( con algunas excepciones ). Y se puede acceder a todo en un objeto Javascript de dos maneras: notación de corchetes y notación de puntos.
Revisaré rápidamente las dos anotaciones respondiendo la primera parte de su pregunta, y luego pasaré a la segunda parte.
Notación de corchetes
Este modo es más similar al acceso a hashmaps y matrices en otros lenguajes de programación. Puede acceder a cualquier componente (datos (incluidos otros objetos) o función) utilizando esta sintaxis.
Esto es exactamente lo que estás haciendo en tu ejemplo. Tienes
'a'
, que es una cadena (y no un carácter literal, como si estuviera en un lenguaje como C ++).Usando la notación de corchetes, accede a su
toUpperCase
método Pero acceder a él todavía no es suficiente; simplemente escribiralert
, por ejemplo, en Javascript, no llama al método. Es solo una declaración simple. Para llamar a la función, debe agregar el paréntesis:alert()
muestra un cuadro de diálogo simple que contieneundefined
, ya que no recibió parámetros. Ahora podemos usar este conocimiento para descifrar su código, que se convierte en:Lo cual es mucho más legible.
En realidad, una buena manera de entender esto un poco mejor es ejecutar el siguiente Javascript:
Esto llama
alert
al pasarle un objeto de función, tambiénalert
, sin ejecutar también la segunda alerta. Lo que se muestra (en Chrome 26, al menos) es lo siguiente:Vocación:
muestra dos cuadros de mensaje consecutivos que contienen
undefined
. Esto es fácil de explicar: el internoalert()
se ejecuta primero, se muestraundefined
(porque no tenía ningún parámetro) y no devuelve nada. La alerta externa recibe el valor de retorno de la alerta interna, que no es nada, y también se muestraundefined
en un cuadro de mensaje.¡Pruebe todos los casos en jsFiddle!
Notación de punto
Este es el enfoque más estándar, que permite acceder a los miembros de un objeto utilizando el
.
operador dot ( ). Así es como se vería su código en notación de puntos:Mucho más legible. Entonces, ¿cuándo debemos usar la notación de puntos y cuándo debemos usar la notación de corchetes?
Comparación
La principal diferencia entre los dos métodos es semántica. También hay algunos otros detalles, pero los abordaré en un segundo. Lo más importante es lo que realmente quiere hacer: una regla general es que use la notación de puntos para los campos y métodos bien establecidos que tiene un objeto, y la notación de corchetes para cuando realmente está usando su objeto como un mapa hash .
Un gran ejemplo de por qué esta regla es tan importante se puede mostrar en su ejemplo, ya que el código está usando la notación de corchetes en un lugar donde la notación de puntos hubiera sido mucho más sensible, hace que el código sea más difícil de leer. Y eso es algo malo, porque el código se lee muchas veces más de lo que se escribe .
En algunos casos, debe usar la notación de corchetes, incluso si usar la notación de puntos fuera más sensato:
si un miembro de un objeto tiene un nombre que contiene uno o más espacios o cualquier otro carácter especial, no puede usar la notación de puntos:
foo.some method()
no funciona, perofoo["some method"]()
sí;si necesita acceder dinámicamente a los miembros de un objeto, también está atrapado usando la notación de corchetes;
Ejemplo:
La conclusión es que debe usar la sintaxis de paréntesis cuando use el objeto como un mapa hash (
foods["burger"].eat()
) y la sintaxis de puntos cuando trabaje con campos y métodos "reales" (enemy.kill()
). Dado que Javascript es un lenguaje dinámico, la línea entre los campos "reales" y los métodos de un objeto y "otros" datos almacenados dentro puede volverse bastante borrosa. Pero siempre que no los mezcles de manera confusa, deberías estar bien.Ahora, sobre el resto de su pregunta (¡finalmente!: P).
No puedes Intentalo. Intenta llamar
derp
a una cadena. Obtendrá un error en las líneas de:Sí, en tu caso tendría que ser así. De lo contrario, terminará con el error que mencioné anteriormente. Sin embargo, no tiene que usar
return obj[method]();
en lacallMethod()
función. Puede agregar su propia funcionalidad que luego utiliza la función de mapa. Aquí hay un método codificado que convierte todas las letras en mayúsculas:El código en el tutorial al que se vinculó utiliza funciones parciales . Son un concepto complicado por sí mismos. Leer más sobre ese tema debería ayudar a aclarar las cosas de lo que podría hacerlo.
Nota: este es el código de la función de mapa utilizada por el código en la pregunta, fuente aquí .
fuente
Si me preguntas cómo funciona realmente, así es como lo leí. Ok, esta es una función matemática simple. Para entenderlo, debes mirar la tabla ascii. Que asigna un valor numérico a cada letra. Para encubrirlo, la competencia simplemente usa una instrucción lógica para encubrir, por ejemplo If (ChcrValue> 80 && charValue <106) // Este es el conjunto de letras minúsculas y luego charValue = charValue - 38; // la distancia entre el conjunto inferior y el conjunto superior
es así de simple, en realidad no me molesté en buscar los valores correctos, sin embargo, esto básicamente está cambiando todas las letras minúsculas a mayúsculas.
fuente
'a'['toUpperCase']()
trabajar. Pero el malentendido es comprensible si alguien no leyó la pregunta.text-transform: uppercase
se agregaron estilos , estaba al final de mi ingenio sobre cómo JS logró cambiar el caso, despejó dudas y aprendí una o dos cosas. muchas gracias.