[REPRODUCIENDO MÚSICA] DAVID MALAN: Muy bien, bienvenidos a
todos al desarrollo de aplicaciones móviles con React Native. Mi nombre es David Malan,
y este de aquí es… JORDAN HAYASHI: Jordan Hayashi. DAVID MALAN: –y este
es un curso que asume como base solo
algo como CS50, que es la Introducción
a las Ciencias de la Computación de Harvard. Pero, de manera más general, si no ha
tomado ese curso en particular, la experiencia previa en programación en la
mayoría de los idiomas debería ser suficiente. El enfoque de esta clase, por supuesto
, será el desarrollo de aplicaciones móviles. Y
lo interesante de este espacio es que ha estado
cambiando bastante rápido. No fue
hace tanto tiempo que ninguno de nosotros tenía teléfonos inteligentes en el bolsillo. Y así, el panorama ha ido
cambiando, particularmente rápido. Y cada vez es mejor. Si ha realizado algún desarrollo de aplicaciones en
dispositivos móviles o cualquier desarrollo web en dispositivos móviles, al
principio solo teníamos HTML y CSS, tal vez algo de
JavaScript para la interactividad.
Luego, muchas bibliotecas
entraron en escena. Ellos, a través de CSS y JavaScript,
daban la apariencia de que tenías una aplicación similar a la de un móvil
en tu teléfono, pero la interfaz de usuario
no era tan buena. Y se puede decir que esto
no es realmente "nativo". Es decir, código que está en Objective-C o
Swift en iOS o en Java para Android. Y algo siempre se sentía un poco fuera de lugar. Por lo tanto, puede aprender
cualquiera de esos idiomas o elegir los diversos conjuntos de herramientas
que existen para escribir software nativo. Pero es una curva de aprendizaje decente. Y si está dirigiendo una
empresa o escribiendo una aplicación , generalmente tiene que escoger y elegir. ¿Quiero apuntar a Android? ¿Quiero hacer iOS o esencialmente
quiero hacer el doble de trabajo? Y eso solo podría
ser un obstáculo potencial.
Y luego estaban
estas otras bibliotecas que le permitían aproximarse a la
experiencia de escribir su código una vez y luego ejecutarlo en ambas plataformas. Pero allí también, siempre se podía
decir que algo no era del todo natural para el dispositivo en particular. Y luego, más recientemente,
ha entrado en escena una serie de nuevos marcos,
particularmente React Native, un marco de código abierto
popularizado por Facebook que realmente ahora permite
desarrollos multiplataforma verdaderamente nativos mientras usa JavaScript para
unir cosas y luego apoyarse en el
marco para proporcionarle esos widgets de interfaz de usuario verdaderamente nativos
y otras características que se esperarían de
esos diversos lenguajes. Entonces, lo que haremos en el
transcurso del semestre es sumergirnos profundamente
en el desarrollo de aplicaciones móviles, específicamente construyendo
sobre este marco popular.
Es posible que haya oído hablar de
Reacht Native o React en el contexto de los navegadores web, que también
existe desde hace algún tiempo. Y muchos de esos paradigmas que la
gente ha estado usando durante algunos años en computadoras portátiles y de escritorio ahora están
disponibles con características adicionales en un contexto móvil, especialmente. Así que hoy vamos a sumergirnos
rápidamente en JavaScript. Si tienes un poco de experiencia
en eso, eso es genial. Con suerte, llenaremos
algunos vacíos en el camino.
Y también veremos algunas de las
funciones más avanzadas tanto esta noche como la próxima semana,
particularmente ES6 6 o ECMAScript 6, que es esencialmente la
última versión de JavaScript, y con ella algunas
funciones sintácticas y capacidades programáticas nuevas. Una semana después de eso,
echaremos un vistazo a React en sí mismo y JSX, que más bien combina el
código con XML o un lenguaje de marcado, si está familiarizado. Y luego mire algunas de
las características particulares y las características de la interfaz de usuario que obtiene
con un marco como React JS. Componentes, accesorios,
cómo maneja los estados, cómo puede estilizar las cosas,
obtener información del usuario y crear vistas, si está familiarizado con paradigmas
como MVC, controlador de vista de modelo. La revisión determina qué es lo que el usuario
está viendo y con lo que interactúa.
Echaremos un vistazo a las
técnicas de depuración, particularmente para una plataforma móvil,
que puede no ser necesariamente obvia si el dispositivo en el que está trabajando está
aquí y el dispositivo en el que está probando está aquí. Te daremos algunas herramientas
y técnicas para eso. Centrándose en última instancia en los datos y la
navegación, cómo puede hacer que los usuarios se muevan en sus aplicaciones. Y luego mirar una
herramienta y un marco de trabajo de terceros llamado Expo, que en realidad
hace que sea aún más fácil desarrollar para este
entorno en particular y comenzar
y trabajar rápidamente. Mirando Redux y la
gestión estatal nuevamente de manera más general.
Ajuste del rendimiento de sus aplicaciones. Y luego, finalmente,
cómo sacas esto de tu computadora portátil o de escritorio
y de tu teléfono y lo conectas a otros teléfonos
y dispositivos móviles. Y aplicaremos todas
estas lecciones aprendidas y los desafíos reales, y la
porción de manos sucias de la clase será a través de los proyectos del curso. Tres de ellos asignan especificaciones
nuestras que especifican exactamente qué es lo que debe aspirar a construir.
Y luego, la clase culminará
con el proyecto final, donde dependerá de usted proponer,
diseñar y, en última instancia, implementar la mayoría de las aplicaciones móviles, un
React Native superior, como le gustaría. Sin más preámbulos, profundicemos
en una descripción general de la clase en sí , así como, entonces. JavaScript. Déjame pasarle las
cosas a Jordan. JORDAN HAYASHI: Genial, sí. Gracias por la gran introducción, David. Algunas cosas sobre
el curso en sí, puede encontrar información en el sitio web. Te envié un correo electrónico con todos los
enlaces hoy. En él, hay un enlace
a Slack, que es lo que vamos a usar para
una comunicación bastante instantánea. Pueden crear grupos
entre ustedes, y lo usaremos para cualquier
cosita rápida cuando tengamos que enviar.
Y luego, además,
tenemos el correo electrónico de nuestro personal que también está vinculado, así es
como puede enviar un correo electrónico al personal directamente. Y así un poco sobre conferencias. Tendremos un breve descanso a mitad de camino. Puedes levantarte, puedes usar el
baño, ir a descansar las piernas. Si tiene alguna
pregunta durante la conferencia, no dude en levantar la
mano o interrumpirme directamente. Los conceptos se complementan constantemente
, por lo que es muy importante aprender todo
hasta cierto punto para poder desarrollarlo más adelante. Y si algo no es muy
importante saber cuando haces una pregunta al respecto, te lo haré saber. Así que no te preocupes por
hacer preguntas tontas. Y el personal estará monitoreando
el Slack durante la conferencia. Entonces, si las personas en línea tienen alguna
pregunta, siéntase libre de publicar allí, y el personal me interrumpirá. Otra cosa, me encantan los ejemplos en vivo. Creo que los mejores ejemplos
se crean en el acto.
Y con eso viene
un poco de riesgo. Entonces, la codificación en vivo tiene riesgos. Si cometo un error,
siéntete libre de corregirme. Tengo algunos dulces en el atril. Así que si me corrigen,
les daré unos dulces. Para aquellos en línea, lamento no recibir
dulces, pero pueden tener algo de gloria. Frio. Comencemos hablando de JavaScript. Entonces JavaScript es un
lenguaje interpretativo. Así que publiqué un
poco en Slack anteriormente preguntando sobre los idiomas más cómodos. La mayoría de ustedes
decían JavaScript, pero sé que aquellos de ustedes que usaron CS50
pueden tener algo de experiencia con CE, que es un lenguaje compilado. Entonces JavaScript no está compilado. En realidad, se interpreta, por lo que un
intérprete leerá línea por línea y ejecutará ese código línea por línea.
Cada navegador tiene
incorporado su propio motor JavaScript, que interpreta el código. Puede hacer algo de magia con
alguna compilación justo a tiempo, pero en su mayor parte es solo
leer su código línea por línea y ejecutarlo. Cada navegador en realidad tiene su
propio motor, y hay nombres. Entonces Chrome se llama V8. Si ha oído hablar de Node.js,
también utiliza el mismo motor de nodo v8. Firefox tiene SpiderMonkey. Safari tiene JavaScriptCore. Chakra para Microsoft Edge
e Internet Explorer. Realmente no
necesita conocer estos nombres, pero es un poco
importante saber que existen diferentes, porque JavaScript en realidad
se basa en un estándar.
El estándar lo publica ECMA,
que significa Asociación Europea de Fabricantes de Computadoras. Y esa asociación está a cargo de
simplemente publicar una especificación, es decir, oye, sé que ustedes tienen este idioma. Pero esto es exactamente lo que
este lenguaje necesita hacer. Y para cada
función individual, así es exactamente como debería comportarse esta función. Entonces, cada uno de estos navegadores, los motores en los navegadores, en realidad implementan el estándar. Pero hay algunas funciones en
las que el estándar es un poco confuso, o tal vez ni siquiera define
esta función en particular.
Y no hay una línea clara en exactamente
lo que debería hacer esa función. Por lo tanto, pueden diferir por cualquier cosa que
no esté definida por ese estándar. Y algo de sintaxis. De hecho, saltemos al
código directamente para esto. Así que hagamos– genial. Y la forma en que declaras las
variables en JavaScript, en realidad hay tres formas diferentes. Hablaremos de eso
un poco más adelante. Pero por ahora, solo usaremos
esta palabra clave llamada const. Entonces, si quiero declarar una
variable, diría const. Así que dame una variable llamada nombre. Y puedo darle el valor que quiera. Así que vamos a llamarlo mi primer nombre.
Así que te das cuenta de que tengo un
literal de cadena allí. Está usando comillas dobles, y luego
termino esa declaración con un punto y coma. También puedo hacer un apellido. Y si se dan cuenta, esta vez,
todavía tengo ese literal de cadena, pero esta vez estoy usando comillas simples. Porque en
JavaScript realmente no hay diferencia entre comillas simples y dobles. También notará que omití ese punto
y coma, que en JavaScript está bien. Así que mis dos puntos son en realidad opcionales. Entonces digamos que quería algo
que no fuera una cuerda. Puedo simplemente darle un valor, como 42. Entonces, en C, es posible que veas
algo como, dame un int, o dame una cadena o una estrella char.
Estás declarando tipos de
inmediato con C, pero para algo como JavaScript, en
realidad no tienes que hacer eso. También podemos hacer arreglos. Y podemos simplemente declararlos en
línea como esta, y puedo tener– Entonces, si se dan cuenta, en realidad tengo
tres tipos diferentes en esta matriz. Así que tengo una cadena, tengo un
número y tengo una función. Y esto está perfectamente bien. A JavaScript realmente no le importa
lo que arrojas en una matriz. Puede tener todo tipo de tipos de
variables diferentes.
Entonces digamos que queremos acceder a
esas cosas en una matriz. ¿Alguien quiere adivinar
exactamente cómo haría eso? Así que digamos que quiero ejecutar esa función. ¿Cómo podría hacer eso? ¿Alguna suposición? Sí. Si, exacto. La matriz de dos. Entonces, si está familiarizado con
otros lenguajes, muchos de ellos tienen la misma sintaxis para
indexar en una matriz. Y como tenemos tres
cosas en esta matriz, hacemos lo que se llama indexación cero,
por lo que el primer índice de esa matriz se denomina índice cero. Y luego cuentas a partir de ahí. Entonces tenemos cero aquí,
primero y segundo aquí.
Y entonces digo que quiero
acceder a esa función. Solo hago la matriz 2 y
obtengo esa función. Y digamos que ahora quería
ejecutar esa función. Puedo, digamos, ejecutarlo así. Así que esto es algo que
puede ver en otros idiomas, pero JavaScript también puede hacerlo. Puede tomar esa función de
esa matriz y ejecutarla así. Digamos que quería un bucle for y
quería registrar en la consola todo lo que hay en esa matriz. Puedo hacerlo casi
como C. Así que puedo hacerlo por… esta vez usaremos
let para la variable. Hablaremos un poco
más sobre eso más adelante.
Así que empiezo de cero. Bueno, es menor que la longitud elevada. [ESCRIBIR ] Es posible que me vea: mi preferencia personal
es omitir los puntos y comas, pero es posible que lea algo en
línea que los incluya. Realmente no importa tanto. Y entonces esta línea de código aquí. Es posible que haya visto un bucle for en
otros idiomas que haya usado. Entonces, este solo dice
que me den una variable que se llame i y comience en cero. Y si bien es menor que el
número de valores en la matriz, matriz.longitud,
siga incrementándolo. Y luego cada
vez console.log, que es la función de impresión de JavaScript,
sea cual sea el valor en esa matriz. Así que en realidad podemos ejecutar esto. Y como ves la primera
vez, la línea 12, donde decimos indexar esa matriz
al segundo valor, y llamarlo.
Eso es lo que está imprimiendo alto. Y este bucle for aquí ahora
imprimirá la cadena 42 y esta cosa llamada función, que es esta función. Genial, ¿alguna pregunta sobre la sintaxis? Sí. AUDIENCIA: En su conjunto
allí, ¿importa si tiene esa tercera coma después de su– JORDAN HAYASHI: No importa. Entonces, la pregunta era, ¿importa en la
línea 9 ese comentario al final? Entonces, JavaScript le permite tener
comas al final, es decir, en matrices, objetos o incluso llamadas a funciones. De hecho, puede tener comas adicionales, y
no importa si las tiene o no. Es opcional al
igual que el punto y coma. Pero si omitiera
la coma aquí e intentara ejecutar eso, obtendría
un error de sintaxis como se esperaba. Genial, ¿alguna otra pregunta? Estupendo. Así que volvamos a las diapositivas. Entonces tipos. Hablamos de tipos
un poco antes, y voy a hablar un
poco más sobre ellos. Entonces, JavaScript tiene lo que se llama
escritura dinámica, lo que significa que, dada una variable, no tiene ningún tipo asociado.
Entonces, como dije, dame
una variable llamada nombre y configúralo igual a una cadena. De hecho, podría cambiar
eso más tarde a, digamos, un número de tipo o un booleano
o algo así. Y JavaScript está bien con eso solo
porque tiene esos tipos dinámicos. Y hay un cierto
número de tipos primitivos. Los tipos primitivos son tipos que
no tienen métodos y son inmutables. Y tan indefinidos, nulos son dos de ellos. booleano. Todo el mundo debería saber el valor
booleano verdadero o falso. Número 1, 2, 3, negativo 1, 2, 3. No tiene coma flotante, por lo que 0 y
0,1 son ambos de tipo número. String, que son las
cosas entre comillas.
Y luego el símbolo,
que es algo nuevo en ES6, pero no vamos a hablar de
eso, ni lo vamos a usar, y luego todo lo demás es un objeto,
y hablaremos un poco más sobre eso. más tarde. Genial, y muchos idiomas
tienen esta cosa en la que cambias un tipo a otro tipo. Entonces, dado que JavaScript
se escribe dinámicamente, tenemos esta cosa llamada encasillamiento. Entonces, la coerción es el acto de cambiar
un tipo a otro tipo diferente, y hay dos formas diferentes de
coaccionar estas variables. Digamos, como ejemplo, que
tenemos esta constante llamada x y le damos un valor de 42. Digamos que quería cambiar
ese valor a una cadena. Hay un par de
maneras diferentes en que puedo hacerlo. Hay coacción explícita. Hay coerción implícita. Tan explícito es, oye,
solo te diré exactamente lo que quiero
envolviéndolo con el tipo que quiero y dármelo.
Y eso es ser muy
explícito con lo que quiero. Entonces, el ejemplo de
eso sería decir que quiero obtener una cadena de ese valor x. Simplemente lo envuelvo con una cadena mayúscula
y sale 42 con una cadena. También hay una forma de
hacerlo implícitamente, que es confiar
en el comportamiento de JavaScript para convertir esto en una cadena. Entonces digamos que quiero
agregar 42 a una cadena vacía. Eso realmente no tendría sentido
si quisiera tener un número, pero dado que 42 se puede
convertir fácilmente en una cadena, puedo decir, oye, dame
42, agrega una cadena vacía y espero obtener
algo del tipo cadena. . Eso se llama coerción implícita. Y entonces, ¿cómo podemos hacer
para comparar– oh, sí. Pregunta. AUDIENCIA: ¿La cuerda pasa por
detrás de la misma cuerda ex.2? JORDAN HAYASHI: Sí, otra
forma sería invocar eso. Entonces la pregunta era,
¿qué pasa con la cadena ex.2? Y sí, otra forma de
pasar de un número a una cadena sería invocar ese método en
la cadena o en el número, lo siento.
Genial, y entonces, ¿cómo
podemos comparar valores? Entonces, en la mayoría de los idiomas, puede comparar
valores con el doble igual, pero JavaScript tiene
algo llamado triple igual. Así que hay dos
maneras diferentes de comparar la igualdad. Hay iguales dobles
y iguales triples, donde los iguales dobles en
realidad obligarán a los tipos, y los iguales triples requieren
que los tipos coincidan. Entonces, juguemos
un poco con eso. Digamos que tengo este valor y
quiero saber exactamente de qué tipo es. Así que hay este operador llamado typeof
en JavaScript donde puedo invocarlo.
Y eso me dará el tipo
de lo que sea que contenga esa variable. Entonces, si tuviera que ejecutar este código
, diría número, porque ese es el tipo. Entonces, en este momento, para
ejecutar mi JavaScript, estoy usando esta cosa llamada nodo,
que, como se mencionó anteriormente, es básicamente un tiempo de ejecución de línea de comando para
JavaScript, que se basa en V8. Cualquier navegador tiene una consola donde
también puede escribir JavaScript directamente allí. Entonces, si tuviera que abrir las herramientas en
Chrome, que es mi navegador preferido, en realidad obtendría esto, que
es una consola de JavaScript integrada en todos estos navegadores.
Entonces, si usan Chrome en
casa y quieren seguirlo , pueden abrir
las herramientas para desarrolladores aquí. Vaya a la consola y tendrá su
propio intérprete de JavaScript aquí. Así que digamos que quería hacer eso
donde hago const x igual a 42, y quería obtener el
tipo de esa variable. Solo puedo hacer typeof x,
y generará ese número. Entonces, hay una pequeña advertencia con
esto, donde esto podría sorprenderlo.
Entonces, ¿quién cree que puede
adivinar lo que esto generará? En primer lugar, ¿qué debería generar? Entonces, si recordamos algunas diapositivas,
hablamos de todos los diferentes tipos. Uno de ellos es indefinido,
uno de ellos es nulo. Y digo que quiero obtener typeof null. Entonces, ¿qué debería generar? ¿Sí? AUDIENCIA: Cuerda. JORDAN HAYASHI: Cadena,
¿por qué diría cadena? AUDIENCIA: Porque [INAUDIBLE]. JORDAN HAYASHI: Esa es una buena suposición.
Entonces, básicamente, la respuesta fue que si
puede iniciar sesión en la consola, debe ser una cadena. Y si bien eso es correcto, la mayoría de estos
tipos se pueden convertir en cadenas. Así que hablamos de
coerción implícita versus explícita. Y la forma en que
funciona el registro de la consola es que en realidad convertirá estos valores en una
cadena para poder registrarlos en la consola, pero no significa necesariamente que el tipo de
ese valor en sí sea una cadena. ¿Sí? Sí, entonces el nulo. Entonces, esperaríamos que el tipo de
nulo fuera nulo, ya que nulo es en realidad un tipo primitivo. Sin embargo, esto realmente devuelve object.
Entonces JavaScript tiene
algunos comportamientos extraños. Este es uno de ellos. Y la gente a menudo pregunta,
oye, ahora estamos en ES6. Ha habido seis
versiones diferentes de JavaScript. ¿Por qué no
cambias esto para que sea nulo? Y la respuesta que da ECMA es,
bueno, todo Internet se rompería. Y así, cada nueva versión de
ECMAScript debería ser definitivamente compatible
con las versiones anteriores. De lo contrario, digamos que lanzo
un sitio web mañana. Si alguien baja y
cambia la especificación de JavaScript, entonces mi sitio web podría romperse. Y, por lo tanto, muchos sitios web
realmente confían en que esto sea cierto. Y, por lo tanto, si
se lanza una versión novedosa de ECMAScript, en realidad podría tener
consecuencias imprevistas. Así que este es solo uno de esos
extraños errores de JavaScript. Genial, entonces otra buena pregunta
sería ¿cuándo debo usar dobles iguales versus triples iguales? Y la gente generalmente dice que
nunca debes usar dobles iguales, porque eso significa que tienes que saber
exactamente cómo coacciona cada cosa. Y no solo usted, sino
cada persona que lea su código debe saber qué hacen todos
estos valores coaccionados.
Y algunos de ellos pueden
ser algo sorprendentes. Aquí tenemos un gráfico que habla
sobre la tabla de igualdad de JavaScript. Para aquellos de ustedes que tienen las diapositivas
abiertas, pueden hacer clic en ese enlace y los llevará
al repositorio que tiene esto. Básicamente, algunas de estas
cadenas son algo extrañas. Por ejemplo, cómo la matriz vacía es doble es
igual a falso, lo que realmente no tiene mucho sentido. Muchos de estos realmente no
tienen mucho sentido y, básicamente, nunca use
ese doble igual porque podría tener algunos comportamientos extraños. Así que sigue adelante con la coerción. Así que hablamos de forzar las
cosas a otros tipos, pero ¿qué tal si llegamos a los bools? Así que JavaScript tiene estas
cosas llamadas valores falsos.
¿Quién puede nombrar un valor falso? Entonces, el valor falso es cualquier valor que,
si se convierte en bool, se vuelve falso. AUDIENCIA: Dos. JORDAN HAYASHI: ¿Dos? Así que dos es en realidad verdad. Entonces, todos los números, excepto uno,
son verdaderos, bueno, en realidad son dos números. AUDIENCIA: Cero. JORDAN HAYASHI: Zero
sería uno de ellos, sí. No un número que en realidad es un número,
del tipo número, es también un valor falso. ¿Quién puede nombrar otro valor falso? AUDIENCIA: ¿En blanco? JORDAN HAYASHI: ¿En blanco qué? AUDIENCIA: O vacío. JORDAN HAYASHI: ¿Vacío qué? AUDIENCIA: Matriz vacía. JORDAN HAYASHI: La
matriz vacía es realmente veraz. Falso es otro. Indefinido, nulo. Así que esos son los cinco valores falsos. Entonces, ¿quién puede nombrar algunos valores verdaderos? Alguien dijo dos, que es una válida. Tres, cuatro, cualquier otro número que no
sea cero, menos cero, no es un número.
La matriz vacía también es otra verdad. Objeto vacío y
literalmente todo lo demás. Así que todo lo que no sean esos
valores ahí mismo es veraz. Genial, así que objetos, arreglos,
funciones, objetos. Parece que puse objetos dos veces
allí, pero en realidad los puse cuatro veces. Entonces, JavaScript tiene esta
cosa extraña donde si no es uno de esos
valores primitivos, es un objeto. Y hablaremos de
esto en un poco llamado
herencia de prototipos, que habla de cómo estos objetos se
heredan unos de otros y cómo
funcionan realmente bajo el capó. Pero primero comparemos esos dos tipos. Hablamos
antes de los primitivos, que es… ¿ quién puede nombrar algunos de los primitivos? AUDIENCIA: Nula. JORDAN HAYASHI: Nulo, indefinido. AUDIENCIA: Número. JORDAN HAYASHI: Número. AUDIENCIA: Booleano. JORDANIA HAYASHI: Booleano.
AUDIENCIA: Cuerda. JORDANIA HAYASHI: Cuerda. y sencillo Muy bien, los tienes todos. Bonito. Entonces, todo lo que no sea esos
tipos primitivos son en realidad objetos. Entonces, los primitivos son inmutables, lo
que significa que si desea cambiarlos, en realidad los está
reemplazando con un nuevo valor en lugar de cambiarlos ellos
mismos, mientras que los objetos no lo hacen. En realidad son mutables. Entonces, ¿quién sabe qué
significa almacenar por referencia? Entonces, almacenar por referencia
significa que en realidad almacenamos una referencia a este
objeto, y podemos cambiar lo que se mantiene allí
sin cambiar realmente dónde se encuentra esa cosa en la memoria. Hablaremos un poco
más sobre eso en un segundo. Pero lo contrario
sería almacenar algo por un valor, que es lo que
sucede cuando tienes primitivas. Entonces, como dije antes, las
primitivas son inmutables, lo que significa que una vez que creas una
primitiva, en realidad no se puede cambiar.
Y cuando quieres cambiar algo, en
realidad creas una nueva primitiva y reemplazas la anterior, mientras que las
cosas mutables se almacenan por referencia, y
puedes cambiar ese objeto. Entonces, juguemos
un poco con eso. Entonces, hay algunas
formas diferentes de crear un objeto. Uno sería así. Así que solo digo, dame un nuevo objeto. Y ahora, ¿es esto un objeto nuevo? Y digamos que queremos comenzar a
poblar el objeto. Podemos hacer o.firstname
y asignarle un valor. o.apellido,
asígnele un valor diferente. Tenga en cuenta que tengo cadenas con
comillas dobles y comillas simples. No importa. Así que algo más que una cadena. Podemos hacer un booleano, por lo que esTeaching. Podemos asignar eso a verdadero. o.greet, y podemos
darle una función. [ESCRIPCIÓN] Así que esa sería una forma
de crear un nuevo objeto es usar esta nueva palabra clave
junto con objetos de capital. Y eso dice, oye,
dame un objeto nuevo. Y solo voy a llenarlo con
estos valores usando esta notación de puntos.
Otra forma de hacerlo sería
lo que se llama un objeto literal. Así que puedo abrir
curly, cerrar curly, y eso me da básicamente un nuevo objeto. En realidad, esta es la forma preferida
sobre la antigua palabra clave nueva con objeto, principalmente porque a, es más fácil
de leer, y bueno, principalmente porque es más fácil de leer. Y entonces puedo comenzar a completar esos
valores con o.firstname. Y otra forma de indexar
estos objetos es hacer o.lastname.
Note que uso corchetes allí, lo
que significa que dentro de este corchete, voy a tener algún
valor, y ese valor será la clave de ese objeto. Así que puedo hacer lo mismo aquí. Y digamos que en realidad no quería usar una
cadena literal dentro de estos corchetes. Yo también podría hacer eso. Así que podría hacer isTeaching y hacer
o y luego pasar esta variable aquí con un valor de isTeaching,
y eso establecerá esa clave. Y luego decir que quería hacer o de
saludar y dar esa misma función. Llame y entonces esos objetos
son básicamente los mismos. Y por último, podemos
poner todo en orden. Así que podemos hacer esto. [ESCRIBIR] Genial, y esos tres objetos
son básicamente lo mismo. Son solo tres
formas diferentes de declarar objetos. También puede anidar objetos. Así que digamos que quería un
objeto dentro de un objeto.
Eso también está bien. Digamos que quería hacer algo como esto. [ESCRIBIR] Eso también está bien. Eso es un objeto dentro de un objeto. ¿Alguna pregunta con eso? Frio. Eso es en realidad– AUDIENCIA: Tengo una pregunta. JORDANIA: Sí. AUDIENCIA: ¿Todos los elementos de los
objetos tienen que estar etiquetados con cadenas? Como si una clave estuviera numerada,
digamos, ¿funcionaría? JORDAN: Um, Entonces cualquier cosa, cualquier cosa
aquí, se interpreta como una cadena. Así que digamos, teníamos que hacer, así, Eso sería, básicamente,
uno como una cadena. Entonces, este valor
aquí se convertirá como una cadena. Y eso es lo que se utilizará como clave. Entonces, la pregunta era, ¿
podemos usar números o cualquier otra cosa que no sean cadenas como claves en los objetos? Y la respuesta es, más o menos,
porque todo se convertirá en una cadena.
Sí, gran pregunta. Copiemos y
peguemos esto en nuestro navegador. Y confirmamos que funciona. Entonces, ¿cómo podríamos
recuperar esos valores? Entonces, es básicamente de la
misma forma en que los introdujimos. Entonces, si ponemos un punto, podemos ver, oh, estos
son todos, este es el navegador diciendo, oh, estas son todas las
claves del objeto. Entonces puedo hacer o3.address, y
me devolverá el objeto. Y digamos que queremos sacar
este número de aquí. ¿Cómo podríamos hacer eso? [ESCRIPCIÓN] PÚBLICO: Punto y el número. JORDAN: Exactamente, punto número. Alternativamente,
también podríamos haber hecho esto. [ESCRIBIENDO] Y obtuve lo mismo. ¿Alguna pregunta con los objetos? Sí. AUDIENCIA: ¿Existe una
forma convencional de hacerlo? ¿O es una especie de referencia? JORDAN: ¿Para hacer qué? PÚBLICO: Justo entre el
número de punto y [INAUDIBLE]. JORDAN: Sí, entonces la pregunta
es, ¿existe una forma convencional de obtener valores de los objetos? Generalmente, la convención
es usar esa notación de puntos. Así que digamos que queremos
o3.dirección.número, la convención sería usar el punto
en ambas ocasiones.
Pero digamos que no sabíamos exactamente
lo que queríamos de él. Podríamos, así que decir que teníamos esto– [ESCRIPCIÓN] Algo así, donde
tenemos una clave dinámica. Donde la clave en realidad no la
conocíamos, ahí es cuando realmente tienes que
usar la notación de corchetes. Donde tenemos o3.address, y
luego le pasamos esa clave. Dado que la clave es dinámica,
dado que es una variable, no sabemos qué es, entonces tenemos que
usar esa notación de paréntesis en lugar del punto. Gran pregunta. Sí. AUDIENCIA: Um– No puedes
hacer 0.1 por ejemplo. [INAUDIBLE] JORDAN: Entonces, si hicimos o.1, sí,
entonces, o.1, 1 aquí, ya que lo estamos escribiendo aquí, es un número. Y no podemos establecer claves para los números. Pero si fuera un objeto
literal como este, [TYPING] JORDAN: Considera que esto no
es un número, sino una cadena. PÚBLICO: Puede asignar la matriz
colocando corchetes alrededor del uno y pasándolo como una
cadena, por lo que puede hacer 0 punto [ESCRIBE] PÚBLICO: Nuestros corchetes
alrededor de [INAUDIBLE] o punto abren corchete, abren
llaves, y luego, comillas, una.
Y luego establezca eso en un valor. JORDAN: Entonces, ¿creo que te refieres a esto? [ESCRIBA] Sí. Y creo que tú también puedes hacer esto. [ESCRIBIR] Porque eso se convertirá en un número. Me refiero a una cadena. ¿Alguna otra pregunta? Genial, ¿sí? PÚBLICO: Si quiere el número
uno dentro de la notación entre paréntesis, en lugar de la cadena uno
dentro de la notación entre paréntesis, ¿se tratará como las mismas teclas? JORDAN: Sí, entonces la pregunta es, ¿cuál
es la diferencia entre esto de aquí y esto de aquí? La diferencia es que todo lo que esté
entre corchetes se convertirá en una cadena. Y así, dado que esto ya es una
cadena, es solo esa cadena uno. Dado que esto no es del
tipo cadena, en realidad se convierte implícitamente en una cadena.
Entonces, como vimos antes, si
hicimos uno más una cadena vacía, obtenemos la cadena uno. Entonces esto se convierte en una cadena,
y se indexará en eso. Mientras que, este número
aquí, así que si hicimos o3.1, [ESCRIBIR] Ese en realidad no es coaccionado,
como lo hace entre paréntesis aquí. Así que JavaScript básicamente dice,
hey, esto realmente no tiene sentido. Necesito una cadena aquí, no un número. Genial, ¿alguna otra pregunta? Genial… Entonces, hablemos un
poco sobre esto, donde estaba hablando de objetos mutantes. Así que digamos– [ESCRIBA] Entonces, digamos que tenía este objeto, así que– En él teníamos, a obtiene a, b obtiene b. Entonces, ¿quiero cambiar
a para que sea otra cosa? ¿Cómo podría hacer eso? Si. PÚBLICO: punto a igual a– JORDAN: Sí, entonces puedo actualizar
esto para que sea cualquier otra cosa. [ESCRITA] Genial, pero di que en realidad hice esto.
[ESCRIBIENDO] ¿Alguien quiere adivinar
qué se registrará en la consola aquí? Básicamente, lo que está haciendo
es crear un nuevo objeto. Y almacenarlo en o. Este objeto tiene dos claves, a y b, donde
sus valores son a y b respectivamente. Estoy creando este nuevo objeto
llamado o2 y le asigno un valor de o. Luego voy a reiniciar o. No o2 sino o.a para ser un nuevo valor.
Y voy a consola log o2.a. ¿Alguien quiere adivinar lo que
esto va a registrar en la consola? Sí. AUDIENCIA: un? JORDAN: Entonces, una conjetura es a. ¿Cuál sería la suposición alternativa? AUDIENCIA: Nuevo valor. JORDAN: Nuevo valor– [INAUDIBLE] JORDAN: Sí, vamos a ejecutar eso. Entonces obtienes un nuevo valor. Y entonces hablé sobre esto
llamado pasar por referencia y pasar por valor. Así que, básicamente, lo que está pasando
aquí es que se está diciendo, oye, dame un nuevo objeto, en alguna parte.
Y luego almacenar dentro de él, a y b. Y luego o2 dice hey, dame
otro objeto y ponlo en o. Y en lugar de crear un nuevo
objeto, con las mismas claves y valores , en realidad está apuntando
a ese mismo objeto. Entonces, este es un caso en el que las
cosas se almacenan por referencia, en lugar de por valor. Es decir, en CS50, hablamos
un poco sobre punteros, y este es exactamente el mismo concepto.
Donde estos objetos no se almacenan
como objetos serializados completos, sino como referencias
a estos objetos en la memoria. Entonces, o y o2 hacen referencia
al mismo objeto exacto. Entonces, cuando regresamos y decimos,
hey, actualice o.a para que sea un nuevo valor , está cambiando este
objeto aquí, y aún así, o y o2 apuntan
al mismo objeto. Entonces, si tuviera que actualizar 02
aquí y la consola iniciara sesión , obtendríamos el mismo resultado. Porque o
y o2 todavía se refieren al mismo objeto en la memoria, y
todavía estamos actualizando ese objeto aquí. ¿Tiene sentido? Sí. AUDIENCIA: ¿Y qué si
quisieras que fueran diferentes? Como, ¿y si quisieras
que no señalaran lo mismo? JORDAN: Sí, entonces la
pregunta es, ¿qué pasaría si quisiéramos que tuvieran el mismo
valor pero fueran referencias diferentes? ¿Cómo podríamos hacer eso? Hay dos formas diferentes. Una, la forma más molesta,
sería escribir todo de nuevo. [ESCRIBIR] Así que ahora tenemos la garantía de
que o y o2 serán referencias diferentes a
un objeto que es básicamente el mismo.
Y otra forma sería: hay varias
formas diferentes de hacer esto. La forma más común en
JavaScript puro sería hacer esto– [ESCRIBE] Por lo cual, el objeto asignado
básicamente dice, oye, pásame un montón de argumentos. Y cada argumento, voy
a fusionarlo con el anterior, esos pierden claves y valores. Y esto es decir,
dame un objeto nuevo. Así que estoy usando el objeto literal
aquí para significar un nuevo objeto. Y luego fusionarse en él, de las claves
y valores de este objeto llamado o. Y esto es básicamente
decir, dame un nuevo objeto, y luego configura todas las claves
y valores de o para que estén allí. Así que esta es la forma de clonar un objeto. Pero digamos que en realidad hicimos esto [ESCRIBIR] Entonces, ¿qué esperamos que
esto imprima ahora? Entonces, mencionamos que en la línea nueve,
estamos tomando las claves y los valores de o, y fusionándolos en un nuevo objeto. Y luego esa línea 11 estamos
tomando o2, obteniendo el objeto de punto, accediendo al valor
con la clave llamada objeto.
Y luego establecer la
clave de ese objeto llamada clave en un nuevo valor. Y luego ahora
inicie sesión en la consola o en la tecla de punto del objeto. Sí. AUDIENCIA: Entonces, ¿nuevo valor? JORDAN: Sí, entonces esto, entonces
la conjetura es un nuevo valor, y eso es absolutamente correcto. Entonces esto, entonces… la línea nueve aquí está
haciendo lo que se llama una copia superficial. Lo cual es simplemente agarrar las
claves y los valores de algún objeto, y simplemente configurarlos ciegamente
en algún otro objeto. A diferencia de lo que
se llamaría una copia profunda. Donde eso llevaría
las claves y valores. Y luego, si los valores
son objetos, también tomaría las claves y los valores de esos objetos.
Hágalo de forma recursiva y, básicamente,
obtenga una clonación profunda de cada capa. Pero dado que el objeto asignado solo
toma las claves y los valores de forma tonta, si tenemos un objeto allí,
actualice la clave de ese objeto. o.obj y o2.obj siguen haciendo referencia a
ese mismo objeto en la memoria, así que como actualizamos , mutamos ese objeto,
se actualizaría tanto en o2 como en o. ¿Tiene eso sentido? Genial, ¿alguna pregunta sobre esto? Sí. AUDIENCIA: ¿Cómo harías una copia profunda? JORDAN: Entonces, ¿cómo harías una copia profunda? Esa es una gran pregunta. Hay múltiples formas diferentes. Así que la mayoría de la gente diría usar una biblioteca.
Es decir, en lugar de implementar
esto por su cuenta, simplemente tome
la implementación de otra persona. Pero vamos, vamos a hacer eso. Buena pregunta. Entonces, ¿cómo haríamos una copia profunda? [ESCRIBIR] Entonces, sé que aún no hemos
hablado mucho sobre JavaScript, pero
intentemos hacerlo juntos. Entonces, llamemos a una función, copia profunda. Y vamos a
pasarle algún objeto.
¿Y cómo implementaríamos
esto, si tenemos la garantía de que ningún objeto tiene valores de objetos? Lo que significa que tenemos la garantía de
no tener objetos dentro de objetos. ¿Cómo podemos hacer esto? PÚBLICO: Consultar por el tipo de llave. JORDAN: Sí, para que podamos
verificar el tipo de cada clave. Pero si tenemos la garantía de que ningún
valor será objeto, podemos hacer una copia superficial, ¿verdad? Sí. AUDIENCIA: Entonces, ¿verifique cada valor? Y si es así, el valor es [INAUDIBLE]
, tenemos que copiarlo en profundidad recursivamente. JORDANIA: Sí. Así que mantén ese pensamiento. En realidad, implementemos
esto como si supiéramos que no hay objetos dentro de los objetos.
Entonces, si eso fuera cierto,
podríamos devolver la copia superficial, ¿verdad? Así que object.assign [TYPING] Así que esta sería una
implementación perfectamente válida, si supiéramos que no
existen los objetos dentro de los objetos. Pero como los hay, vamos
a tener que hacer algo de magia aquí. Entonces, ¿puede repetir su
recomendación de nuevo? PÚBLICO: Por lo tanto, verifique si alguno de los valores es un objeto. Entonces no puede simplemente tomar
ese valor en un nuevo objeto, solo para hacer referencia al mismo objeto
, necesitamos copiar ese objeto en profundidad, en lugar de simplemente tomar [INAUDIBLE]. JORDAN: Entonces, básicamente,
verifique cada valor y vea si es un objeto.
Si es un objeto,
continúe y copie en profundidad ese objeto. De lo contrario, devuelve ese valor. Frio. Así que hagamos eso. Entonces, la forma de obtener las claves de
un objeto es esta función llamada object.keys [TYPING] Entonces, al hacer object.keys
y pasar el objeto, ahora tenemos una matriz llena de los
valores de cadena de las claves en ese objeto. Entonces, lo que vamos a hacer es
iterar a través de esas claves. Compruebe si el
valor es de un objeto. Si es así, seguiremos adelante y clonaremos eso. No nos preocupemos por las funciones, o
cualquiera de esas otras cosas por ahora.
De lo contrario, simplemente devuelva ese valor. Así que, tengamos este ciclo for– [ESCRIBE] Y haz eso. Así que primero, definamos– [ESCÓGRAFO] Los nuevos objetos que
vamos a devolver. Y empecemos con
un objeto vacío por ahora. Entonces, ahora tenemos que verificar
si cada uno de estos valores es un objeto. Si es así, cópielo, de lo contrario devuélvalo. Entonces, ¿cómo vamos a verificar
el tipo de una clave en particular? AUDIENCIA: Tipo de operador. JORDAN: Sí, exactamente,
ese tipo de operador. Entonces podemos hacer si el tipo de
obj, y luego pasar por claves. [ESCRIBIR] Entonces, ¿qué queremos verificar? [ESCRIBA] Muy bien, ¿qué estoy haciendo mal aquí? AUDIENCIA: Tres iguales. JORDAN: Sí, siempre deberíamos
usar esos tres signos iguales. En este caso importaría. Pero, deberíamos adquirir
el hábito de hacer eso. Quiero decir, si observa aquí, en
realidad tenemos una notación de corchetes dentro de la notación de corchetes. Eso está totalmente bien. Frio. Entonces, si algo es un objeto
¿a qué nos vamos a dirigir? Podemos hacer objeto, nuevo
objeto con esa tecla.
[ESCRITA] Es igual a… ¿qué? AUDIENCIA: ¿El valor? Oh no, lo siento, copia profunda. JORDAN: Sí, copiemos en
profundidad ese valor a dos. [ESCRIBE] De lo contrario– [ESCRIBE] Podemos configurarlo
igual que la otra tecla. [ESCRIBIR] Y luego, al final,
podemos devolver ese nuevo objeto. [ESCRIBIENDO] Genial. ¿Alguien ve algún error? Dulce oportunidad. Muy bien,
sigamos adelante y probemos esto. Así que– vamos a hacer– Copie o– Luego actualice o– [ ESCRIBA] o.obj.key Digamos de a la nueva clave. [ ESCRIBIR] o3.obj.key. Deshazte de eso. Muy bien, entonces el momento de la verdad– [ESCRIPCIÓN] Clave, en lugar de nueva clave. Así que lo hicimos. Uf. Muy bien, ¿alguna otra pregunta sobre… objetos, mutación,
referencias, alguna de esas cosas? genial Entonces, las matrices también se
almacenan por referencia.
Entonces, si tuviéramos que hacer
exactamente el mismo ejemplo, y en lugar de actualizar el
objeto, actualizamos esa matriz , terminaríamos con exactamente los mismos resultados. Entonces, si tuviéramos que actualizar nuestra
función de copia profunda para que también se ocupe de las matrices, todo lo que tenemos que
hacer es también verificar, en lugar de verificar el objeto, también verificar las
matrices o cualquier otro tipo de datos que vamos a verificar. Pasemos a la herencia de prototipos. Entonces, ¿qué es exactamente la
herencia de prototipos? Bueno, entonces los tipos no primitivos
tienen algunas propiedades y métodos asociados con ellos. Entonces, matriz, tenemos esta
cosa llamada matriz.push, que agregará valores a una matriz. Por lo tanto, supongamos que tenemos algo como– [TIPEO] Una matriz vacía, si hicimos array.push– algún valor, entonces la matriz
ahora tiene algo en ella. Si le
metiéramos otro valor… Ahora tiene dos valores. Entonces array.prototype.push
es un método que tenemos disponible en todos los arreglos, que
simplemente agrega nuevos valores a un arreglo. Otro sería como,
string.prototype.toUpperCase.
Entonces, supongamos que tuviéramos que
tener una cadena, así que– [ESCRIBIR] Si haces str.toUpperCase– Ahora, nos queda una nueva
cadena con todo en mayúsculas. Entonces, estas son solo funciones que
podemos invocar en cualquier no primitivo que nos brinde algo más. Eso está disponible para todos los
no primitivos de un tipo dado. Entonces cada objeto almacena una
referencia a su prototipo.
Es decir, tiene todo el…
sabe acerca de todos estos métodos. Y almacena una referencia al
objeto para saber dónde están estos métodos: el código para ejecutarlo realmente. Y digamos que tenemos una
cadena de prototipos donde hay un montón de métodos diferentes con
el mismo nombre. Cualquiera que esté ligado más estrechamente
a la instancia tiene la prioridad. Digamos que tenemos un objeto en
una matriz, donde matriz es el– Digamos que tenemos un valor que es de
tipo matriz, en la cadena de prototipos tenemos matrices, su prototipo es una
matriz, ese prototipo es un objeto.
Digamos que tenemos el mismo
método con nombre en ambos. Si llamamos a ese método, el
que esté más unido a la matriz tendrá prioridad. Así que vamos a mostrar eso. Entonces, digamos que tenemos algo como– Así que matriz, tiene una
referencia a sus prototipos. Así que si hiciste array dot, double
underscore, proto, double underscore, vemos este objeto grande con
un montón de funciones diferentes. Y entonces vemos aquí abajo, empujar, que
es el que invocamos antes. Entonces, así es exactamente como sabe
dónde está esa implementación de empuje. Y entonces podemos hacer
arr.__proto__.__proto__, e ir aún más arriba en la cadena. Así que este tiene un montón de
otros para valor de cadena, lo que sea.
Y si nota, tanto el
prototipo de matrices como el prototipo de prototipos de matrices , tienen este
método llamado toString. Y si tuviera que invocar
arr.toString, ¿cuál de estos se llamará realmente? AUDIENCIA: La segunda. JORDAN: ¿El segundo? ¿Cuál es el segundo? AUDIENCIA: punto proto, punto proto. [INAUDIBLE] JORDANIA: punto proto, punto proto. Entonces, en realidad todo lo contrario. Entonces, dado que toString,
en el prototipo de matriz, es más específico que el
método toSting en el prototipo de objeto, este será invocado. Porque es, solo porque
es más específico. Porque una matriz es una
matriz y es un objeto. Pero es más específico llamarlo
matriz que llamarlo objeto. Entonces va a invocar
el que está en la matriz. ¿Tiene eso sentido? ¿Alguien tiene una pregunta sobre eso? Es un concepto importante y
un poco confuso al principio. Frio. La mayoría de los tipos primitivos
tenían envoltorios de objetos. Y entonces hablamos sobre
cómo los tipos primitivos no tienen ningún método asociado con ellos.
Pero los tipos primitivos
también tienen envoltorios que tienen prototipos asociados con ellos. ¿Qué diablos significa eso? Entonces, si tuviera que hacer
42.toString , sería como, ¿qué diablos quieres decir? 42.toString– [TYPING] Bien, te dije que estos
valores primitivos no tienen métodos. Y entonces 42.toString
realmente no tiene sentido. Pero digamos que tengo que hacer esto
const num = 42 e hice num.toString, [TYPING] Eso realmente hará algo. Y eso es un poco extraño. Este es otro de esos
comportamientos interesantes de JavaScript. Porque todos los
valores primitivos tienen contenedores que les dan acceso
a un montón de métodos.
Y JavaScript automáticamente
hará lo que se llama boxeo por ti. Lo que dice, hey,
sé que 42 es un primitivo, pero si llamas a este
método toString, sé lo que quieres decir. Voy a encuadrar este
número 42 con este prototipo que tiene muchos de estos métodos. Entonces, si tuviera que hacer 42.toString,
eso tendría sentido. Y si pongo num.__proto__, [ESCRIBIENDO] Eso realmente existe. Pero 42.__ proto__ [Escribiendo] no. ¿Tiene sentido? Otra forma de averiguar si un
valor es una instancia de algún tipo , puede hacer esto
llamado x instancia de número. Y eso devolvería falso. Debido a que x en realidad no es
del tipo de número en mayúscula , simplemente está encuadrado alrededor de ese
objeto numérico para su referencia. ¿Tiene sentido? Nuevamente, no es algo que vaya a
usar todos los días, solo algo que es útil saber en caso de que
se encuentre con casos extraños en las esquinas. Frio. Entonces, ¿por qué usaríamos una
referencia al prototipo? ¿Y cuál es la alternativa allí? ¿Alguien quiere darle una oportunidad a eso? Así que esto se remonta a una copia demasiado
profunda frente a una copia superficial.
AUDIENCIA: Entonces, tal vez si el
objeto inicial es masivo. ¿Y luego solo quieres hacer
algo, como, después de eso? JORDAN: Sí, así que si el objeto inicial
es masivo, ¿qué sucede entonces? Entonces, la alternativa es
básicamente clonar cada uno: copiar en profundidad cada
prototipo cada vez que no pueda obtener un nuevo valor. Lo cual es seguro, porque ese
número y todos sus métodos están todos encapsulados dentro de
esa variable específica. Pero también es un poco
caro en rendimiento, porque tienes que hacer esa
copia profunda cada vez. Y también de memoria, porque el
objeto empieza a hacerse bastante grande. Y si tiene una variedad de
como 100 cosas diferentes, todos los cientos de ellos, la copia profunda de
cada prototipo se vuelve bastante grande. Entonces, ¿cuál es el peligro de almacenar
una referencia al prototipo, en lugar de copiarlo todo? PÚBLICO: Supongo que si lo
cambia, [INAUDIBLE] JORDAN: Sí, exactamente. Si lo cambia, entonces cambia
para cada valor individual de ese tipo.
Así que hagámoslo muy rápido. Entonces, digamos que tenemos, entonces resolvimos
num, que es igual a 42, ¿verdad? Y si haces num.toString,
¿qué esperamos que salga? 42 es una cadena, ¿verdad? Pero digamos, algún
programador tortuoso estaba haciendo esto en el que hizo number.prototype.toString [TYPING] Y en realidad anulas eso para que sea
una función que devolverá 100. Ahora, ¿qué sucede si
llamo a num.toString? Espera un segundo. [ESCRIBIR] Así que eso podría tener algunas
penalizaciones peligrosas, ¿verdad? Entonces, si tuviera que cambiar el
prototipo de la clase numérica, aunque num se declaró 100
líneas antes de ser el número 42.
Y probamos num.toString
aquí y devolvió 42. Si tuviéramos que cambiar
el prototipo más tarde , afectaría todo lo
que ha pasado alguna vez. Entonces num.toString ahora
comienza a devolver 100. Y todo lo que sucederá. Así que si tuviera que hacer– [ESCRIBA] Todo en el futuro
también tiene esas consecuencias. Por lo tanto, cambiar el prototipo
es algo muy peligroso y se recomienda no hacerlo.
¿Tiene sentido? Frio. Así que tomemos un breve descanso. Bien, bienvenido de nuevo. Entonces, hablemos ahora del alcance. Entonces, ¿qué diablos es el alcance? Por lo tanto, Ámbito es un término que se
refiere a la duración de las variables y cuánto tiempo
existen realmente estas variables. Así que hay un par de
tipos diferentes de alcance. Existe el alcance léxico, que es
esa palabra clave var que podría ver si está leyendo JavaScript antiguo. Y está el ámbito de bloque, que se
refiere a cómo se analizan cosas como const o let. Entonces, el alcance léxico básicamente
dice, oye, dame una variable y
existirá desde que se declaró hasta el
final de una función o el archivo si está en un archivo. Mientras que el análogo
sería un alcance de bloque donde se comporta de manera muy similar a como
algo se comporta en C.
Donde básicamente una
variable estará presente desde que se declara hasta que
se alcanza la siguiente llave. Y para que exista la gran diferencia
entre var y const y let. Y la diferencia
entre const y let es que const es algo
que no se puede actualizar, lo que significa que si configuro una variable
para que sea una constante, significa que no voy a
actualizar esa referencia más tarde, mientras que let se puede actualizar. Entonces, si tuviera que hacer const
thisIsAConst y estableciera algo así como 50, si dijera thisIsAConst
y tratara de actualizar eso para que sea 51, obtendré un error
que dice, oye, llamas a eso un constante? Pero estás tratando de cambiarlo.
Eso no está bien. Y no importa
cómo quiera cambiarlo, digamos que hago ese plus-plus o
algo así, eso también va a fallar. Mientras que si hice algo como
dejar que thisIsALet sea igual a 50, puedo seguir adelante, o 51, cometí
un error tipográfico, pero solo puedo decir, oye, fue un error tipográfico, thisIsALet, déjame
cambiar eso a 50 y listo. esta todo bien Quiero decir, también puedo hacer ese plus-plus
o cambiarlo como quiera y en realidad lo actualizará. Tenga en cuenta que dije que la
referencia no se puede actualizar. No dije nada acerca de que las
cosas fueran inmutables. Entonces, si obtengo que const obj es igual a
este objeto vacío, si entonces, no puedo actualizarlo para que sea, apunto a un objeto diferente. Si trato de hacer obj es otra
cosa, voy a decir, oye, llamas a esto const y
estás tratando de cambiarlo.
Pero aún puedo hacer obj.a y establecer
eso igual a a, porque ¿por qué? ¿Alguien quiere decirme por qué? Exactamente. Así que el puntero sigue
apuntando al mismo objeto. La referencia no ha cambiado. Así que mutamos ese
objeto, pero todavía apunta al mismo lugar en la memoria. Todavía apunta al
objeto que existe aquí y esa referencia no ha cambiado. ¿Esa distinción
tiene sentido para las personas? Es bastante importante. Genial Entonces, juguemos un poco
con estas vidas útiles variables. Entonces dije antes que si intentaba hacer
algo como esto, ¿qué sucede aquí? Error.
¿Por qué? Porque es una constante y
no podemos actualizar una constante. Y podemos confirmar esto. Oh. De hecho
, nos dirá, oye, un TypeError. Llamas a esto una variable constante
pero estás tratando de asignarla. Eso no está bien. Pero si lo hicimos, está bien porque la referencia
a ese objeto no cambió , simplemente lo mutó. Por otro lado, si hicimos algo
como let thisIsALlet A Let igual a 51, y luego queremos cambiar eso
más tarde, vamos a 50, está totalmente bien. Pero si en realidad traté de
reasignar– así que deja que thisIsALet. Si intento hacer esto de nuevo, me va
a gritar porque está diciendo, hey , ya declaraste
algo llamado thisIsALet. No puedes declarar eso de nuevo. Y así, const y let
realmente lo protegen de declarar algo con el mismo
nombre de variable dos veces, que es algo que var no hace. Frio. ¿Qué creen que
pasaría si tratara de hacer esto? ¿Alguien quiere adivinar? ¿Indefinido? Así que intentemos ejecutarlo.
Error. Entonces, dado que estas cosas
tienen un alcance de bloque, significa que la variable se declara
en la línea en la que está escrita. Y si intentamos usarlo antes de eso
, en realidad ni siquiera existe. Entonces, si traté de consola.
registrar algo llamado thisIsAConst aquí, recuerde, el intérprete de JavaScript
solo está leyendo y no verá, oye,
¿qué diablos es thisIsAConst? No tengo idea de qué es eso
, así que solo voy a Error aquí. Lo mismo si traté de
hacer esto como let aquí. Eso también dará error
con el mismo error. AUDIENCIA: Entonces, ¿cuál es el error de la línea 14? JORDAN: ¿Por qué da error? Porque estamos tratando de declarar dos
variables con el mismo nombre de variable dos veces. Así que hemos dejado que thisIsALet sea igual a
51 aquí, y tratamos de hacerlo de nuevo y dice, oye, ya
tienes una variable llamada thisIsALet, así que no voy a permitir
que lo hagas de nuevo. Así que va a ser
este error aquí.
AUDIENCIA: Entonces, ¿es la
instanciación de eso? JORDANIA: Sí. Está diciendo como– básicamente estoy
diciendo, oye, dame una variable para llamar, esto es un let aquí, y luego un
par de líneas después digo, oye, dame una variable
llamada thisIsALet, y JavaScript dice,
oye, ya tienes una variable de alcance de bloque
llamada thisIsALet, así que no puedo darte otra. Sin embargo, si trato de
actualizarlo así, está totalmente bien. ¿Alguna otra pregunta aquí? Entonces, la otra cosa que dijimos, podemos
hacer que estas cosas se llamen var. Si hice var thisIsAVar igual a
50, está bien, puedo actualizarlo. Eso también está bien. También puedo hacer esto, y
eso no me gritará.
Entonces, vars son formas más antiguas
de declarar variables y no tienen la misma
protección que let y const. Puede anularlos
así y está totalmente bien. Y en realidad puede declarar una
variable completamente nueva con el mismo nombre de variable y eso también está bien. Y algo… ¿sí? Es solo… sí, eso es… Así que si trato de ejecutar esto
, actualizará el anterior. Simplemente reemplazará ese valor. En realidad, se llama sombreado,
donde crea una nueva variable con el mismo nombre de variable
que básicamente eclipsa a la anterior.
Entonces es como si el
otro no existiera. Genial, así que echa un vistazo a esto. Entonces estos errores y nosotros conocemos estos errores. Pero digamos que yo fuera a hacer esto. Es de esperar que esto también
produzca un error, pero en realidad no es así. Devuelve indefinido. Así que esta es otra
cosa extraña sobre JavaScript. Esto se llama izar. Y así, ciertas cosas
se elevan, lo que significa que básicamente toma
la definición de algo y la eleva a la parte superior
del archivo y lo hace primero. Obtener Y algunas cosas se izan.
Var the– en realidad, la declaración
de la creación de una variable vacía se iza. Las definiciones de función también se
elevan, pero const y let no, como vimos si intentamos acceder
al nombre de la variable de const o let, entonces se produce un error. Pero con una var, la declaración de
esa variable en realidad se eleva. Y podemos hablar un poco más
sobre cómo funciona eso en un segundo, pero
juguemos un poco más con eso.
Por lo tanto, las definiciones de funciones se elevan. Así que vamos a limpiar
un poco este archivo. Así que llamemos a esta
nueva función, llamada– así que esto es console.log. Así que definí esta función
llamada thisIsHoisted en la parte inferior del archivo. Y todo lo que hace es
console.logs, hay una función declarada en
la parte inferior del archivo. Pero algo muy interesante está en la
parte superior de este archivo, puedo llamarlo. Y eso realmente funcionará. Y eso es lo que se
llama elevación de funciones. El comportamiento mediante el cual
una definición de función declarada en la parte inferior de un
archivo también está disponible para su uso en la parte superior del archivo. Pero esto no funciona en otros casos. Así que digamos que iba a hacer algo como esto. Entonces, ¿quién puede decirme cuál es la
diferencia entre la línea 21 y la línea 25? Se ven bastante similares, ¿verdad? ¿Sí? está bien. Sí. Entonces, repitiendo para la cámara, la línea 25,
thisIsHoisted se declara como una constante, por lo que no se puede cambiar, mientras que la línea 21
se declara como una función y, por lo tanto, se puede cambiar, lo cual es absolutamente correcto.
¿Qué pasa si trato
de hacer esto aquí arriba? Sí, entonces vamos a obtener un error. thisIsHoisted no está definido, pero ¿por qué? Porque, como mencionamos
anteriormente, estas cosas llamadas consts no están disponibles para su
uso hasta que realmente se declaran. Así se izan ciertas cosas. Var. Por lo que se izan las declaraciones de estas
variables. Las definiciones de funciones, si se
declaran así, se elevan. Pero si creamos lo que se
llama una función anónima, una función sin ningún nombre,
y la igualamos a… o la asignamos para que sea una constante,
entonces esa constante no se crea. ¿Tiene sentido? Entonces, ¿qué sucede si trato de hacer esto? Sí, pues lo mismo. Tiene errores. ¿Qué sucede si trato de hacer esto? ¿Qué se iza? Así que fíjate, fíjate en la
diferencia entre los dos errores. En realidad, no son
exactamente el mismo error. Entonces, ¿quién quiere adivinar
lo que está pasando aquí? Entonces, cuando lo declaré con un let
que dice error de referencia, thisIsHoisted no está definido,
mientras que cuando uso una var , dice TypeError,
thisIsHoisted no es una función.
¿Por qué podría ser eso? ¿Sí? UH Huh. Exactamente. Entonces, repitiendo para la cámara, y
también mostraré el código. Entonces, aquí abajo, la primera vez
que declaramos esto con let , no se declaró en absoluto. Esta variable no existe en absoluto. Así que esto no está levantado,
el JavaScript no sabe lo que eso significa en la línea 1. Pero cuando uso una var
aquí, recuerda, levanta la declaración de esta variable. Entonces crea una variable
llamada thisIsHoisted. Sin embargo, no le asigna un
valor hasta que se ejecuta la línea 25. Y así, en la línea 1, thisIsHoisted existe. Es simplemente igual a indefinido. Y si trato de
invocarlo como una función , dice, hey, esta es
una variable indefinida, no puedo invocarlo como una
función, esto es un TypeError.
Y así, aunque ambas cosas
fallaron, la razón por la que fallaron es ligeramente diferente. En caso de que se
declaren usando una const o un let, esa variable simplemente
no existe en absoluto. Sin embargo, cuando declaramos
usando var, la variable existe. Simplemente no está definido, por lo que si
tratamos de invocarlo como una función y dice, bueno, esto
no está definido, no es una función. ¿Tiene eso sentido para todos? Entonces, ¿por qué pasa ésto? ¿Como sucedió esto? Y la razón es en realidad
cómo se ejecuta JavaScript. Así que hay dos fases en la
ejecución de un archivo JavaScript. Entonces, antes de ejecutar cualquier código,
tiene todo el texto delante, pero no ha ejecutado nada
, solo lee el archivo completo. ¿Y qué busca? Bueno, uno, está buscando
cualquier problema con el archivo.
Entonces digamos como mi primer ejemplo
cuando tenía una matriz y le faltaba una coma, eso es algo que se
detecta en la primera lectura. Dice, hey, como, esto parece
una matriz pero no está del todo bien. Como, veo esta cosa que no estoy
esperando, estoy respetando una coma aquí. Así que eso es una cosa que está atrapada.
Otras cosas, tal vez
agregue algunos puntos y comas para usted y cosas así. Y luego cualquier definición de función
simplemente se guarda en la memoria. Dice, hey, esta es una función,
pongamos esto en la memoria para que si alguien quiere
usarla en la línea 1, pueda hacerlo. Inicializaciones de variables, si
tienen un alcance léxico, o quiero decir, si tienen un alcance
léxico, se declararán, pero no se inicializarán. Lo que significa que cualquier cosa
declarada con var será declarada, como
si existiera una variable, pero no se establecerá
igual a nada hasta más tarde. Y luego hay una segunda fase llamada fase de
ejecución, en la que el código se ejecuta, se ejecuta. Y ahí es cuando
se invocan cosas como const o let, o se declaran e inicializan. ¿Tiene eso sentido para todos? ¿Alguien tiene alguna pregunta sobre el alcance? Entonces, ¿por qué podríamos
aprovechar este alcance? ¿Parece una característica
o parece un error? ¿Alguien quiere adivinar? No hay una respuesta correcta para esto.
Es completamente una opinión. ¿Sí? AUDIENCIA: Así que tienes un controlador
con funciones matemáticas. JORDANIA: Ajá. AUDIENCIA: ¿Puede llamar a los que
están allí y establecer un archivo para que pueda escribir todo
su código en una función gigante? JORDAN: Sí Entonces, una
cosa podría ser que podemos tener estas
declaraciones de funciones en la parte inferior y luego podemos usarlas en la parte superior. Y eso podría ser bueno
para la organización del código. Como alguien que lea
su código sabría, oye, si estoy buscando
estas funciones, todas se declararán
juntas en la parte inferior.
Y pueden usarse en todas partes,
pero todas las declaraciones de funciones van a estar aquí. Esa podría ser una característica
porque es buena para la organización. Así que digamos que vamos a hacer de abogado del [ __ ]. ¿Quién podría ver esto como un error? UH Huh. está bien. Entonces, la pregunta es, ¿por qué
podemos declarar dos variables con el mismo nombre cuando
parecen estar en el mismo ámbito, específicamente con esta palabra clave var? Lo cual es otra cosa donde es un
error/característica que mucha gente usa.
Entonces, si se actualizara JavaScript
y ese error/característica desapareciera, se rompería una gran cantidad de código. Así que mucha gente se ha
aprovechado de esto. Y básicamente es lo mismo que
, ¿por qué typeof es un objeto nulo? Solo porque lo es. Y no podemos cambiar eso porque la
gente confía en ese comportamiento. Sé que es una especie de anti-respuesta,
pero ¿tiene sentido? Sí, deberías… así que ya no hay
una buena razón para usar var. Con ES6, todo es
compatible con const y let. Y por eso los he estado usando en
todos los ejemplos excepto en estos.
Y creo que
definitivamente deberías usarlos también. La razón por la que obtengo var
es uno, así que si ve esto , sabe qué está pasando, y
porque mucho código heredado, mucho código escrito hace dos, cinco
años, hace 10 años usa var solo
porque era la única opción. Una cosa que no mencioné
antes es que también puedes declarar una variable como esta. Así que esta es otra forma
de declarar una variable. Esto crea una variable global. Es algo que
probablemente no verás tan a menudo, realmente no hay razón para hacerlo. Pero en caso de que alguna vez veas
eso, eso es lo que es. Entonces, si declara una variable sin
darle una palabra clave como let, const o var, la crea globalmente. Pero no hay ninguna razón para
que uses esto, de verdad. Es solo que si alguna vez lo
ves, eso es lo que es. ¿Alguna pregunta sobre el alcance? Es un concepto bastante importante. Y también para la gente en línea,
recuerde que puede publicar en Slack y el personal
responderá esas preguntas o me las pasará.
Genial Así que pasemos a
nuestro tema final del día. Así que el objeto global. Entonces, la forma en que funcionan todas estas cosas
es básicamente en cualquier tiempo de ejecución dado, existe una cosa
llamada objeto global. Entonces, todas las variables, todas las
funciones son en realidad claves, parámetros o
métodos en el objeto global. Entonces, en el navegador, hay una
cosa llamada ventana que es un objeto global de una ventana. Así que este es un entorno de navegador. Y si escribo ventana, veo esto. Y tiene mucho dentro. Pero básicamente la ventana
es este objeto global, y en él hay todo tipo de cosas. Entonces vemos $0, $0a. Así que estos– así que cualquier variable
que declares en esta consola se pone en este
objeto global llamado ventana. Y, en realidad, déjame abrir
una nueva pestaña del navegador.
Y obtendremos un
poco de una ventana más limpia. Entonces, la razón por la que vimos estas
cosas llamadas $0, $lo que sea, es porque abro estas herramientas de desarrollo en
la misma pestaña que las diapositivas de mi conferencia. Y la forma en que funciona Google
Slides es que, dado que es algo dinámico en la web
, tiene que usar JavaScript. Y como está usando
JavaScript, obviamente está creando un montón de funciones
, está creando un montón de variables. Y todas estas cosas
terminan en el objeto ventana. Entonces, cuando revisamos,
cuando inspeccionamos el objeto de la ventana de esa pestaña en particular,
había un montón de cosas porque así es como
funciona Google Slides. Y cuando creamos una nueva
pestaña, esta es una pestaña completamente nueva y, por lo tanto, no
se ha ejecutado JavaScript, por lo que hay muchas menos variables
y otras cosas en esta nueva pestaña.
Entonces, cada vez que
creamos nuevas variables, digamos que hacemos const x es igual a esta es
una nueva variable, vemos que x es esto. También podemos hacer esto window.x– Lo declaro como const. Entonces, la forma en que las ventanas del navegador
manejan estos bloques de variables es un poco diferente. Entonces usaremos var por
el bien de la explicación. Entonces, cuando creo esta nueva
variable llamada var y , es exactamente lo mismo que window.y.
Entonces, si inspeccionamos la ventana, vemos un montón de cosas que son parte
de la API de JavaScript, la API del navegador , todas estas cosas. Y si vamos
hasta el final , esto es lo que se
crea en la nueva pestaña. L, M, N, O, P, Q, R,
S. Vemos esto y aquí. Entonces, parte de ese objeto de ventana
es esa variable llamada y que pegamos en la ventana.
Y así, aunque lo
declaramos con var y es igual a algo , terminó en ese
objeto global, y así es como JavaScript realiza un seguimiento
de todos sus objetos de valor y demás. Entonces, ¿qué sucede cuando estamos en el
entorno del nodo y escribimos ventana? la ventana arriba no está definida. Y es que en
el entorno del nodo, la variable global no se llama
ventana, en realidad se llama global. Y si escribimos global,
ahora vemos todas estas cosas. Y mucho de esto se superpondrá con
ese objeto de ventana en el navegador, pero dado que la API del navegador tiene
cosas que no se usan necesariamente en la línea de comandos
, como, dame un nodo DOM o dame CSS en este nodo DOM,
cosas así, que realmente no tienen sentido en una interfaz de línea de
comandos, por lo tanto, esas cosas no están en este objeto global.
Y luego, si tratamos de escribir
global, aquí en la ventana, eso tampoco tiene sentido. Hay otra cosa que
es importante saber, pero es posible que nunca la
aproveches. Pero, ¿eso… tiene sentido? Frio. Entonces, pasemos a algo que
discutiremos mucho más en la próxima lección, pero seguiré adelante e introduciré
el concepto en esta lección y los dejaré con un
pequeño adelanto. Entonces, ¿quién aquí ha oído hablar
de un cierre antes? Así que los cierres son en realidad
una de las cosas que
más odian los programadores de JavaScript porque es un concepto muy, muy
difícil de aprender.
Sobre todo porque siempre se
enseña algo mal. Así que la próxima vez
intentaré hacer un buen trabajo enseñándoles, pero les mostraré ahora mismo
el problema al que se enfrenta mucha gente. Entonces, lo que son los cierres son funciones: es un comportamiento mediante el cual las funciones
que se refieren a variables declaradas por una función principal
aún existen, y posiblemente se deba al alcance. ¿Qué diablos significa eso? Lo explicaré en la próxima
lección, pero sigamos adelante y exploremos lo que esto realmente significa. Está bien. Así que hagamos esto. Entonces, lo primero
que haré es declarar una matriz vacía
llamada matriz, y la llenaré con algunos valores. Eso es Y estoy usando var intencionalmente. Y eso es presionar una
función que hace esto.
Muy bien Entonces, ¿qué
diablos hice aquí? Así que declaré una función
llamada makeFunctionArray, y todo lo que hace es crear una
matriz, llenarla con funciones y luego invocar una de ellas. Entonces, si tuviera que llamar a esto, si tuviera que llamar a esto, obtendría
una matriz llena de funciones, ¿verdad? ¿Y qué esperamos que hagan esas
funciones? ¿cada uno de ellos? Imprime un número, ¿verdad? Entonces, lo que debería
suceder es que debería… Debería poder recorrer esta
matriz, invocar cada una de esas funciones y recuperar algo
que cuente, ¿verdad? ¿Básicamente? Entonces, veamos qué sucede. Así que solo voy a acceder
al primero y lo invoco, y esperamos que imprima 0. Así que hay uno,
el peor enemigo de un programador de JavaScript, porque es algo inesperado,
y como veremos en las próximas conferencias. , eso es realmente como se esperaba.
Así que los dejaré en ese
suspenso para la próxima vez , seguiremos adelante y
terminaremos oficialmente la conferencia. Me quedaré si tienes alguna pregunta.