-
Notifications
You must be signed in to change notification settings - Fork 0
/
captions-es.sbv
1312 lines (957 loc) · 35.7 KB
/
captions-es.sbv
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
0:00:00.630,0:00:04.080
Si estuviste dando vueltas por el mundillo de Javascript
lo suficiente, habrás encontrado
0:00:04.080,0:00:08.970
un conjunto de recetas para trabajar orientado a objetos.
La manera estándar, si es que puede haber una manera estándar,
0:00:08.970,0:00:11.900
es esta.
0:00:11.900,0:00:14.620
Y esta es la receta para la herencia.
0:00:14.620,0:00:22.880
Este es el estándar. Pero ¿por qué esto? ¿Por qué este...
lío? ¿Y por qué esto funciona?
0:00:22.880,0:00:28.210
Hola a todos. Mi nombre es James Shore y esto es
Let’s Code: Test-Driven JavaScript.
0:00:28.210,0:00:31.999
Vengo a ofrecerles algunas lecciones que aprendí sobre programación orientada a objetos en javascript. Estoy grabando
0:00:31.999,0:00:33.430
esto el 1ro de enero de 2013.
0:00:33.430,0:00:39.480
En el episodio de hoy, vamos a armar estas recetas
desde el comienzo.
0:00:39.480,0:00:43.160
Comenzaremos con un repaso de los fundamentos de objetos,
luego veremos como las funciones trabajan en javascript
0:00:43.160,0:00:48.720
Seguido, cubriremos prototipos y herencia,
luego polimorfismo y sobreescritura de métodos.
0:00:48.720,0:00:53.180
Conversaremos sobre clases e instancias en el modelo de prototipos,
luego veremos cómo se relacionan estos conceptos
0:00:53.180,0:00:58.079
con el modelo clásico que la mayoría utiliza.
Por último, nos meteremos en el funcionamiento interno
0:00:58.079,0:01:02.630
del operador instanceof, antes de terminar con un
vistazo de futuros caminos, una herramienta para explorar
0:01:02.630,0:01:06.539
estos conceptos en profundidad y mis recomendaciones.
0:01:06.539,0:01:10.100
Es un gran tema y vamos a cubrir mucho terreno.
Asegurate de aprovechar
0:01:10.100,0:01:14.130
los botones de pausa y retroceso de tu reproductor de video.
También puedes usar estas referencias para ir
0:01:14.130,0:01:17.530
directo a las secciones de interés.
0:01:17.530,0:01:23.450
Comencemos con lo básico. Estos son los
tipos comunes en JavaScript—es todo
0:01:23.450,0:01:28.329
lo que realmente puedes tipear en tu código fuente.
De cualquier forma, la mayoría de estos no son realmente tipos
0:01:28.329,0:01:32.689
primitivos. Los únicos que son primitivos son
los strings, números y booleanos; un par de maneras
0:01:32.689,0:01:38.399
de decir “no puedo encontrarlo” y
objetos. Todo lo demás—funciones, arrays
0:01:38.399,0:01:43.350
y expresiones regulares, así como todos
los objetos que utilizas en tus programas—son
0:01:43.350,0:01:46.289
todas variantes de objetos.
0:01:46.289,0:01:52.409
Entonces, ¿qué es un objeto? Bueno, es un conjunto
de pares de clave/valor. En otros lenguajes tal vez
0:01:52.409,0:01:57.259
lo llames diccionario, hash o
array asociativo, pero fundamentalmente
0:01:57.259,0:02:02.649
son pares de clave/valor. Puedes usar cualquier
número de claves con un nombre dado, siempre que sea
0:02:02.649,0:02:08.240
un string, y cada string estará asociado
con un valor. Estos valores pueden ser de cualquier
0:02:08.240,0:02:14.140
tipo: alguno de los primitivos básicos, así
como cualquier tipo de objeto, incluyendo funciones y,
0:02:14.140,0:02:17.310
por supuesto, objetos en sí mismos.
0:02:17.310,0:02:21.830
Algo importante a tener en cuenta sobre los objetos es que, si bien los primitivos se pasan por valor,
0:02:21.830,0:02:24.840
los objetos se pasan por referencia. Veamos
qué quiere decir esto.
0:02:24.840,0:02:30.110
O sea que si tenemos dos variables, llamadas number1
y number2, y asignamos un valor a number1—digamos
0:02:30.110,0:02:37.310
3.14 etcetera—y luego copiamos
esta variable dentro de number2, estos dos valores
0:02:37.310,0:02:41.920
no están conectados. Si cambiamos number2, number1
no es afectado.
0:02:41.920,0:02:46.260
Los objetos, por otro lado, son almacenados por
referencia. Lo que quiere decir esto es que
0:02:46.260,0:02:52.110
si asignas un objeto a una de estas variables
y luego copiamos ese objeto en una nueva variable,
0:02:52.110,0:02:56.660
no estamos copiando el objeto. Sigue
habiendo un solo objeto. Lo que estamos copiando
0:02:56.660,0:03:02.690
es la referencia. El puntero. El
cursor. Si cambiamos object2, object1 se
0:03:02.690,0:03:09.470
modifica también. object2.a es 42, así como,
object1.a is 42.
0:03:09.470,0:03:11.710
Queda una cosa antes de terminar con
lo básico.
0:03:11.710,0:03:15.360
Si buscas una propiedad que no se encuentra
en un objeto, obtendrás undefined
0:03:15.360,0:03:20.970
como resultado. Ahora bien, puedes asignar undefined
a cualquier propiedad que quieras. Esto no
0:03:20.970,0:03:25.000
elimina la propiedad. Si por alguna razón
necesitas eliminar por completo la propiedad del objeto,
0:03:25.000,0:03:29.680
debes utilizar el operador delete.
Honestamente, en el día a día, esta distinción
0:03:29.680,0:03:33.440
no es muy importante.
0:03:33.440,0:03:38.670
Anteriormente he dicho que las funciones son
objetos particulares, y eso es verdad.
0:03:38.670,0:03:42.770
Cuando defines una función, Javascript crea
un objeto que tiene tres propiedades
0:03:42.770,0:03:46.440
predefinidas: name, que es el nombre
de la función; length, que es
0:03:46.440,0:03:50.730
el número de argumentos; y prototype, que
explicaré luego.
0:03:50.730,0:03:53.980
Como las funciones son sólo objetos,
puedes hacer con ellas las mismas cosas
0:03:53.980,0:03:58.760
que harías con un objeto común. Puedes asignarles propiedades; puedes asignarlas a
0:03:58.760,0:04:03.220
variables; y cuando lo haces, ellas se pasan
por referencia, entonces puedes ejecutarlas
0:04:03.220,0:04:07.580
en su nueva localización simplemente diciendo el
nombre de la variable y paréntesis.
0:04:07.580,0:04:11.790
Cuando pones una función dentro de un objeto,
típicamente es llamada un “método”. Puedes
0:04:11.790,0:04:17.060
ejecutar métodos como a cualquier
función, diciendo object.methodname y luego
0:04:17.060,0:04:17.579
paréntesis.
0:04:17.579,0:04:22.060
Cuando haces esto, JavaScript asignará
la palabra clave this al objeto utilizado.
0:04:22.060,0:04:28.040
Entonces si dices myObject.get(), this referencia
a myObject. Luego de que la función retorne,
0:04:28.040,0:04:30.490
this volverá a referenciar valor que tenía antes.
0:04:30.490,0:04:35.889
La palabra clave this es uno de los grandes
temas en Javascript. Depende del objeto, no del
0:04:35.889,0:04:40.110
contexto en donde la función fue definida, y eso puede causar muchos problemas.
0:04:40.110,0:04:46.350
Entonces, si tenemos myMethod que devuelve this.val,
llamamos object1.get(), obtendremos 42.
0:04:46.350,0:04:52.000
Si llamamos a object2.get(), this será
asignado a object2 y obtendremos 3.14159.
0:04:52.000,0:04:58.770
Si llamamos directamente a myMethod(),
this no será asignado a nada en particular.
0:04:58.770,0:05:02.500
Puede ser undefined si estamos usando la directiva
strict mode; puede ser el objeto global;
0:05:02.500,0:05:04.370
es difícil asegurar su valor.
0:05:04.370,0:05:08.600
Tienes que ser realmente cuidadoso al usar this.
Cuando sea posible, recomiendo
0:05:08.600,0:05:13.820
utilizar el strict mode ya que esto forzará que
this sea undefined. Esto no va a
0:05:13.820,0:05:18.970
prevenir problemas relacionados a this,
pero te ayudará a identificarlos más rápido.
0:05:18.970,0:05:22.850
En caso de necesitar que this referencie
a un valor en particular, puedes forzar
0:05:22.850,0:05:27.930
su asignación utilizando call(), apply() o bind(). Entrar
en detalle en el uso de estas funciones excede
0:05:27.930,0:05:32.389
el alcance de este material, pero déjame
mostrarte un ejemplo de uso.
0:05:32.389,0:05:38.270
Si decimos myMethod.call(), se ejecutará
la función myMethod forzando el valor de this
0:05:38.270,0:05:45.070
a lo que digamos. Entonces myMethod.call(object1)
asignará la refencia this al object1.
0:05:45.070,0:05:50.500
Bien, estas son las bases. Empecemos a meternos
en los temas más complicados.
0:05:50.500,0:05:54.950
Es un poco raro que te pongas
a definir todos tus objetos desde cero.
0:05:54.950,0:05:59.550
Típicamente tendrás algún tipo de patrón repetido.
En este caso, por ejemplo, object1,
0:05:59.550,0:06:04.330
object2, y object3 utilizan la misma
función. En vez de definirlas a todas
0:06:04.330,0:06:09.199
por separado, lo que a la larga sería una
pesadilla de mantenimiento, lo que puedes hacer
0:06:09.199,0:06:12.320
es usar algo llamado “prototipos”.
0:06:12.320,0:06:17.290
Esto funciona así: tu defines un
único objeto, y luego tienes otros objetos
0:06:17.290,0:06:22.050
que heredan de éste, o lo “extienden”. La forma
de hacer esto es llamando a Object.create().
0:06:22.050,0:06:27.070
Entonces si tengo un objeto base con una función
y un valor, puedo crear un nuevo objeto (que he
0:06:27.070,0:06:31.440
llamado hijo) diciendo Object.create(child).
Puedes hacer con este objeto hijo
0:06:31.440,0:06:36.400
lo que harías con cualquier objeto. Puedes
agregarle valores o incluso extenderlo con
0:06:36.400,0:06:37.480
otro hijo.
0:06:37.480,0:06:40.800
La parte interesante es cuando
comenzamos a usar estos objetos.
0:06:40.800,0:06:45.360
El objeto base sigue siendo el mismo. Digamos
que invocamos parent.get(). Bien, this será
0:06:45.360,0:06:51.030
asignado al objeto parent, entonces JavaScript buscará por get en ese objeto. Cuando lo encuentre
0:06:51.030,0:06:56.389
llamará a esa función, que dice
devolver this.val, esto causará que Javascript
0:06:56.389,0:07:00.520
busque val en parent. Hasta acá todo
es como esperamos.
0:07:00.520,0:07:07.199
Pero ahora se pone interesante. Si llamamos a child.get(),
ahora this referencia a child. JavaScript buscará
0:07:07.199,0:07:11.900
el método get en child, pero no lo encuentra.
Entonces buscará en su prototipo
0:07:11.900,0:07:18.430
—subirá un eslabón en la cadena de prototipos—examinando
a parent, encontrando al método get allí.
0:07:18.430,0:07:24.370
Cuando encuentre la función, tratará de devolver
this.val, lo que significa que volverá a child,
0:07:24.370,0:07:30.949
buscando val, encontrandolo. Entonces child.get()
devolverá 3.14 en vez de 42, incluso
0:07:30.949,0:07:35.280
cuando está utilizando la función definida
en parent.
0:07:35.280,0:07:39.550
JavaScript atravesará toda la cadena de prototipos
si es necesario para encontrar
0:07:39.550,0:07:45.070
una propiedad. Si decimos grandchild.get(),
Javascript buscará get en el objeto grandchild.
0:07:45.070,0:07:49.780
Como no puede encontrarlo, irá al
prototype buscando get en child. No lo
0:07:49.780,0:07:54.860
encontrará aquí, entonces irá a parent, busca
y encuentra a get allí. Llamará a
0:07:54.860,0:08:01.430
la función, intentando devolver this.val, entonces
nuevamente buscará en grandchild la propiedad val.
0:08:01.430,0:08:10.389
No la encontrará, entonces irá a child,
busca val, la encuentra, y devuelve 3.14159.
0:08:10.389,0:08:15.009
Estos son los fundamentos de la herencia
en JavaScript. Ahora, si has visto otras maneras
0:08:15.009,0:08:18.669
de hablar sobre objetos en JavaScript, seguramente
estarán pensando en clases u otra
0:08:18.669,0:08:25.669
cosa primero. Pero lo que acabamos de ver—esta herencia
basada en prototipos—es la forma en la que JavaScript
0:08:25.669,0:08:30.780
funciona. Actualmente, JavaScript no tiene otra
forma de herencia más
0:08:30.780,0:08:33.360
que la prototípica que estoy mostrando aquí.
0:08:33.360,0:08:38.210
Hay una cuestión más que me gustaría compartir,
y es que cada objeto tiene
0:08:38.210,0:08:43.240
un prototipo, excepto el objeto base y
los objetos que son creados explícitamente
0:08:43.240,0:08:46.240
sin prototipo. Así es como se ven.
0:08:46.240,0:08:53.450
By default, objects that you create have Object.prototype
as their prototype, and functions have Function.prototype
Por defecto, los objetos que creas tienen a Object.prototype como su prototipo, y las funciones tienen a Function.prototype
0:08:53.450,0:08:57.850
como su prototipo. Puedes notar que de aquí
provienen los métodos call(), apply(), y bind()
0:08:57.850,0:09:00.070
que mencioné hace poco.
0:09:00.070,0:09:04.820
Now, this is way too much detail to show in
most of these visualizations, so what I’m
Ahora, mostrar todo esto en las visualizaciones sería hacerlas demasiado detalladas, por eso
0:09:04.820,0:09:10.640
voy a utilizar [[Object]] y [[Function]] para
referir a esos prototipos de ahora
0:09:10.640,0:09:12.370
en adelante.
0:09:12.370,0:09:17.940
Una vez que tienes objetos en una cadena de prototipos,
te encontrarás necesitando hijos que se comporten
0:09:17.940,0:09:23.110
distinto a sus padres, incluso cuando el mismo método es invocado. Llamamos a esto
0:09:23.110,0:09:26.880
“polimorfismo”. Polimorfismo significa, “el
mismo nombre, diferente comportamiento”. Ahora,
0:09:26.880,0:09:29.870
técnicamente, puedes obtener polimorfismo
sin herencia, pero no vamos a
0:09:29.870,0:09:31.089
hablar de eso ahora.
0:09:31.089,0:09:35.360
En JavaScript es fácil generar polimorfismo;
utilizas el mismo nombre para la propiedad, asignándole
0:09:35.360,0:09:40.370
otro método. Entonces si queremos tener
un objeto firmAnswer que responda algo
0:09:40.370,0:09:46.800
distinto—o de otra manera—podríamos simplemente
decir firmAnswer.get y asignar la función.
0:09:46.800,0:09:50.450
En este caso, lo que vamos a hacer
es devolver el mismo valor
0:09:50.450,0:09:53.370
agregando “!!” al final.
0:09:53.370,0:09:57.940
So if we say answer.get(), that will give
us “42” back, but if we say firmAnswer.get(),
Entonces si decimos answer.get(),
esto devolverá “42”, pero si decimos firmAnswer.get(),
0:09:57.940,0:10:04.640
esto devolverá “42!!”. Supongo
que captas la idea.
0:10:04.640,0:10:09.100
Esta relación es un poco más fácil de ver si no tenemos las visualizaciones de la función
0:10:09.100,0:10:11.390
aquí, por lo que voy a dejar de mostrarlas
por ahora.
0:10:11.390,0:10:17.330
Ahora podrás notar que nuestra fn2 busca su
this.val y nuestra fn1 busca this.val.
0:10:17.330,0:10:23.790
Aquí hay un poco de código duplicado. Si bien
no parece tan malo, en programas más complejos
0:10:23.790,0:10:29.990
encontrarás que este tipo de lógica
es muy difícil de mantener. Típicamente,
0:10:29.990,0:10:35.399
que lo vamos a querer es llamar fn1
desde fn2.
0:10:35.399,0:10:40.760
Desafortunadamente, no es tan fácil
como parece. La respuesta obvia sería
0:10:40.760,0:10:45.360
simplemente llamar fn1… diciendo answer.get().
Esto no funciona. Devuelve
0:10:45.360,0:10:50.600
la respuesta incorrecta. Va a devolver 42.
¿Sabes por qué? Si no, puedes pausar
0:10:50.600,0:10:53.100
el video para ver si te das cuenta.
0:10:53.100,0:10:55.050
Bien, vamos a explicarlo.
0:10:55.050,0:11:00.279
Cuando llamamos firmAnswer.get(), this es asignado
a firmAnswer y JavaScript busca
0:11:00.279,0:11:07.459
la propiedad get. La encuentra y ejecuta fn2.
Esto ejecuta answer.get(), lo que asignará
0:11:07.459,0:11:13.770
this a answer, para luego buscar la
propiedad get en answer. Cuando la encuentra,
0:11:13.770,0:11:20.899
ejecutará fn1 y tratará de devolver this.val.
Como this está apuntando a answer, cuando
0:11:20.899,0:11:28.350
busque por this.val, encontrará la propiedad en
el objeto answer devolviendo 42 en vez de 3.14159,
0:11:28.350,0:11:30.040
que es el valor esperado.
0:11:30.040,0:11:34.779
Entonces, para hacer que funcione correctamente, necesitamos utilizar la función call. Necesitamos
0:11:34.779,0:11:39.380
decir answer.get.call(this). Puedes intentar
descubrir por qué funcionaría esto.
0:11:39.380,0:11:42.810
Bien, así es cómo esto funciona.
0:11:42.810,0:11:48.990
Cuando llamamos firmAnswer.get(), this es asignado
a firmAnswer… busca por get…
0:11:48.990,0:11:58.750
lo encuentra… ejecuta fn2… y ahora dice answer.get.call(this). Esto asigna a this, bueno, el valor al que apunta this nuevamente.
0:11:58.750,0:12:05.269
Pero luego ejecuta answer.get() directamente,
que intenta devolver this.val, buscando
0:12:05.269,0:12:12.610
la propiedad val en firmAnswer, la encuentra,
devolviendo la respuesta esperada.
0:12:12.610,0:12:17.550
Puedes organizar tus objetos Javascript de
la manera que quieras, aunque una manera bastante común
0:12:17.550,0:12:20.970
de hacerlo es separando tus métodos de tus datos.
0:12:20.970,0:12:25.269
Por ejemplo, tenemos este objeto answer que,
cuando le pides que te de su value, devuelve
0:12:25.269,0:12:26.610
el value que tiene almacenado.
0:12:26.610,0:12:31.310
Bien, normalmente quieres tener
múltiples copias de este objeto, entonces la gente
0:12:31.310,0:12:38.070
generalmente pondrá la función en un prototipo
—al que llamaremos AnswerPrototype—y luego
0:12:38.070,0:12:44.130
tendrán múltiples objetos extendiendo
ese prototipo para darle valores especiales.
0:12:44.130,0:12:48.339
Aquí vemos que lifeAnswer tiene un value
de 42, ya que es la respuesta de la Vida,
0:12:48.339,0:12:53.220
(ver Hitchhiking guide to the galaxy), y dessertAnswer tiene un value de pi, por, bueno, razones obvias (dessert = postre, pi = pie = pastel).
0:12:53.220,0:12:57.410
Si quisieras especializar esta respuesta,
como hicimos con firmAnswer, puedes
0:12:57.410,0:13:03.560
hacer lo mismo. Tenemos nuestro FirmAnswerPrototype
mas su fn2—la que agrega “!!”
0:13:03.560,0:13:09.779
al final—que extiende AnswerPrototype. También tenemos
nuestra luckyAnswer y magicAnswer
0:13:09.779,0:13:11.800
extendiendo a esta.
0:13:11.800,0:13:16.850
Cuando utilizas esta forma de organizar tus objetos,
los prototipos son generalmente llamados
0:13:16.850,0:13:22.410
“clases,” y los objetos—los que los extienden
—generalmente llamados “instancias”.
0:13:22.410,0:13:26.940
Una clase que extiende a otra es llamada “subclase”.
0:13:26.940,0:13:30.120
Se le dice “instanciar” a esta creación de una instancia,
y te darás cuenta que esto implica
0:13:30.120,0:13:35.730
un proceso de dos pasos. Primero, se crea el objeto extendiendo el prototipo, segundo,
0:13:35.730,0:13:40.920
se inicializan sus estados. (Recuerda, las instancias
usualmente se ocupan de los estados y los prototipos
0:13:40.920,0:13:46.230
de los métodos—las clases de los métodos.)
Entonces extendemos y luego inicializamos.
0:13:46.230,0:13:50.540
El problema que tiene esto es que la lógica de inicialización es duplicada cada vez que creamos
0:13:50.540,0:13:56.200
un objeto. Esto no es tan problemático en un
ejemplo sencillo, pero en programas reales,
0:13:56.200,0:14:00.880
la lógica de inicialización suele ser
más complicada. Entonces no queremos duplicarla
0:14:00.880,0:14:04.680
en todos lados. Eso sería un gran
problema de mantenimiento.
0:14:04.680,0:14:08.769
Esto también vulnera el encapsulamiento. Una de las
cosas lindas que tiene la OOP
0:14:08.769,0:14:13.790
es que nos permite decidir cómo nuestros datos
van a ser almacenados de una manera en la que nadie
0:14:13.790,0:14:18.190
más deba preocuparse. Simplemente provees acceso
a esos datos a través de tus métodos
0:14:18.190,0:14:21.750
y luego, si quieres cambiar la manera en la que los
datos son almacenados, lo haces. Actualizas tus
0:14:21.750,0:14:26.120
métodos—los de tu objeto—sin tener
que actualizar el resto
0:14:26.120,0:14:26.459
del programa.
0:14:26.459,0:14:31.279
Pero aquí, como todas nuestras instancias acceden
a val directamente, no podemos cambiar la forma en que val
0:14:31.279,0:14:35.180
es almacenado sin tener que cambiar a
todas nuestras instancias.
0:14:35.180,0:14:40.930
Entonces lo que generalmente haces es usar algún
tipo de función de inicialización. En este caso,
0:14:40.930,0:14:46.029
voy a llamarla constructor(). Este es un método que muchos utilizan para inicializar
0:14:46.029,0:14:46.940
sus objetos.
0:14:46.940,0:14:52.570
Así es como funciona. Digamos que
queremos crear una nueva instancia de magicAnswer.
0:14:52.570,0:14:59.170
Extendemos FirmAnswerPrototype y luego decimos magicAnswer.constructor(3). Esto
0:14:59.170,0:15:03.310
llamado asignará this a magicAnswer y luego buscará la
propiedad constructor. No la encontrará
0:15:03.310,0:15:08.310
en magicAnswer, entonces la buscará en el prototipo.
Tampoco la encontará allí, entonces
0:15:08.310,0:15:15.180
buscará en el prototipo de FirmAnswerPrototype. Allí
la encontrará y ejecutará fn0(value).
0:15:15.180,0:15:23.110
fn0 va a asignar a la propiedad this._val el value. Entonces localiza a this, asigna el valor,
0:15:23.110,0:15:24.019
y aquí estamos.
0:15:24.019,0:15:28.970
Puedes notar que agregué un guión bajo adelante en _val.
Es una convención en la comunidad
0:15:28.970,0:15:33.790
JavaScript para decir que esta propiedad es “privada”.
En otras palabras, no deberías acceder o
0:15:33.790,0:15:37.610
asignar valores a esa propiedad. Ahora bien, en JavaScript no hay forma de forzar a que esto sea así,
0:15:37.610,0:15:41.670
pero esta es la manera correcta de trabajar. Y si sigues esta regla, esto significa que podemos cambiar
0:15:41.670,0:15:46.800
AnswerPrototype sin cambiar
la manera en que
0:15:46.800,0:15:51.600
FirmAnswerPrototype debe ser programada para
todas nuestras instancias.
0:15:51.600,0:15:58.170
Este es un panorama completo de herencia prototípica en JavaScript. Es un poco distinto
0:15:58.170,0:16:02.130
a lo que mostré al comienzo, todavía no terminamos con esto. Pero utilizando este modelo puedes
0:16:02.130,0:16:06.680
programar completamente orientado a objetos con JavaScript.
0:16:06.680,0:16:12.850
Ahora, observemos el modelo clásico. Se va a construir
sobre todo
0:16:12.850,0:16:14.410
lo que hicimos hasta ahora.
0:16:14.410,0:16:18.670
Para comenzar, si recuerdas, en el modelo de prototipos, instanciamos un objeto creandolo
0:16:18.670,0:16:23.260
y luego llamando a algún tipo de constructor, ¿no?.
Esto es tan común que JavaScript
0:16:23.260,0:16:26.139
tiene una palabra especial para hacerlo.
Esta palabra es new.
0:16:26.139,0:16:32.470
De todas formas, new es un poquito, bueno, rara.
No funciona de la manera que hemos visto
0:16:32.470,0:16:36.880
hasta ahora, y eso es lo que diferencia al
modelo clásico que estoy por mostrar con
0:16:36.880,0:16:40.589
el de prototipos que estuve mostrando hasta ahora.
0:16:40.589,0:16:45.829
Ahora, antes de meternos en eso, tengo que mostrarte
algo un poco raro sobre las funciones.
0:16:45.829,0:16:49.920
¿Recuerdas esa propiedad prototype que dije que explicaría luego? Bueno, voy a explicarla
0:16:49.920,0:16:52.660
ahora. Y es… es rara.
0:16:52.660,0:16:56.420
Al crear una función, JavaScript crea un objeto con las propiedades name, length y prototype.
0:16:56.420,0:17:02.360
Esta propiedad prototype en realidad referencia
a un objeto completamente nuevo
0:17:02.360,0:17:07.240
con una propiedad constructor que referencia a la función que acabas de crear. Entonces cada vez
0:17:07.240,0:17:11.559
defines una función en JavaScript, estás creando dos objetos: el de la función,
0:17:11.559,0:17:14.850
y también su objeto prototype
que está colgado por ahí.
0:17:14.850,0:17:17.780
Te dije que era raro.
0:17:17.780,0:17:20.150
Observemos esto más de cerca. ¿No te parece familiar?
0:17:20.150,0:17:27.470
Si. Es un prototipo. Es, básicamente,
una clase. O sea que cada vez que defines una función
0:17:27.470,0:17:32.460
en JS, estás realmente definiendo
un constructor que está asociado con esta mini clase
0:17:32.460,0:17:34.040
que no-hace-nada.
0:17:34.040,0:17:39.400
Ahora, claro está, no toda función que uno define fue pensada para ser un constructor. Entonces la convención
0:17:39.400,0:17:43.260
en JS es que, si la pensamos como
un constructor, debería comenzar
0:17:43.260,0:17:47.080
con una letra mayúscula, y si fue pensada como una función tradicional, entonces la nombramos
0:17:47.080,0:17:48.210
con minúsculas al comienzo.
0:17:48.210,0:17:53.100
Bien, hasta aquí un poco de la rareza con las funciones.
Veamos como se pone en juego esto en
0:17:53.100,0:17:54.110
el modelo clásico.
0:17:54.110,0:18:00.900
Primero, volvamos a nuestro modelo de prototipos.
Vamos a revisarlo paso a paso.
0:18:00.900,0:18:04.570
Lo que vamos a hacer es crear
una clase llamada AnswerPrototype.
0:18:04.570,0:18:09.870
Vamos a crear un constructor en ella. Y cuando creamos ese constructor, JavaScript
0:18:09.870,0:18:15.190
va a definir un objeto para la función y otro para su prototipo (al que no le daremos importancia;
0:18:15.190,0:18:19.110
lo vamos a ignorar). También vamos
a crear una función get en
0:18:19.110,0:18:27.490
AnswerPrototype y un par de instancias: lifeAnswer y dessertAnswer.
0:18:27.490,0:18:32.270
Este es un ejemplo básico usando el modelo
de prototipos. Ahora hagamos lo mismo,
0:18:32.270,0:18:35.410
pero esta vez utilizando el modelo clásico
y la palabra new.
0:18:35.410,0:18:43.000
En el modelo clásico, se define el constructor
primero. Entonces creemos la función Answer.
0:18:43.000,0:18:47.480
JavaScript va a crear automáticamente un objeto
a su lado, con una propiedad constructor
0:18:47.480,0:18:51.960
que referencia a la misma función Answer. Este prototipo es nuestra clase. Es la que va a cumplir
0:18:51.960,0:18:58.220
el mismo propósito que AnswerPrototype
en el ejemplo previo. Entonces asignamos nuestro
0:18:58.220,0:19:04.780
método get en AnswerPrototype. Luego podemos
instanciarlo llamando a new Answer(). Vamos a
0:19:04.780,0:19:09.590
decir new Answer(42) y esto nos va a dar la instancia
correcta. Esto va a crear un hijo de
0:19:09.590,0:19:17.020
Answer.prototype inicializandolo llamando al
constructor Answer pasandole el valor 42.
0:19:17.020,0:19:22.770
Para saber que al crear a lifeAnswer
debe usar a Answer.prototype como su prototipo
0:19:22.770,0:19:27.960
JavaScript inspecciona la propiedad prototype
presente en la función al utilizar la palabra clave new.
0:19:27.960,0:19:30.040
Lo mismo sucede con dessertAnswer.
0:19:30.040,0:19:32.419
Esto es el modelo clásico.
0:19:32.419,0:19:37.790
Esto se pone un poco más complicado cuando
comenzamos a lidiar con subclases. Observemos
0:19:37.790,0:19:41.850
cómo sería con una subclase.
Agreguemos la clase FirmAnswer
0:19:41.850,0:19:45.030
que hicimos en nuestro ejemplo previo
con prototipos.
0:19:45.030,0:19:50.940
Nuevamente, vamos a comenzar creando el constructor
FirmAnswer en primer lugar. JavaScript creará automáticamente
0:19:50.940,0:19:58.200
el objeto FirmAnswer.prototype, pero no podemos utilizarlo ya que necesitamos que FirmAnswer.prototype
0:19:58.200,0:20:04.940
extienda a Answer.prototype—y esto no es así. Lo que haremos es, asignar la propiedad FirmAnswer.prototype
0:20:04.940,0:20:10.880
a un nuevo objeto que crearemos extendiendo
a Answer.prototype. Esto hará que el viejo
0:20:10.880,0:20:15.000
FirmAnswer.prototype to have nothing pointing
to it, so it will get collected by the garbage
FirmAnswer.prototype quede sin referenciar, siendo recolectado por el garbage
0:20:15.000,0:20:15.760
collector.
0:20:15.760,0:20:22.720
Luego, asignaremos la propiedad constructor
para volver a referenciar a FirmAnswer. Ahora, hasta donde
0:20:22.720,0:20:26.380
puedo decir, esta propiedad constructor no es necesaria.
Todo lo que estamos haciendo con
0:20:26.380,0:20:31.190
JS funciona bien sin esa propiedad.
Pero vamos a asignarlas para ser consistentes.
0:20:31.190,0:20:33.850
Quizá quieras probar en saltear este paso,
pero debo admitir, no he sido lo suficientemente
0:20:33.850,0:20:37.169
valiente para hacerlo, por lo que hazlo
asumiendo el riesgo.
0:20:37.169,0:20:42.090
Bien, tenemos el FirmAnswer.prototype
con su constructor. Ahora necesitamos asignarle