-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathOOP.txt
6593 lines (5167 loc) · 162 KB
/
OOP.txt
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
组合式继承:
// 组合式继承
/*
var o1 = { num: 123 };
var o2 = { num2: 456 };
// o2 继承自 o1
o2.extend = function ( obj ) {
for ( var k in obj ) {
this[ k ] = obj[ k ];
}
};
o2.extend( o1 );
*/
function Fn() {}
// 组合式实现 原型继承 原型继承修改的是对象的原型对象 函数的原型属性
// ???
Fn.fn = Fn.prototype;
Fn.fn = function ( obj ) {
for ( var k in obj ) {
this[ k ] = obj[ k ]; //这里的this指的是Fn.prototype的
}
};
Fn.fn.extend( {} );
$( '<p>ppp</p>' ).appendTo( ? )
$( '<p>ppp</p>' ).appendTo( document.body )
$( '<p>ppp</p>' ).appendTo( 'body' )
$( '<p>ppp</p>' ).appendTo( $( 'body' ) )
/*
* 直接继承与间接继承来源于 模拟 Java 等语言啊概念
*
* 在 js 中 一个构造函数 Person 创建的对象, 上面继承自他的原型 Person.prototype
* 而 Person.prototype 是继承自 Object.prototype 所以
* 我们称 Person 的实例 直接继承自 Object.prototype, 因为中间没有切入其它对象
*
*
* 间接继承就是说 Person 的实例与 Object.prototye 中间隔了一层到多层对象
*
* function Animal() {}
* var am = new Animal();
*
* function Person() {};
* Person.prototype = am;
*
* var p = new Person();
*
* p 间接的继承自 Object.prototype
*
*
*/
构造函数:
// 什么是构造函数
// 构造: 他就是设计, 组合, 将没有的东西概念实现
// 构造函数: 它是函数( 任何函数都可以作为构造函数来使用 ), 它的作用是初始化对象
// new 是什么?
// new 就是在创建对象, 从无到有, 可以理解为一个没有穿衣服的新生儿
// 比喻
// new 好比 有了一个新对象, 但是没有任何成员. 好比代码
// var obj = {}; ---不知道具体是什么对象 不知道是什么类型
函数用new来调用 就是构造函数
// 构造函数就是在为它初始化, 简单说就是给他添加属性和方法( 成员 )
// 好比
// obj.name = 'jim';
// obj.age = 10;
// obj.gender = '男';
// 构造方法的意义: 复用
// 将四局代码简化得到
// var obj = new Person( 'jim', 10, '男' );
// 构造函数如何初始化, 就看 this
// 如果没有构造函数如何给对象添加成员: 对象.成员 = 值
// 构造对象的整个过程:
// 1, new 申请内存, 创建对象
// 2, 调用构造函数, 构造函数有一个隐式参数, 即 this
// 3, 刚创建出来的对象的引用 赋值给 this, 由函数处理
// 4, 在构造函数中利用 this.成员 = 值 来给对象添加成员
使用构造函数---他有原型 是独立的原型-- 只影响到当前对象的原型 有独立的类型名了
A. 使用构造函数 他有独立的原型对象存在
B. 他的对象创建出来是有类型名的
// prototype 与 __proto__
//
// 相同点?
// 1, 这两个都是属性, 简单说就是存储引用的变量
// 2, 同一个构造函数, 与构造函数的实例对象. 这两个属性的引用对象是同一个对象
// 不同点?
// 1, 在不同的角度使用这两个属性
// prototype 使用在构造函数后面
// __proto__ 使用在对象后面
// 2, 描述也不相同
// prototype 叫做 构造函数的原型属性
// __proto__ 叫做 对象的原型对象
// 3, __proto__ 是非标准属性
// 所以我们在描述对象的时候是说 对象会连接到原型对象上
// 作用
// 在实现继承的时候, 一般都是使用 构造函数的 prototype 属性
// 在分析结构与验证对象等测试与调试中, 会用到 __proto__
3, 有函数 Fn, 对象 fobj. 获得原型的语法有: Fn.prototype, 和 fobj.__proto__
4, 给对象添加方法可以怎么写:
obj.fn = function(){};
obj.extend({function(){}})
5, 继承的语法有几种, 分别是什么?
原型式继承
Fn.prototype.fn = function(){}
Fn.prototype = {
constructor: Fn,
fn:function(){}
}
Fn.prototype.extend({fn:function(){}})
组合式继承
fObj.extend({...})
6, 简单描述一下 __proto__ 与 prototype 的区别
7, 代码
function Func() {
}
var f1 = new Func();
Func.prototype = {
name: 'jim'
};
var f2 = new Func();
console.log( f1.name ); undefined--->
console.log( f2.name ); jim
执行的结果是什么, 为什么?
function Func() {
}
var f1 = new Func();
Func.prototype.name="jim";
var f2 = new Func();
console.log( f1.name ); jim
console.log( f2.name ); jim
8, 简单描述一下
function F(){}
F.prototype.name = 'jim'
var obj = new F();
obj.name 与 obj.__proto__.name 的区别
obj.name--->当前对象找 当前对象没有去原型对象里面找
obj.__proto__.name 直接去原型对象里面去找
// var car = { name: 'BMW' };
// var o1 = { name: 'jim', car: car };
// o1 与 o1.car 的关系
function Person() {} 这个只是定义了一个函数 这里只能说是定义了一个函数
// Person 与 Person.prototype 的关系是什么?
只要前面加new就是构造函数
对象只有__proto__属性
但是函数有prototyoe 和 __proto__属性
// 结论
// 1, 定义函数, 函数有一个属性叫 prototype
// 2, 函数的属性 prototype 是一个对象类型
// 类似 var o = { name: {} };
// 3, 属性 prototype 是一个含有 constructor 与 __proto__ 属性的对象
// 这个对象就是 Person.prototype
// 4, constructor 属性就是当前函数
Person === Person.prototype.constructor (把Person.prototype看成一个整体)
// 推论: 函数的 prototype 属性的 constructor 就是当前函数
// 5, 所有的函数的 prototype 属性所表示的对象都继承自 Object.prototype
// 即: 函数.prototype.__proto__ 就是 Object.prototype
有一个例外---Object.prototype.__proto__ === Object.prototype ---> false
Array.prototype.__proto__ === Object.prototype ---> true
Obecjt对象和原型对象的关系
function Person() {
// this.name = 'jim';
}
var p = new Person();
// 1, p 是函数 Person 的实例
// 2, p 就继承自 Person.prototype
// p.__proto__ 就是 Person.prototype
// 浏览器分析的结论
// 1, 由于构造函数中什么都没有写, 因此 p 中也是什么都没有
// 2, 对象 p 的原型对象 就是 构造函数 Person 的原型属性
// 即: p.__proto__ 就是 Person.prototype
// 经典的 "对象原型和函数三角形" 就出现了
var o = new Object();
</script>
Object 中的成员:
// Object 原型中的常用方法
// 1, 带有下划线的除了 __proto__ 其他可以不考虑
// 2, constructor 是构造函数的引用, 就是构造函数
/*
var Person = function () {
this.name = 'jim';
};
var p1 = new Person();
var p2 = new Person.prototype.constructor();
将函数赋给变量使用
Person.prototype.init = Person;
// initial 初始化的
var p3 = new Person.prototype.init();
*/
// 3, hasOwnProperty
// has 有
// own 自己的
// property 属性
// 有自己的属性, 检查属性是否是自己原生提供的, 如果是被继承的 则返回 false
// 语法
// boolean 对象.hasOwnProperty( 属性名字 )
/*
var o = { name: 'jim' };
function Person() {
this.name = 'tom';
}
Person.prototype = o;
var p = new Person();
console.log( p.name );
var isTrue = p.hasOwnProperty( 'name' );
console.log( isTrue );
*/
// 4, isPrototypeOf
// of 的
// 语法:
// boolean 对象1.isPrototypeOf( 对象2 );
// 判断 对象1 是否为 对象2 的原型对象, 如果是返回 true, 否则返回 false
// var Person = function () {};
// var p = new Person();
/*
console.log( p.isPrototypeOf( Person ) );
console.log( p.isPrototypeOf( Person.prototype ) );
console.log( Person.prototype.isPrototypeOf( p ) );
console.log( Person.prototype.isPrototypeOf( Person ) );
*/
/*
var o = {};
// Person.prototype = o;
var p = new Person();
Person.prototype = o;
alert( o.isPrototypeOf( p ) );
*/
// 5, propertyIsEnumerable
// -able 表示可能性的后缀
// enum 枚举, 一个一个的展示出来
// 属性是否可以枚举, 属性是否可以被 for-in 遍历到
// var o = {};
// in
// alert( 'hasOwnProperty' in o ); // o.hasOwnProperty
// for ( var k in o ) {
// console.log( k );
// }
// 这个方法判断属性是否可以被枚举, 同时判断属性是否是自己提供的
// 因此该方法表示判断属性必须是 自己提供的, 同时可以被枚举的, 那么就返回 true, 否则返回 false
// 在 ES3 的基础上, 该方法没有任何意义, 是对 hsOwnProperty 的一个升级版
// 在 ES5 中引入了 对象特性( attribute )的概念, 才会使得该方法有点作用
// 语法:
// boolean 对象.propertyIsEnumberable( 属性名字 );
/*
var o = { name: 'jim' };
o.__proto__.age = 10;
console.log( o.age );
console.log( o.propertyIsEnumerable( 'name' ) );
console.log( o.propertyIsEnumerable( 'age' ) );
*/
// 6, toString, toLocaleString, valueOf
/*
var d = new Date();
console.log( d.toString() );
console.log( d.toLocaleString() );
*/
function Person() {
/*
this.toString = function () {
return 'toString 字符串';
}
this.toLocaleString = function () {
return '本地字符串';
}
*/
}
var d = new Person();
console.log( d.toString() );
console.log( d.toLocaleString() );
// console.log( (new Number(1)).toString() );
// console.log( (new Number(1)).toLocaleString() );
// 借用方法
// console.log( Object.prototype.toString.call( 1 ) );
// console.log( toLocaleString.call( 1 ) );
// console.log( Object.prototype.toString.call( new Date() ) );
/*
var o = {};
if ( !!o ) {
console.log( 1 );
}
*/
// var a = [ 1, 2, 3 ];
// alert( a.valueOf() );
</script>
instanceof:
// instanceof
// instance 实例
// of 的
// 用法
// boolean 对象 instanceof 构造函数
// console.log( [] instanceof Array );
// console.log( [] instanceof Object );
// instanceof 的运算规则?
function Fn() {}
function Foo() {}
// var o = new Fn();
// console.log( o instanceof Foo );
Fn.prototype = new Foo();
var o = new Fn();
console.log( o instanceof Foo );
// 规律
// 任意的一个对象都有一条原型链
// 那么 只要是 在该链上的构造函数, 这个判断都是 true
// 或
// 如果直接判断的是构造函数, 那么也是 true
创建函数:
// 创建函数
// 1, 声明式
// 2, 表达式
// 3, new Function
// 结论: 任意函数都是 Function 的实例
/*
console.log( Array instanceof Function );
function PeSoN() {}
console.log( PeSoN instanceof Function );
console.log( Date instanceof Function );
console.log( Object instanceof Function );
// Function 也是函数
console.log( Function instanceof Function );
*/
// new Function 的语法规则
// 语法
// var 函数名 = new Function( arg1, arg2, arg3, ..., argN, body );
// 解释
// Function 构造函数所有的参数都是字符串类型的
// 除了最后一个参数, 所有的参数都作为生成函数的参数. 这里可以没有参数
// 最后一个参数也是字符串, 表示的是生成函数的函数体
/*
function max( a, b ) {
return a > b ? a : b;
}
var fnMax = new Function( 'a', 'b', 'return a > b ? a : b;' );
var res = fnMax( 1, 2 );
*/
// 写一个函数, 求传入数字的和
// 1, 有两个参数的时候
/*
function sum( a, b ) {
return a + b;
}
var fnSum = new Function( 'a', 'b', 'return a + b;' );
var res = fnSum( 123, 456 );
alert( res );
*/
// 2, 多个参数的时候
/*
function sum() {
var total = 0,
args = arguments,
len = args.length;
for ( var i = 0; i < len; i++ ) {
total += args[ i ];
}
return total;
}
var res = sum( 1, 2, 3, 4, 5 );
alert( res );
*/
// new Function
/*
var fnSum = new Function( 'var total = 0, args = arguments, len = args.length;for ( var i = 0; i < len; i++ ) {total += args[ i ];}return total;' );
var res = fnSum( -1, 1,1,1,1,1,1 );
alert ( res );
*/
// 解决这个问题比较晦涩, 代码难以维护
// 给出两个解决方案
// 1, 传统
// 将字符串进行换行分割
var fnSum = new Function(
'var total = 0, ' +
' args = arguments, ' +
' len = args.length; ' +
'for ( var i = 0; i < len; i++ ) { ' +
' total += args[ i ]; ' +
'} ' +
'return total; '
);
var res = fnSum( 1,1,1,1,1,1 );
alert ( res );
// 2, 吸收了 MVC 的思想( 不做要求 )
// 练习
// 1, 求两个数字中最大的数字
// 2, 求任意个数字中最大的数字
// Object instanceof Function
// Function instanceof Object
****求和函数
<script id="engin">
/*
var total = 0,
args = arguments,
len = args.length;
for ( var i = 0; i < len; i++ ) {
total += args[ i ];
}
return total;
*/
</script>
<script>
var getBody = function ( id ) {
var script = document.getElementById( id );
var body = script.innerHTML.replace('/*', '').replace('*/', '');
script.parentNode.removeChild( script );
return body;
}
onload = function () {
var fnSum = new Function( getBody( 'engin' ) );
var res = fnSum( 1, 2, 3 );
alert( res );
};
</script>
求最大值:
<script id="abc">
/*
var m, args = arguments, len = args.length;
m = args[ 0 ]; // 1 号同学到前面来
// 从 2 号同学依次上来比较, 留下较高的同学
for ( var i = 1; i < len; i++ ) {
if ( m < args[ i ] ) {
m = args[ i ];
}
}
return m;
*/
</script>
<script src="angular.js"></script>
<script>
/*
function max() {
var m, args = arguments, len = args.length;
m = args[ 0 ]; // 1 号同学到前面来
// 从 2 号同学依次上来比较, 留下较高的同学
for ( var i = 1; i < len; i++ ) {
if ( m < args[ i ] ) {
m = args[ i ];
}
}
return m;
}
var res = max( -1, 2, -3, 4, -7, 9, 1, 2, 3, 4, 5 );
alert( res );
*/
var getBody = function ( id ) {
var script = document.getElementById( id );
var body = script.innerHTML.replace('/*', '').replace('*/', '');
script.parentNode.removeChild( script );
return body;
};
var body = getBody( 'abc' );
var fnMax = new Function( body );
var res = fnMax( -1, 2, -3, 4, -7, 9, 1, 2, 3, 4, 5 );
// alert( res );
var r = Math.max(1,2,3,4);
// alert( r );
var s = '12\
3';
alert( s );
</script>
结论--eval函数:
<script>
// 使用 Function 和 使用 eval
// 他们都有一个共同 的特点, 可以将字符串作为 js 代码来执行
// eval 函数的语法
// eval( 字符串 )
// 这个函数在调用的时候会将字符串作为 js 代码来执行
// var a = 10;
// eval( 'var a = 10;' );
// console.log( a );
// 应用方向比较的广泛, 可以利用该方法实现动态操作
// 1, ajax
// 服务器与浏览器交互, 服务器发给浏览器的数据是一个字符串
// 那么要执行这个代码, 就需要将字符串作为 代码执行, 这个就要用到 eval
var str = '{ name: "jim", age: 19, gender: "男" }';
// '[{{}},{{},[]}]'
// 当从服务器拿到字符串以后, 理论上应该将其作为数据对象使用
// 解析字符串
// 传统的做法
/*
str = str.replace('{', "").replace("}", "");
// ' name: "jim", age: 19, gender: "男" '
var arr = str.split( ',' );
// [ ' name: "jim"', ' age: 19', ' gender: "男" ' ]
var o = {};
for ( var k in arr ) {
var tempArr = arr[ k ].split( ':' );
// 去空格
var key = tempArr[ 0 ].trim();
var value = tempArr[ 1 ].trim();
o[ key ] = value;
}
console.log( o.name );
console.log( o.age );
console.log( o.gender );
*/
var o1 = { };
// var o2 = eval( "(" + str + ")" );
var o2 = eval( str );
console.log( o2.name );
console.log( o2.age );
console.log( o2.gender );
// 2, 所见即所得的案例( 难度 )
</script>
eval简单案例:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
.c {
width: 800px;
height: 300px;
border: 1px solid red;
padding: 10px;
}
</style>
</head>
<body>
<div id="dv" class="c">
</div>
<textarea class="c">
</textarea>
</body>
<script type="text/javascript">
// 理论上用户输入一个字符就做相应的处理, 才可以实现实时的效果
var txt = document.getElementsByClassName( 'c' )[ 1 ];
// 绑定事件
txt.onkeyup = function () {
// console.log( this.value );
//
// 每次执行代码的时候都将 div 中的所有元素都去掉
document.getElementsByClassName( 'c' )[ 0 ].innerHTML = "";
try {
eval( this.value );
} catch ( e ) {
}
};
</script>
</html>
代码块--eval
<script type="text/javascript">
/*
if ( 0 ) {
alert( 123 ); alert( 456 );
}// 逻辑上, 代码块就是一条语句
// : 语法用在哪里?
// case :
// 键值对
var o = { name: 'jim' };
// {} 有两重意思: 1, 代码块, 2, 对象
if ( 1 ) {
// :
}
*/
// doc
var str = '{ name: "jim" }';
// eval( 'var o = ' + str );
var o = eval( '(' + str + ')' );
</script>
eval-Function 函数使用注意
<script>
// Function 和 eval 都可以实现字符串执行代码
// 在实际开发中, 如果考虑效率可以直接使用 eval
// 但是考虑安全性则建议使用 Function
// eval( 'var a = 10;' ); // eval 会污染全局变量
// eval 等价与
// 直接实行 var a = 10;
// (new Function( 'var a = 10; alert( 123 );' ))();
// new Fucntion 等价于
// 定义一个函数, 在函数内部, 执行
// var a = 10;
// console.log( a );
var str = '{ name: "tom" }';
var o = (new Function( 'return ' + str ))();
// var o = (new Function( str ))(); 报错,name is not defined,因为无返回值
alert( o.name );
</script>
函数的原型链:
// 总结一下基本结论
// 1, 对象都有原型对象, 对象默认继承自原型对象
// 2, 函数被定义后, 默认就有原型属性, 原型属性也是对象
// 3, 函数的原型属性默认继承自 Object.prototype
// 4, 原型对象中 constructor 指向对应的构造函数
// 5, 所有的函数都是 Function 的实例
// 6, 函数也是对象
// 基本的概念
// prototype 是函数的原型属性, 是该函数创建的对象的原型对象
// __proto__ 是对象的原型对象, 是创建该对象的构造函数的 原型属性
function Foo() {}
// Foo 有 prototype 属性
// 讨论 __proto__
// 函数 Foo 是 Function 的实例
// 即 Function 是 Foo 的构造函数
// 类比
// Person p
// => p.__proto__ 就是 Person.prototype
// => Person.prototype.__proto__ 就是 Object.prototype
// 替换
// => Foo.__proto__ 就是 Function.prototype
// => Function.prototype.__proto__ 就是 Object.prototype
// 原型对象就是构造函数的原型属性
// 所以, Foo.__proto__ 就是 构造函数的原型属性, 即 Function.prototype
// 默认函数的原型属性继承自 Object.prototype
// Function 是函数, Function.prototype 是函数的原型属性
// Function.prototype 继承自 Object.prototype
// 这里与之前唯一不同的是将 函数当做对象来看
// 根据结论: Function, 和 函数, 和 Function.prototype 之间的关系, 可以得到
// Array 是 Function 的实例, 继承自 Fucntion.prototype
// Date 是 Function 的实例, 继承自 Fucntion.prototype
// Object 是 Function 的实例, 继承自 Fucntion.prototype
// ...
// Fucntion 是 Function 的实例, 继承自 Fucntion.prototype
// 结论 Function.__proto__ 就是 Function.prototype
结论案例:
var o = {};
o.name = 'jim';
o.sayHello = function () {};
// 属性与方法有一个特点是和当前对象息息相关的
// 这些与当前对象息息相关的属性与方法就称为实例属性与实例方法
// 那么再函数中, 也可以添加属性与方法
// function Foo() {}
// Foo.name = 'tom';
// 这个属性对于 Foo 的实例来说是全局的, 和个体对象没有关系
// 称这样的属性与方法为 静态属性与静态方法
// 这两组概念在实际使用, 实例成员与对象息息相关, 而静态成员一般
// 作为通用的工具性的成员使用
// $('p').each( function ... );
// $.each()
// jQuery.each( this, fn )
</script>
疑问:
// 训练代码分析的能力
// 1, 分析当前执行行上下游那些局部变量, 那些全局变量, 并且值为多少
// 2, 单步运行代码. 然后分析每一句话是干什么用的. 并且执行完该语句后
// 对全局变量与局部变量有什么影响
// 疑点
function Fn() {}
function Foo() {}
var o = new Fn();
console.log(o instanceof Fn); //true
Fn.prototype = new Foo();
Fn.prototype.constructor = Fn;
console.log(o instanceof Fn); // false
console.log(o instanceof Foo); // false
function Fn() {}
function Foo() {}
var f = new Fn();
// f -> Fn.prototype -> Object.prototype -> null
// 覆盖
var o;
Fn.prototype = o = new Foo();
var f = new Fn();
// f -> o -> Foo.prototype -> Object.prototype -> null
// 传统的 C++ 系列的编程语言 (C++, Java, C#, Swift)
// 变量是强类型
// int n = 123;
// string s = 'abc';
// n = s; // 报错
// 什么是多态
// 给父类调用方法, 由绑定在父类的子类实现
// 动物 anim = new 子类(); // 猫, 狗, 猪, ...
// anim.叫();
// 这种用法来源于, anim 只能被赋值为 动物类型 以及 它的子类的类型
var a = ...;
if ( typeof a.fn === 'function' ) a.fn();
function Fn(){}
function Foo(){}
var o = new Fn()
console.log(o instanceOf Fn) -- true
//o-->Fn.prototype(原来的)
//Fn.prototype是否在o的原型链上
Fn.prototype = new Foo();
console.log(o instanceOf Fn) -- fasle
// new Foo() 是否在o的原型链上
console.log(o instanceOf Foo) -- fasle
实例成员和静态成员:
// 术语:
// 对象
// 实例: 一般在描述实例这个概念的时候, 也是指对象. 但是实例一般是用来描述一个由某个构造函数创建的对象
// 一般称作为 xxx 构造函数的实例
// 构造函数
// 实例成员就是 由构造函数创建的对象的成员
// 静态成员就是 构造函数的成员
// 一般在使用的时候, 将通用的方法 由 静态成员提供, 实例成员如果要实现该功能, 调用静态成员来实现
//
/*
function Person() {
this.sayHello = function () { alert(' Hello JavaScript '); };
}
*/
// Person.name 静态成员, 静态属性
// new Person().sayHello(); 实例成员, 实例方法
// alert( Person.name );
// ( new Person ).sayHello();
// 在 商品案例中
// 当页面向下滚动的时候动态的加载更多商品
// 当动态加载商品的时候, 应该考虑如果商品已经在页面中有了, 就不再加载该商品
// 所以
// 一把来说, 展示一个商品, 就是展示商品的信息与链接
// 就在在判断一个对象的所有属性相等, 则为同一件商品
var data = '[{name:"神器js", price:100, img:"1234567800.jpg"},{name:"神器js", price:100, img:"12345678900.jpg"}]';
var o = eval( "(" + data + ")" );
// var o1 = o[ 0 ];
// var o2 = o[ 1 ];
// alert( o1 == o2 );
// 对象都有一个构造函数的东西 --对象的复制
var Goods = function ( o ) {
// ...
for ( var k in o ) {
this[ k ] = o[ k ];
}
}
var o1 = new Goods( o[ 0 ] );
var o2 = new Goods( o[ 1 ] );
// 要判断是否相同, 就判断每一个属性是否相同
// var compare = function ( s1, s2 ) {
// return s1.name === s2.name &&
// s1.price === s2.price &&
// s1.img === s2.img;
// };
// alert( compare( o1, o2 ) );
// 在项目中, 这种类似的判断可能会很多, 为了便于管理, 该判断是和商品息息相关的.
// 因此应该将该方法与该类型绑定在一起, 以便使用与维护
// 函数也是对象, 也可以利用动态添加成员的办法添加成员
Goods.compare = function ( s1, s2 ) {
return s1.name === s2.name &&
s1.price === s2.price &&
s1.img === s2.img;
};
// alert( Goods.compare( o1, o2 ) );
// 为了方便调用, 我应该同时保留 静态方法与实例方法
// 复用 isEqualTo--> 实例方法
Goods.compare---静态方法
Goods.prototype.isEqualsTo = function ( o ) {
// 比较 this 与 o 是否相等
return Goods.compare( this, o );
}
alert( o1.isEqualsTo( o2 ) );
函数的属性与方法:
// 1, 函数名.name
// 2, 函数名.length
// 形参的数量
// 与 arguments.length 进行区分
// function Foo( a, b, c ) {}
// alert( Foo.length ); // 与函数定义的时候 参数定义的个数
// 如何判断传入的参数与定义的参数个数一样?
// 就是 函数名.length === arguments.length
// 3, 函数名.caller // 已被废除