Julian Levy
@julianilevy
Buenos Aires, Argentina
@julianilevy
Buenos Aires, Argentina
Julian Levy@julianilevy
Ya que en el video no está del todo claro el por qué se usa ~~~function.bind(object)~~~, voy a intentar explicarlo de la forma más simple posible:
Antes que nada, hay que entender el concepto de ~~~this~~~ en JavaScript. Cuando utilizamos ~~~this~~~, siempre hacemos referencia al objeto del contexto actual, ¿Y qué significa esto? Significa que estamos accediendo a una propiedad o método del objeto que envuelve al código en el que estamos parados actualmente.
Por ejemplo, si creo una clase "Perro", cada vez que escriba DENTRO de la clase algo como ~~~this.altura~~~ o ~~~this.ladrar()~~~, estoy haciendo referencia a una propiedad (altura) o a un método (ladrar) que sólo existe dentro de "Perro". La forma más simple de entenderlo, es tomar la traducción literal de "this", que significa "esto" en español. Entonces, cuando esté programando y escriba ~~~this~~~, simplemente pienso en el "esto" que envuelve al código que estoy escribiendo actualmente. Si miro unas líneas más arriba y veo que está todo dentro de la clase "Perro", entonces sé que "esto" (this) significa "Perro", por lo que cualquier propiedad o método que escriba allí pertenece exclusivamente a "Perro" (this).
Algo importante a tener en cuenta: cuando escribimos ~~~this~~~ fuera de cualquier clase u objeto, siempre vamos a estar haciendo referencia al objeto global ~~~window ~~~. Básicamente, todo lo que escribimos en JavaScript está contenido dentro de ~~~window~~~.
Ahora, sabiendo todo lo anterior, estamos listos para entender la utilidad de ~~~function.bind(object)~~~.
En JavaScript, los métodos que declaramos dentro de una clase u objeto permanecen enlazados a esa clase u objeto siempre y cuando no se asignen a una constante o variable externa. ¿Qué quiero decir con esto? Que el ~~~this~~~ del método puede cambiar, y no necesariamente va a apuntar al mismo objeto en el que se declaró el método.
Siguiendo el ejemplo anterior, si dentro de la clase "Perro" está el método ~~~ladrar()~~~, podemos suponer que este método accede a propiedades internas de "Perro" como pueden ser ~~~this.lengua~~~ o ~~~this.hocico~~~. En un llamado normal a este método que se haga desde fuera de la clase, como es ~~~perro.ladrar()~~~, sabemos que cualquier ~~~this~~~ que haya dentro del método hace referencia a ~~~perro~~~. Bueno, la cosa cambia totalmente cuando asignamos ~~~this.ladrar()~~~ a una constante o variable externa a la clase. Si declaramos algo como ~~~const ladrarExterno = perro.ladrar~~~ y llamamos a ~~~ladrarExterno()~~~, el ~~~this~~~ de ~~~ladrarExterno()~~~ va a pasar a ser el objeto del contexto actual, que normalmente es ~~~window~~~, salvo que estemos dentro de una clase u objeto. En un caso como este, al ejecutar nuestro código recibiríamos un error, ya que ~~~ladrarExterno()~~~ estaría intentando acceder a ~~~this.lengua~~~ o ~~~this.hocico~~~ siendo que nuestro nuevo ~~~this~~~ (el objeto ~~~window~~~) no contiene ninguna de esas propiedades.
Para solucionar un problema como el del ejemplo anterior es que utilizamos ~~~function.bind(object)~~~. Lo que hace esto es devolvernos una copia exacta de la función, pero ahora es una función que realmente está enlazada al objeto que le pasemos por parámetro. Haciendo uso del ~~~bind~~~, no importa dónde o a qué constante o variable le asignemos esta nueva función, su ~~~this~~~ SIEMPRE apuntará al objeto que le hayamos pasado por parámetro.
Sabiendo todo esto, ¿Pór qué el profesor escribe ~~~this.vender = this.vender.bind(this)~~~ en el constructor de la clase "Cupcake"?
Lo que hace es crear una nueva propiedad en "Cupcake": ~~~this.vender~~~, a la que le asigna una copia del método ~~~vender()~~~ en la cual su ~~~this~~~ siempre apuntará al ~~~this~~~ que le envió por parámetro, que en este caso es "Cupcake" (aclaración: siempre apuntará al objeto instanciado a partir de "Cupcake", no a la clase "Cupcake" en sí). Una vez hecho esto, y gracias a la utilización del ~~~bind()~~~, puede asignar este nuevo ~~~this.vender~~~ al método ~~~onClick~~~ de ~~~button~~~ sin perder la referencia del ~~~this ~~~ original.
La explicación resultó un poco extensa, pero espero que pueda entenderse con claridad. Para cerrar, voy a dejar una imagen del ejemplo de la clase "Perro" con código y resultados en consola, como para despejar cualquier duda posible sobre el uso y funcionamiento del método ~~~bind()~~~.
Saludos.
Julian Levy@julianilevy
Aún usando componentes de clase, es posible utilizar los props de forma más prolija y menos engorrosa.
Con la desestructuración de ~~~this.props~~~, podemos desempacar únicamente los valores que vamos a utilizar y guardarlos en una constante para facilitar su acceso más adelante.
Tomando de ejemplo las props de ~~~Cupcake~~~, es tan simple como declarar ~~~const { color, sabor, foto } = this.props;~~~ dentro de la función ~~~render()~~~, y obviamente antes del ~~~return()~~~.
Julian Levy@julianilevy
Si las variables son públicas no tiene mucho sentido usar los métodos ~~~get~~~ y ~~~set~~~, ya que igualmente voy a poder tener libre acceso a la variable.
Por ejemplo, ¿Para qué quiero un ~~~getNombre()~~~ y un ~~~setNombre()~~~ si igualmente tengo permitido acceder a ~~~objeto.nombre ~~~?
La idea es que las variables de un objeto sean siempre privadas y su acceso desde otras secciones del código sólo pueda darse a través de los getters y setters (u otros métodos), respetando así el principio de encapsulamiento en POO.
Para hacer nuestra variable privada, simplemente necesitamos agregar un # (hash) como prefijo de su nombre. Por ejemplo: ~~~#nombre~~~, ~~~#apellido~~~, etc.
También aplica lo mismo para los métodos privados, por ejemplo: ~~~#hablar() {}~~~, ~~~#tomarCurso() {}~~~, etc.
Para más información: https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Classes/Private_class_fields
Julian Levy@julianilevy
El 56.25% que se le asignó al ~~~padding-bottom~~~ no es un número aleatorio, viene de la siguiente fórmula:
Entonces, si buscamos un aspect ratio de 16:9, haríamos lo siguiente:
Para un aspect ratio de 4:3:
Y así con el aspect ratio que queramos.
Este link tiene más información sobre el tema: https://www.w3schools.com/howto/howto_css_aspect_ratio.asp (ahí utilizan ~~~padding-top~~~ en vez de ~~~padding-bottom~~~, pero es lo mismo).
Julian Levy@julianilevy
En el vídeo no está muy bien explicado, así que lo resumo en lo siguiente:
En programación, que una entidad sea considerada "ciudadano de primera clase" significa que puede hacer lo mismo que las otras entidades, como ser retornadas de funciones, asignadas a variables, pasadas como parámetros, etc.
Por ejemplo, cuando hablamos de un ~~~boolean~~~ sabemos que puede ser retornado de una función, cuando hablamos de un ~~~string ~~~ sabemos que puede ser asignado a una variable, cuando hablamos de un ~~~number~~~ sabemos que puede ser pasado como parámetro. Tanto ~~~boolean ~~~ como ~~~string ~~~ como ~~~number~~~ son entidades de primera clase (o "ciudadanos de primera clase"), por lo que pueden manipularse de la misma manera que una entidad ~~~function~~~, que también es de primera clase. Esto significa que también puedo retornar un ~~~function ~~~, que también puedo asignar ~~~function~~~ a una variable (el ejemplo del vídeo), y que también puedo pasar un ~~~function~~~ como parámetro, entre otras cosas.
En el vídeo puede darse a entender que las funciones sólo son "ciudadanos de primera clase" cuando se asignan a una variable, lo cual es falso. Lo que intentaba explicar Beto en el vídeo es que las funciones pueden ser tratadas igual que un ~~~boolean~~~, ~~~string~~~, ~~~number~~~ u ~~~object~~~, y lo ejemplificó justamente asignando una ~~~function~~~ a una variable.
Julian Levy@julianilevy
Por lo visto en el vídeo, entendemos que el sistema hexadecimal usa 16 símbolos distintos:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9 para representar esos mismos números.
A, B, C, D, E, F para representar los números 10, 11, 12, 13, 14, 15.
También sabemos que en hexadecimal podemos representar los 3 canales RGB usando 3 pares de valores, o sea, un par para cada canal:
Los 2 primeros valores para R (Red).
Los 2 valores del medio para G (Green).
Los 2 últimos valores para B (Blue).
Por ejemplo: con el valor hexadecimal #19BD1E, asignamos 19 a R, BD a G, y 1E a B.
Sabiendo todo lo anterior, ¿Cómo convertimos cualquier valor hexadecimal en RGB? Esto es bastante simple, tenemos que hacer lo siguiente en los 3 canales (R,G y B): multiplicar el primer valor * 16, y al resultado de esa multiplicación sumarle el segundo valor.
De manera que la explicación quede lo más clara posible, vamos a convertir el hexadecimal del ejemplo (#19BD1E) en RGB:
Para el canal R: multiplicamos 1 (primer valor) * 16, lo que nos da un resultado de 16. A eso le sumamos 9 (segundo valor), lo que nos termina dando 25.
Para el canal G: multiplicamos B (11, primer valor) * 16, lo que nos da un resultado de 176. A eso le sumamos D (13, segundo valor), lo que nos termina dando 189.
Para el canal B: multiplicamos 1 (primer valor) * 16, lo que nos da un resultado de 16. A eso le sumamos E (14, segundo valor), lo que nos termina dando 30.
Habiendo hecho el cálculo en los 3 canales, ya tenemos el valor convertido a RGB (25, 189, 30). Ahora podremos hacer la misma conversión con cualquier otro valor hexadecimal sin ningún problema.
Espero que les sea de utilidad.
Julian Levy@julianilevy
Por si la explicación en el vídeo no quedó del todo clara, voy a intentar explicar lo que es el Device Pixel Ratio de la forma más simple posible:
Para empezar, existen 2 tipos de píxeles:
Píxeles físicos: son los píxeles reales que están en un monitor, smartphone, tv, etc. Por ejemplo, cuando se habla de 1920x1080 (Full HD), se refiere siempre a una pantalla de 1920 píxeles FÍSICOS de ancho y 1080 FÍSICOS de alto.
Píxeles CSS (o del viewport): es la unidad de medida con la que trabaja CSS para pintar elementos en el viewport, y NO siempre son del mismo tamaño que un píxel físico.
Ahora bien, ¿Qué es el Device Pixel Ratio (DPR)?: el DPR es el ratio entre los píxeles físicos y los píxeles CSS. Veamos algunos ejemplos para que sea más fácil de entender:
Si mi DPR es de 1, el tamaño de 1 píxel CSS será de 1 píxel físico, por lo que ambos abarcarán el mismo espacio en pantalla.
Si mi DPR es de 2, el tamaño de 1 píxel CSS será de 4 píxeles físicos (2 píxeles físicos de ancho x 2 píxeles físicos de alto).
Si mi DPR es de 3, el tamaño de 1 píxel CSS será de 9 píxeles físicos (3 píxeles físicos de ancho x 3 píxeles físicos de alto).
El valor del DPR también puede ser decimal, como 2,5 o 2,75.
Sabiendo lo anterior, hay que tener en cuenta que cuando manejamos medidas ~~~px~~~ en HTML y CSS estamos hablando SIEMPRE de píxeles CSS (o del viewport) y NUNCA de píxeles físicos.
Entonces, si tenemos por ejemplo un DPR de 1 e insertamos una imagen de 300x300 píxeles CSS en el navegador (como podría ser con ~~~~~~, esta imagen terminará ocupando 300x300 píxeles físicos. A su vez, si tenemos un DPR de 3 e insertamos una imagen de 300x300 píxeles CSS en el navegador, esta imagen terminará ocupando 900x900 píxeles físicos, o sea, 3 veces más píxeles que los que definimos por código.
Como dato a tener en cuenta, la mayoría de los smartphones modernos tienen un DPR de 2,75 o 3, ya que si tuviesen un DPR de 1 todos los elementos se verían muy pequeños en sus pantallas Full HD de sólo 5" o 5.5". Por otra parte, en pc el DPR por defecto es de 1, pero si hacemos zoom en el navegador el DPR aumentará a la par (con un zoom de 150% el DPR será de 1,5, con un zoom de 200% el DPR será de 2, y así). De hecho, pueden probar esto muy fácilmente en: https://www.mydevice.io/.
Para leer un poco más sobre el tema: https://tomroth.com.au/dpr/.
Espero que les sirva.
¡Saludos!