/
JavaScript-guide.txt
1235 lines (1193 loc) · 61.7 KB
/
JavaScript-guide.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
1、数据类型
1.1、分类
(1)原始类型
Number:整型,浮点数,NaN,无穷大。 //JavaScipt中%是求余运算
字符串(String)
布尔值(Boolean):逻辑运算和比较运算的结果值 //在JavaScipt中坚持使用===比较
JavaScipt把null、undefined、0、NaN和空字符串''视为false,其他值一概视为true。(' '为true)
null:表示一个“空”的值 //Java也用null,Swift用nil,Python用None
undefined:表示值未定义 //仅仅在判断函数参数是否传递的情况下有用
Symbol:ES6新定义,在其他编程语言中symbol也被称为原子(atoms)。
(2)对象类型
数组类(Array):JavaScipt的数组可以包括任意数据类型
函数类(Function):低效!创建时解析,函数声明和函数表达式则是与其他代码一起解析
对象类(Object):由键-值组成的无序集合,键都是String类型,
值可以说任意数据类型
.
.
.
1.2、字符串String
(1)转义字符:\
\n表示换行,\t表示制表符,\\表示字符\
ASCII字符可以用\x##形式的十六进制表示,例如:‘\x41’; //完全等同于‘A’
Unicode字符可以用\u####表示,例如:‘\u4e2d\u6587’; //完全等同于‘中文’
注意:由于多行字符串用\n费事,ES6标准新增了用反撇号`...`表示。
(2)模板字符串
由于字符串连接用+费事,ES6标准新增了模板字符串,例如:
'你好,'+name+'!' 可以写成 `你好,${name}!` //注意是反撇号!!
(3)操作字符串
String类型存在String.length属性,可以用String[index]获取。
注意:如果对String的某个索引赋值,不会报错,但是也不会改变String的值。
方法:toUpperCase,toLowerCase,indexOf,substring
var s = 'Hello, Word';
s.toUpperCase(); //返回'HELLO, WORD!'
s.toLowerCase(); //返回'hello, word!'
s.indexOf('Word'); //返回7,注意空格符
s.indexOf('word'); //没有找到指定的字串,返回-1
s.substring(0,5); //从索引0开始到5(不包括5),返回'Hello'
s.substring(7); //从索引开始到结束,返回'Word'
1.3、数组Array
(1)Array可以包含任意数据类型,并通过index来访问每个元素,index被视为对象的属性。
注意:直接对Array的length赋值或者通过索引(index)将对应的元素修改成新的值,均有可能改变
Array的大小。 //大多数其他编程语言不允许直接改变数组的大小,越界访问索引会报错,如Java。但
JavaScipt的Array不会有任何错误,建议不直接修改Array的大小,访问索引时要确保索引不越界。
(2)方法:
不改变原有数组,单一数组操作
找到匹配元素的第一个索引,返回索引值: arr.indexOf(searchElement[,fromIndex=0]);
//未匹配,返回-1
截取数组,返回所截取部分Array:
arr.slice(); //可以利用此方法复制一个Array
arr.slice(begin); arr.slice(begin,end); //但不包含end
排序Array,默认排序顺序是Unicode码点,返回新Array:
arr.sort();
arr.sort(compareFunction);
Araay(类数组对象)的所有元素连接到一个字符串,返回字符串: arr.join(separator)
//separator默认为',';
多维数组会依index顺序转化,separator只起一次作业,多维数组内部用','相连;
null和undefined显示空字符,NaN仍为NaN.
不改变数组,多个数组操作
合并多个Array,返回新Array:Array.concat(value1,...,valueN)
//对多维数组只进行降一维度拆解
改变原有数组,单一数组操作
Array的末尾添加若干元素,返回Array的新length: arr.push(element1,...,elementN);
Array删除最后一个元素,返回被删除的元素: arr.pop(); //如arr为空,返回undefined
Array的头部添加若干元素,返回Array的新length: arr.unshift(element1,...,elementN);
Array删除第一个元素,返回被删除的元素: arr.shift(); //如arr为空,返回undefined
颠倒Array中元素的位置,返回也是新Array: arr.reverse();
var Arr = ['one','two','three'];
newArr = Arr.reverse();
console.log(Arr); //["three", "two", "one"]
console.log(newArr); ////["three", "two", "one"]
同时删除和添加若干元素的“万能方法”,返回被删除元素组成的Array:
arr.splice(start);
arr.splice(start,deleteCount); //如果deleteCount大于start后面的元素总和,
则start后面的元素全部删除;如果deleteCount小于等于0,返回空数组[]
arr.splice(srart,deleteCount,item1,item2,...);
1.4、对象Object
(1)用{...}表示一个对象,键值对以xx:xx形式声明,用','隔开。
建议在最后一个键值对末尾不加上',',低版本IE会报错。
(2)键名可以是一个有效的变量名(区分大小写,允许包含字母、数字、$、_,第一个字符不能是数字,
不允许空格和其他标点符号,禁止使用JavaScipt关键词、保留字全名);如果包含特殊字符,
就必须用''括起来。访问是必须用['XXX']来访问。
(3)判断Object是否存在一个属性(继承的也算):prop in ObjectName
//prop为一个字符串类型或数组索引或Symbol类型(ES6新特性)的属性名,存在返回true
(4)判断一个属性是否是Object自身拥有的:obj.hasOwnProperty(prop)
//prop为一个字符串类型或Symbol类型,拥有返回true
1.5、函数Function
(1)语法:new Function([arg1[,arg2[,...argN]],]functionBody)
注意:低效!创建时解析;而函数声明和函数表达式是与其他代码一起解析。
2、条件判断
2.1省略{}
如果语句块只包含一条语句,那么可以省略{},但不建议这样做,如果后来想添加一些语句,却忘了写
{},就改变了if...else...的语义。
2.2判断条件(condition)
JavaScipt把null、undefined、0、NaN和空字符串''视为false,其他值一概视为true。(' '为true)
判断条件(condition)不能为空,会报SyntaxError。
3、循环
3.1 for循环的三个条件都可以为空,这样必须用break语句退出循环,不然就是死循环。
3.2 for...in 循环,可以把一个对象的所有属性一次循环出来。
for...in 对Array的循环得到是String而不是Number,
需要利用Number(value),parseInt(string,radix基数),parseFloat(string)转化
for...in的坑:
1.顺序不确定,具体的顺序依赖引擎的实现;
2.对象的每个属性具有描述器,enumerable(可枚举)为false时,不会被遍历
3.for...in对象属性时,受原型链影响(enumerable为true的话)。
3.3 while循环:while(condition){循环语句},do{循环语句}while(condition);
do{...}while(),循环体至少执行一次,for和while可能一次都不执行。
4、数据结构Map和Set
JavaScipt的默认对象表示方式{}可以视为其他语言的Map和Dictionary的数据结构,即一组键值对。
但是JavaScipt的对象有个小问题--键名key必须是字符串。但实际上Number或者其他数据类型作为键名也是
非常合理的,为了解决这个问题,ES6规范引入了新的数据类型Map。
4.1 Map 是一组key-value的集合
初始化:需要一个二维数组,或者直接初始化一个空Map。
属性:Map.size,类似数组的length,值为Map的键值对数量
方法:
var m = new Map(); //初始化Map
m.set('Adam',67); //添加一个新的key-value
m.has('Adam'); //true 是否存在key'Adam',返回Boolean。
m.get('Adam'); //返回相对应的value,不存在返回undefined
m.delete('Adam'); //删除key'Adam'的数据,返回true,如果key不存在返回false。
m.clear(); //清空Map'm'的所有数据,返回undefined。
注意:由于一个key只能对应一个value,所有对同一个key放入value,后面的值会覆盖前面的值。
4.2 Set 是一组key的集合
初始化:需要一个一维Array,或者直接初始化一个空Set。
属性:Set.size,类似数组的length,值为Set的key数量
方法:
var s = new Set(); //初始化Set
s.add(1); //Set {1} 添加一个新的key,返回新的Set:s
s.add(5).add('some text'); //Set {1,5,"some text"} chainable可链的
s.has(5); //true 是否存在key 5,返回Boolean。
s.delete(1); //删除key 1的数据,返回true,如果key不存在返回false.
s.clear(); //清空Set's'的所有数据,返回undefined。
注意:Set的key可以重复添加,但不会有效果,Number和String是不同的key。
5、iterable:ES6新的对象类型
遍历Array可以采用下标循环,遍历Map和Set就无法使用下标。ES6标准引入了新的iterable类型。
Array、Map、Set都属于iterable类型,可以通过新的for...of循环来遍历,遍历的是元素。
例:var a = ['A', 'B', 'C'];
var s = new Set(['A', 'B', 'C']);
var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
for (var x of a) { // 遍历Array
alert(x);
}
for (var x of s) { // 遍历Set
alert(x);
}
for (var x of m) { // 遍历Map
alert(x[0] + '=' + x[1]);
}
5.1遍历方法:for...in和for...of
对于Array,for...in实质上是遍历Array对象的属性名称,for...of遍历的是length属性的元素;
var a = ['A','B','C'];
a.name = 'Hello';
for(var x in a){
console.log(x); //'0','1','2','name'
}
var a = ['A', 'B', 'C'];
a.name = 'Hello';
a[3] = 'D';
for (var x of a) {
alert(x); // 'A', 'B', 'C','D'
}
当我们手动给Array对象添加了额外的属性后,
for...in会把name包括在内,但Array的length属性却不包括在内;
for..of就不会把name包括在内,只包含length属性所对应的元素。
5.2遍历方法:forEach() ES5.1标准引入
对于Array,回调函数参数为element,index,array本身
对于Map,回调函数参数为value,key,map本身
对于Set,回调函数参数为element,sameElement,set本身,前两个参数都是元素本身。
注意:由于JavaScipt的函数调用不要求参数必须一致,因此可以忽略后两个参数,
只传入element或者value也可以。
6、函数定义和调用:最基本的一种代码抽象的方式
6.1函数初始化
方式一:function name(argument1,...){...}
方式二:var name = function (arg1,...){...}; //后面有个;,表示语句结束
注意:函数体内部的语句在执行到return时,函数执行完毕,并返回结果。如果没有return语句,
函数返回undefined。
6.2调用函数
如果调用时未传入参数,arg1将收到undefined,如果要避免收到undefined,可以对参数进行类型检查。
6.3实参arguments
JavaScipt有个关键字arguments,对于每个function都是存在的,只在函数内部起作用。
arguments对象类似Array,但不是一个数组对象。
实际上arguments最常用于判断传入参数的个数:
例:把第二个传入的参数变成可选参数
//foo(a[,b],c)
//接收2~3个参数,b是可选参数,如果只传2个参数,b默认为null
function foo(a,b,c){
if(arguments.length === 2){
//实际传入的参数是a和b,c为undefined
c = b; //把b赋值给c
b = null; //b变成默认值
}
//...
}
由于JavaScript允许接收任意个函数,于是不得不用arguments来获取所有参数。
例:把非预期的参数放入rest数组中
function foo(a,b){
if(arguments.length>2){
var i, rest = [];
for(i = 2;i<arguments.length;i++){
rest.push(arguments[i]);
}
}
console.log('a='+a);
console.log('b='+b);
console.log('no expect arguments = '+rest);
}
6.4 rest参数
ES6标准引入了rest参数,上述例子可以改写为
function foo(a,b,...rest){
console.log('a='+a);
console.log('b='+b);
console.log('no expect arguments = '+rest);
}
rest参数只能写在最后面,前面用...标识。
注意:如果传入的参数连正常定义的参数都没填满,rest参数会接收一个空数组,而不是undefined。
6.5 注意 return语句坑
JavaScript引擎有一个在行末自动添加分号的机制!
基于此,return有个大坑!
例:return语句块不执行的坑
function foo(){
return {name: 'foo'};
}
foo(); //{name: 'foo'}
如果把return语句拆成两行:
function foo(){
return
{name: 'foo'};
}
foo(); //undefined
在这里return就变成了return; 所以正确的多行写法是
function foo(){
return{ //这里不会自动加分号因为{表示语句尚未结束
name: 'foo'
};
}
7、函数变量作用域 function scope
7.1 作用域
由于JavaScript的函数可以嵌套,此时,内部函数可以访问外部函数定义的变量,反过来则不行。
注意:JavaScript的函数在查找变量时从自身函数定义开始,从内向外查找。如果内部函数定义了
与外部函数重名的变量,则内部函数的变量将屏蔽外部函数的变量。
7.2 变量提升
JavaScript的函数定义有个特点,先扫描整个函数体,把所有声明的变量
提升到函数顶部!
因此,在函数内部定义变量时,建议严格遵守“在函数内部首先申明所有变量”这一个规则。
常见做法是用一个var申明函数内部用到的所有变量。
7.3 全局作用域
不在任何函数内定义的变量就具有全局作用域。
全局作用域的变量实际上被绑定到全局对象window的一个属性。
实际上,JavaScript只有一个全局作用域,如果变量在全局作用域没有找到,则报ReferenceError错误。
7.4 名字空间
不同的JavaScript文件如果使用了相同的全局变量,或者定义了相同名字的顶层函数,
都会造成命名冲突,并且很难被发现。
减少冲突的方法:把私有的所有变量和函数都绑定到一个全局变量中!
7.5 局部作用域
用于JavaScript的变量作用域实际上是函数内部,所有在for循环等条件语句块中是无法定义具有局部
作用域的变量的。
let: ES6标准为了解决块级作用域,引入了新的关键字let,let申明的变量具有块级作用域。
7.6 常量
由于var 和let 声明的都是变量,在ES6之前通常使用大写字母来表示“这是一个常量,不要修改它的值”。
ES6标准引入了新的关键字const来定义常量,const和let一样具有块级作用域。
const在声明的同时必须初始化,可以同时声明多个常量。
const常量不可以被重复声明(SyntaxError),也不能对其直接赋值修改(TypeError)。
8、函数-方法 function-method
绑定到对象上的函数称为方法,和普通函数基本没有区别,方法内部具有this关键字
8.1 this关键字
谁调用this,就指向谁!
JavaScriptd中以对象形式调用了this,就指向被调用的对象;单独调用函数,视全局对象调用了该函数,
所以this指向全局对象,即window。
注意:ECMA标准规定,在strict模式下让函数的this指向undefind。
在strict模式下,要让方法内部定义的函数的this指向该方法所绑定的对象,可以用that变量先捕获this。
例:
'use strict';
var xiaoming = {
name: '小明',
birth: 1990,
age: function(){
var that = this; //在方法内部一开始就捕获this,指向对象xiaoming
function getAgeFromBirth() {
var y = new Date().getFullYear();
return y - that.birth; //用that而不是this,这里的this指向undefind
}
return getAgeFromBirth();
}
};
8.2 apply
在一个独立的函数调用中,根据是否strict模式,this指向undefined或window
Syntax: fun.apply(thisArg[,argsArray]);
thisArg:将this指向绑定改为thisArg;
[argsArray]可选项,一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 fun 函数。
巧妙利用argumens关键字捕获参数。
8.3 call
与apply方法相似,只是函数参数不以数组传入,而是逐个传入。
Syntax: fun.call(thisArg,arg1,arg2,...)
9、高阶函数 Higher-order function
由于JavaScript的变量可以指向函数,函数的参数能接受变量,那么一个函数接受另一个函数作为参数,
此类函数称之为高阶函数。
9.1 map() 定义在JavaScript的Array中,实质上是单个元素的遍历操作。
Syntax: arr.map(callback[,thisArg]) //返回值是一个新数组,不改变原有数组
callback有三个参数:currentValue(第一个),数组正在处理的当前元素;
index(第二个),数组正在处理的当前元素的索引;
array(第三个),map方法被调用的数组。
thisArg: 可选,执行callback函数时使用的this值。
注意:map 方法会给原数组中的每个元素都按顺序调用一次 callback 函数。
如果callback所需参数与map默认传入的不一致,需特别注意!有坑!!!!
callback 每次执行后的返回值(包括 undefined)组合起来形成一个新数组。
callback 函数只会在有值的索引上被调用;
那些从来没被赋过值或者使用 delete 删除的索引则不会被调用。
例:把Array的所有数字转为字符串
var arr = [1,2,3,4,5];
arr.map(String); //['1','2','3','4','5']
9.2 reduce() 定义在JavaScript的Array中,实质上两个元素的遍历操作。
Syntax: arr.reduce(callback[,initialValue]) //返回值是callback函数处理的结果,不改变原有数组
callback有四个参数:accumulator(第一个),上一次调用回调返回的值,初始是initialValue
currentValue(第二个),数组正在处理的当前元素;
index(第三个),数组正在处理的当前元素的索引;
如果提供了initialValue,从0开始;否则从1开始
array(第四个),reduce方法被调用的数组。
initialValue: 可选项,其值用于第一次调用callback的第一个参数。
例:数组扁平化
var flattened = [[0,1],[2,3],[4,5]].reduce(function(a,b){
return a.concat(b);
},[]); //flattened is [0,1,2,3,4,5]
9.3 filter() 定义在JavaScript的Array中,实质上是过滤操作。
filter为数组中的每个元素调用一次callback函数,并利用所有使得 allback返回true或等价于true的值
创建一个新数组。callback只会在已经赋值的索引上被调用,对于那些已经被删除或者从未被赋值的索引
不会被调用。那些没有通过 callback 测试的元素会被跳过,不会被包含在新数组中。
Syntax: arr.filter(callback[,thisArg]) //返回值是一个新数组,不改变原有数组
callback有三个参数:currentValue(第一个),数组正在处理的当前元素;
index(第二个),数组正在处理的当前元素的索引;
array(第三个),map方法被调用的数组。
thisArg: 可选,执行callback函数时使用的this值。
例:把Array中的空字符串删掉
var arr = ['A', '', 'B', null, undefined, 'C', ' '];
var r = arr.filter(function (s) {
return s && s.trim(); // 注意:IE9以下的版本没有trim()方法
});
console.log(r); // ['A', 'B', 'C']
trim的原生JS
if (!String.prototype.trim) {
String.prototype.trim = function () {
return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
};
}
9.4 sort() 定义在JavaScript的Array中,实质上是排序操作。此函数改变原有数组,返回新数组。
Syntax: arr.sort() //未指定compareFunction,元素会转换为字符串,按逐个字符的Unicode位点排序
arr.sort([compareFunction]) //可选,传入两个参数(a,b)若函数返回值:
小于0,a排前;等于0,相对位置不变;大于0,b排前。
注意:必须总是对相同的输入返回相同的比较结果,否则排序的结果将是不确定的。
例:对纯数字数组进行升序
var numbers = [4, 2, 5, 1, 3];
var newNumbers = numbers.sort(function(a, b) {
return a - b;
});
console.log(numbers); // [1, 2, 3, 4, 5]
console.log(newNumbers); // [1, 2, 3, 4, 5]
console.log(numbers === newNumbers); //true
10、闭包 Closures
10.1 闭包是一种特殊的对象。它由两部分构成:函数,以及创建该函数的环境。
环境由闭包创建时在作用域中的任何局部变量组成。
10.2 注意:如果不是因为某些特殊任务而需要闭包,在没有必要的情况下,在其它函数中创建函数是不明智的,
因为闭包对脚本性能具有负面影响,包括处理速度和内存消耗。
10.3 返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量。
如果一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,
无论该循环变量后续如何更改,已绑定到函数参数的值不变。
ES6标准引入的块级作用域let,可以修复这个bug。
10.4 一个立即执行的匿名函数写法:(function(){...})();
10.5 利用闭包实现私有变量封装。
例:创建一个计算器
'use strict'
function create_counter(initial){
var x = initial || 0;
return {
inc: function(){
x ++;
return x;
}
}
}
使用举例:var c1 = create_counter();
c1.inc(); //1
c1.inc(); //2
var c2 = create_counter(10);
c2.inc(); //11
c2.inc(); //12
10.6 闭包可以把多参数函数变成单参数函数
例:构建平方和立法函数pow2,pow3
//闭包原函数Math.pow
function makePow(n){
return function(x){
return Math.pow(x,n);
}
}
//创建两个新函数pow2,pow3
var pow2 = makePow(2);
var pow3 = makePow(3);
//测试
console.log(pow2(5)); //25
console.log(pow3(7)); //343
11、箭头函数 Arrow Function
11.1 箭头函数表达式的语法比函数表达式短,并且不绑定自己的 this,arguments,super或new.target。
此外,箭头函数总是匿名的。
11.2 如果要返回一个对象{foo:x},需要把它()起来,如:var func = () => ({foo:x});
11.3 this 箭头函数看上去是匿名函数的一种简写,但实际上,箭头函数和匿名函数有个明显的区别:
箭头函数内部的this是词法作用域,由上下文确定。
11.4 arguments 箭头函数不会在其内部暴露出arguments对象:
arguments.length, arguments[0], arguments[1] 等等,都不会指向箭头函数的 arguments,
而是指向了箭头函数所在作用域的一个名为arguments的值(如果有的话,否则,就是 undefined。)
12、生成器 generator
12.1 生成器对象是由一个 generator function 返回的,并且它符合可迭代协议和迭代器协议。
12.2 调用generator对象的方法
gen.next();
gen.return(value);
for...of循环
13、标准对象
13.1 typeof
Syntax: typeof operand
例:
typeof 123; // 'number'
typeof NaN; // 'number'
typeof 'str'; // 'string'
typeof true; // 'boolean'
typeof undefined; // 'undefined'
typeof Math.abs; // 'function'
typeof null; // 'object'
typeof []; // 'object'
typeof {}; // 'object'
13.2 包装对象
http://blog.csdn.net/molly_xu/article/details/51194656 //浅析了包装对象的意义
值从逻辑上是没有方法,调用方法JS内部已经隐式地帮我们帮创建了一个包装对象了。
包装对象用new创建:var n = new Number(123); // 123,生成了新的包装类型
var b = new Boolean(true); // true,生成了新的包装类型
var s = new String('str'); // 'str',生成了新的包装类型
上述n,b,s的类型已经变成Object了,包装对象和原始值用===比较会返回false:
typeof new Number(123); // 'object'
new Number(123) === 123; // false
typeof new Boolean(true); // 'object'
new Boolean(true) === true; // false
typeof new String('str'); // 'object'
new String('str') === 'str'; // false
Number()、Boolean和String()被当做普通函数,
把任何类型的数据转换为number、boolean和string类型(注意不是其包装类型)
例:
var n = Number('123'); // 123,相当于parseInt()或parseFloat()
typeof n; // 'number'
var b = Boolean('true'); // true
typeof b; // 'boolean'
var b2 = Boolean('false'); // true! 'false'字符串转换结果为true!因为它是非空字符串!
var b3 = Boolean(''); // false
var s = String(123.45); // '123.45'
typeof s; // 'string'
注意:包装类型是个大坑!!闲的蛋疼也不要使用包装对象!尤其是针对string类型!!!
注意遵守规则:
1.不要使用new Number()、new Boolean()、new String()创建包装对象;
2.用parseInt()或parseFloat()来转换任意类型到number;
3.用String()来转换任意类型到string,或者直接调用某个对象的toString()方法;
4.通常不必把任意类型转换为boolean再判断,因为可以直接写if (myVar) {...};
5.typeof操作符可以判断出number、boolean、string、function和undefined;
6.判断Array要使用Array.isArray(arr);
7.判断null请使用myVar === null;
8.判断某个全局变量是否存在用typeof window.myVar === 'undefined';
9.函数内部判断某个变量是否存在用typeof myVar === 'undefined'。
13.3 toString()的一些坑
并非所有对象都有toString()方法,null和undefined没有toString()方法。
number对象调用toString()报SyntaxError: 123.toString(); //SyntaxError
需要特殊处理一下:123..toString(); //'123',注意是两个点!
(123).toString(); //'123'
14、Date
14.1 Date对象用来表示日期和时间。
var now = new Date();
now; // Wed Jun 24 2015 19:49:22 GMT+0800 (CST)
now.getFullYear(); // 2015, 年份
now.getMonth(); // 5, 月份,注意月份范围是0~11,5表示六月
now.getDate(); // 24, 表示24号
now.getDay(); // 3, 表示星期三
now.getHours(); // 19, 24小时制
now.getMinutes(); // 49, 分钟
now.getSeconds(); // 22, 秒
now.getMilliseconds(); // 875, 毫秒数
now.getTime(); // 1435146562875, 以number形式表示的时间戳
14.2 如果要创建一个指定日期和时间的Date对象,可以用:
方式一:
var d = new Date(2015, 5, 19, 20, 15, 30, 123);
d; // Fri Jun 19 2015 20:15:30 GMT+0800 (CST)
JavaScript的月份范围用整数表示是0~11,0表示一月,1表示二月……,所以要表示六月,我们传入的是5!
方式二:创建一个指定日期和时间的方法是解析一个符合ISO 8601格式的字符串,返回一个时间戳。
var d = Date.parse('2015-06-24T19:49:22.875+08:00');
d; // 1435146562875
var day = new Date(1435146562875);
day; // Wed Jun 24 2015 19:49:22 GMT+0800 (CST)
14.3 时区 Date对象表示的时间总是按浏览器所在时区显示的
var d = new Date(1435146562875);
d.toLocaleString();
// '2015/6/24 下午7:49:22',本地时间(北京时区+8:00),显示的字符串与操作系统设定的格式有关
d.toUTCString(); // 'Wed, 24 Jun 2015 11:49:22 GMT',UTC时间,与本地时间相差8小时
14.5 时间戳
Date.now() 方法返回自1970年1月1日 00:00:00 UTC到当前时间的毫秒数。//IE9以下的版本没有
兼容方法:
if (!Date.now) {
Date.now = function now() {
return new Date().getTime();
};
}
15、RegExp 正则对象 regular expression object
[a-zA-Z\_\$][0-9a-zA-Z\_\$]* 可以匹配由字母或下划线、$开头,
后接任意个由一个数字、字母或者下划线、$组成的字符串,也就是JavaScript允许的变量名;
[a-zA-Z\_\$][0-9a-zA-Z\_\$]{0, 19} 更精确地限制了变量的长度是1-20个字符
(前面1个字符+后面最多19个字符)。
例:利用正则切分字符串
'a b c'.split(' '); // ['a', 'b', '', '', 'c']
'a b c'.split(/\s+/); // ['a', 'b', 'c']
'a,b, c d'.split(/[\s\,]+/); // ['a', 'b', 'c', 'd']
'a,b;; c d'.split(/[\s\,\;]+/); // ['a', 'b', 'c', 'd']
15.1 Syntax
/pattern/flags // 字面量: 模式 标志
new RegExp(pattern [, flags]) // 构造函数: 模式 标志
RegExp(pattern [, flags]) // 工厂符号: 模式 标志
15.1 参数:pattern: 正则表达式的文本
· flags: 如果指定,标志可以具有以下值得任意组合:
g 全局匹配;找到所有匹配,而不是在第一个匹配后停止
i 忽略大小写
m 多行; 将开始和结束字符(^和$)视为在多行上工作
(例如,分别匹配每一行的开始和结束(由 \n 或 \r 分割),
而不只是只匹配整个输入字符串的最开始和最末尾处。
u Unicode; 将模式视为Unicode序列点的序列
y sticky标志; 仅匹配目标字符串中此正则表达式的lastIndex属性指示的索引
(并且不尝试从任何后续的索引匹配)。
15.2 方法
regexObj.test(str) //如果正则表达式与指定的字符串匹配,返回true;否则false。
regexObj.exec(str) //如果成功匹配,exec() 方法返回一个数组并更新正则表达式对象的属性。
返回的数组的第一个元素是正则表达式匹配到的整个字符串,后面的字符串表示匹配成功的子串;
如果匹配失败,exec() 方法返回 null。
例:正则表达式识别合法的时间
var re = /^(0[0-9]|1[0-9]|2[0-3]|[0-9])
\:(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])
\:(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])$/;
re.exec('19:05:30'); // ['19:05:30', '19', '05', '30']
15.3 分组:用()表示的就是要提取的分组(Group)。
15.4 贪婪匹配:正则默认贪婪匹配,即匹配尽可能多的字符
15.5 全局搜索:标志位 g
全局匹配类似搜索,因此不能使用/^...$/,那样只会最多匹配一次。
例:多次匹配模式,运行exec(),正则表达式本身会更新lastIndex属性,表示上次匹配到的最后索引位置:
var s = 'JavaScript, VBScript, JScript and ECMAScript';
var re=/[a-zA-Z]+Script/g;
// 使用全局匹配:
re.exec(s); // ['JavaScript']
re.lastIndex; // 10
re.exec(s); // ['VBScript']
re.lastIndex; // 20
re.exec(s); // ['JScript']
re.lastIndex; // 29
re.exec(s); // ['ECMAScript']
re.lastIndex; // 44
re.exec(s); // null,直到结束仍没有匹配到
16、JSON (JavaScript Object Notation)
JSON字符集必须是UTF-8,表示多语言就没有问题了。
为了统一解析,JSON的字符串规定必须用双引号"",Object的键也必须用双引号""。
16.1 方法 JSON.parse() JSON.stringify()
JavaScript值转换为JSON字符串:
Syntax: JSON.stringify(value[,replacer[,space]]) //返回一个表示给定值的JSON字符串
Parameters: value 需要序列化的值
replacer: function 转化处理函数
(可选) array 只有包含在这个数组中的属性名才会被序列化到最终的 JSON 字符串中
null或undefined或未提供 对象所有的属性都会被序列化
space: 用于美化输出(pretty-print),可能值:
(可选)数字 它代表有多少的空格,上限为10,该值若小于1,则意味着没有空格。
字符串 该字符串(前十个有效)将被作为空格
null或undefined或未提供 无空格
toJSON方法:如果一个被序列化的对象拥有 toJSON 方法,
那么该 toJSON 方法就会覆盖该对象默认的序列化行为;也可以通过调用此方法将对象序列化。
JSON字符串解析成JavaScript对象:
Syntax: JSON.parse(text[,reviver]) //返回Object,对应给定的JSON文本
Parameters: text 需要被解析的JSON字符串
reviver 可选项,处理函数。
17、面向对象编程 Object-oriented
17.1 面向对象编程的两大基本概念
类:类是对象的类型模板,例如,定义Student类来表示学生,类本身是一种类型,
Student表示学生类型,但不表示任何具体的某个学生;
实例:实例是根据类创建的对象,例如,根据Student类可以创建出xiaoming、xiaohong、
xiaojun等多个实例,每个实例表示一个具体的学生,他们全都属于Student类型。
JavaScript不区分类和实例的概念,而是通过原型(prototype)来实现面向对象编程。
例:
var Bird = {
fly: function () {
console.log(this.name + ' is flying...');
}
};
xiaoming.__proto__ = Bird;
注意:上述代码仅用于演示目的。在编写JavaScript代码时,
不要直接用obj.__proto__去改变一个对象的原型!
17.2 创建对象
创建一个Array对象: var arr = [1,2,3];
其原型链是: arr --> Array.prototype --> Object.prototype --> null
创建一个函数: function foo() { return 0;}
其原型链是: foo --> Function.prototype --> Object.prototype --> null
构造函数
除了直接用{...}创建一个对象外,JavaScript还可以用构造函数的方法来创建对象。
首先创建一个构造函数:(命名规则,首字母应大写)
function Student(name) {
this.name = name;
this.hello = function () {
alert('Hello, ' + this.name + '!');
}
}
利用关键字new来调用构造函数,返回一个对象:
var xiaoming = new Student('小明');
xiaoming.name; //'小明'
xiaoming.hello(); //Hello, 小明!
新建的xiaoming的原型链是: xiaoming --> Student.prototype --> Object.prototype --> null
注意:如果不写new,这就是一个普通函数!Student返回undefined。写了new,默认返回this!
共享函数,节省内存:
function Student(name){
this.name = name;
}
Student.prototype.hello = function(){
console.log('Hello, '+this.name+'!');
};
封装new操作,编写createStudent()函数:
function Student(props){
this.name = props.name || '匿名'; //默认值为'匿名'
this.grade = props.grade || 1; //默认值为1
}
//共享函数
Student.prototype.hello = function (){
console.log('Hello, '+this.name+'!');
};
//封装new操作,编写createStudent
function createStudent(props){
return new Student(props || {}) //默认传入{}空数组
}
优点:不需要new调用;参数灵活。(如果对象有很多属性,只传递某些属性,剩下的属性可以用默认值。)
17.3 原型继承 Prototypical Inherit
利用一个中间对象来实现正确的原型链,中间对象利用空函数F来实现。(JSON发明者道格拉斯的代码)
//PrimaryStudent构造函数:
function PrimaryStudent(props){
Student.call(this.pros); //绑定this变量
this.grade = props.grade || 1; //对于默认属性的修改
}
//空函数F:
function F(){
}
//把F的原型指向Student.prototype:
F.prototype = Student.prototype;
//把PrimaryStudent的原型指向一个新的F对象,F对象的原型指向Student.prototype:
PrimaryStudent.prototype = new F();
//把PrimaryStudent原型的构造函数修复为PrimaryStudent:
PrimaryStudent.prototype.constructor = PrimaryStudent;
这样,基于Student扩展出PrimaryStudent的原型链是:
new PrimaryStudent() --> PrimaryStudent.prototype --> Student.prototype -
-> Object.prototype --> null
注意:函数F仅用于桥接,仅创建了new F()实例,并没有改变原有的Student定义的原型链。
可以把继承这个动作用inherits()函数封装起来,隐藏F的定义,简化代码,且便于复用:
function inherits(Child, Parent){
var F = function(){};
F.prototype = Parent.prototype;
child.prototype = new F();
child.prototype.constructor = child;
}
//复用inherits()函数
function Student(props) {
this.name = props.name || 'Unnamed';
}
Student.prototype.hello = function () {
alert('Hello, ' + this.name + '!');
}
function PrimaryStudent(props) {
Student.call(this, props);
this.grade = props.grade || 1;
}
// 实现原型继承链:
inherits(PrimaryStudent, Student);
// 绑定其他方法到PrimaryStudent原型:
PrimaryStudent.prototype.getGrade = function () {
return this.grade;
};
17.3 class继承(新的关键字class从ES6开始正式被引入到JavaScript中。目的是让定义类更简单。)
注意:现在用还早了点,因为不是所有的主流浏览器都支持ES6的class。
如果要现在就用上,就需要一个工具把class代码转换为传统的prototype代码,可以试试Babel这个工具。
用新的class关键字来编写构造函数Student:
class Student {
constructor(name){
this.name = name;
}
hello(){ //无function关键字
console.log('Hello, ' + this.name + '!');
}
}
class继承,通过extends来实现:
class PrimaryStudent extends Student {
constructor(name, grade){
super(name); //记得用super调用父类的构造方法;
this.grade = grade;
}
myGrade(){
console.log('I am at grade ' + this.grade);
}
}
18、浏览器 browser
18.1 window (不仅充当全局作用域,且表示浏览器窗口)
innerWidth和innerHeight属性:获取浏览器窗口的内部宽度和高度。
内部宽高是指除去菜单栏、工具栏、边框等占位元素后,用于显示网页的净宽高。
兼容性:IE<=8不支持。
兼容代码: var width = window.innerWidth || document.body.clientWidth;
outerWidth和outerHeight属性:获取浏览器窗口的整个宽高。
18.2 navigator(表示浏览器的信息)
navigator.appName:浏览器名称;
navigator.appVersion:浏览器版本;
navigator.language:浏览器设置的语言;
navigator.platform:操作系统类型;
navigator.userAgent:浏览器设定的User-Agent字符串
注意:navigator的信息可以很容易地被用户修改。
18.3 screen (表示屏幕信息)
screen.width:屏幕宽度,以像素为单位;
screen.height:屏幕高度,以像素为单位;
screen.colorDepth:返回颜色位数,如8、16、24
18.4 location(表示当前页面的URL信息)
一个完整的URL:http://www.example.com:8080/path/index.html?a=1&b=2#TOP
可以用location.href获取。也可以获取URL各部分的值:
location.protocol; // 'http'
location.host; // 'www.example.com'
location.port; // '8080'
location.pathname; // '/path/index.html'
location.search; // '?a=1&b=2'
location.hash; // 'TOP'
加载一个新页面,可以调用location.assign(url)。
重新加载当前页面,调用location.reload()。
18.5 document (表示当前页面,document对象就是整个DOM树的根节点。)
cookie属性,可以获取当前页面的Cookie。
Cookie是由服务器发送的key-value标示符。因为HTTP协议是无状态的,但是服务器要区分到底是哪个用
户发过来的请求,就可以用Cookie来区分。当一个用户成功登录后,服务器发送一个Cookie给浏览器,例
如user=ABC123XYZ(加密的字符串)...,此后,浏览器访问该网站时,会在请求头附上这个Cookie,服务器
根据Cookie即可区分出用户。
注意:Cookie中含有用户的登录信息,造成安全隐患,为了确保安全,服务器端在设置Cookie时,
应该始终坚持使用httpOnly。
18.6 history (保存了浏览器的历史记录)
任何情况,你都不应该使用history这个对象了!
18.7 操作DOM
querySelector()和querySelectorAll(),无法查找带伪类状态的元素。
前者返回单个element,后者返回Array。
兼容性:IE<8不支持,IE8部分支持。
更新DOM
innerHTML和innerText或textContent属性
前者可以设置HTML标签,后者innerText不返回隐藏元素的文本,textContent返回所有文本
兼容性:IE<9不支持textContent
插入DOM
appendChild: 把一个子节点添加到父节点的最后一个子节点
parent.appendChild(child); //返回插入节点child的引用
insertBefore: 子节点插入到指定的位置
parent.insertBefore(newElement,referenceElement); //返回插入节点newElement的引用
删除DOM
removeChild: 删除一个子节点
parent.removeChild(child); //返回删除的节点
注意:父节点的children属性是一个只读属性,并且它在子节点变化时会实时更新。
删除节点时,要注意children属性时刻都在变化。
18.8 操作表单
HTML表单的输入控件主要有:
文本框,对应的<input type="text">,用于输入文本;
口令框,对应的<input type="password">,用于输入口令;
单选框,对应的<input type="radio">,用于选择一项;
复选框,对应的<input type="checkbox">,用于选择多项;
下拉框,对应的<select>,用于选择一项;
隐藏文本,对应的<input type="hidden">,用户不可见,但表单提交时会把隐藏文本发送到服务器。
H5新增标准控件:date、datetime、datetime-local、color等
提交表单
方式一:通过<form>元素的submit()方法 //缺点是扰乱了浏览器对form的正常提交
方式二:响应<form>本身的onsubmit事件,在提交form时作修改:
例:
<!-- HTML -->
<form id="test-form" onsubmit="return checkForm()">
<input type="text" name="test">
<button type="submit">Submit</button>
</form>
<script>
function checkForm() {
var form = document.getElementById('test-form');
// 可以在此修改form的input...
// 继续下一步:
return true;
}
</script>
注意:要return true来告诉浏览器继续提交,如果return false,浏览器将不会继续提交form,
这种情况通常对应用户输入有误,提示用户错误信息后终止提交form。
在检查和修改<input>时,要充分利用<input type="hidden">来传递数据。
没有name属性的<input>的数据不会被提交。
18.9 操作文件
在HTML表单中,可以上传文件的唯一控件就是<input type="file">
注意:当一个表单包含<input type="file">时,表单的enctype必须指定为multipart/form-data,
method必须指定为post,浏览器才能正确编码并以multipart/form-data格式发送表单的数据。
H5
HTML5的File API提供了File和FileReader两个主要对象,可以获得文件信息并读取文件!
回调
在JavaScript中,浏览器的JavaScript执行引擎在执行JavaScript代码时,总是以单线程模式执行。
在JavaScript中,执行多任务实际上都是异步调用,发起异步操作,利用回调函数完成任务。
18.10 AJAX
18.11 Promise
18.12 Canvas
19、jQuery
优势:消除浏览器差异;简洁的操作DOM的方法;轻松实现动画、修改CSS等各种操作
版本:1.X --> 支持IE6、7、8; 2.X --> 代码更精简
使用方式:在页面<head>引入jQuery文件
$符号:本质上是一个函数,也是对象,如果$被占用,调用jQuery.noConflict()还原变量。
19.1 选择器
注意:返回的是jQuery对象,类似数组,每个元素都是一个引用了DOM节点的对象。
jQuery对象和DOM对象相互转化:
var div = $('#abd'); //div为jQuery对象
var divDOM = div.get(0); //获取div类数组中的第一个DOM元素,divDOM为DOM对象
var another = $(divDOM); //重新把divDOM包装成jQuery对象。annther为jQuery对象
按ID查询:$('#id')
按tag查询:$('tagName')
按class查询:$('.className')
按属性查找:$('[atrName=value]')
组合查询:逻辑与 --> $('.red.green') //注意没有空格
逻辑或 --> $('.red,.green') //多个选择器用,组合起来
模糊匹配 ^,$,!......
多项组合 $('input[name=email]') //匹配<input name="email">
层级选择器:Descendant Selector --> $('ancestor descendant')
子选择器:Child Selector --> $('parent>child')
过滤器:Filter --> 一般不单独使用,附加在其他选择器上
$('ul.lang li:first-child');
$('ul.lang li:last-child');
$('ul.lang li:nth-child(n)'); //选出第n个元素,注意:n从1开始!!!
$('ul.lang li:nth-child(even)'); //选出子元素序号为偶数的元素
$('ul.lang li:nth-child(odd)'); //选出子元素序号为奇数的元素
表单相关:
:input:可以选择<input>,<textarea>,<select>和<button>;
:file:可以选择<input type="file">,和input[type=file]一样;
:checkbox:可以选择复选框,和input[type=checkbox]一样;
:radio:可以选择单选框,和input[type=radio]一样;
:focus:可以选择当前输入焦点的元素,例如把光标放到一个<input>上,
用$('input:focus')就可以选出;
:checked:选择当前勾上的单选框和复选框,用这个选择器可以立刻获得用户选择的项目,
如$('input[type=radio]:checked');
:enabled:可以选择可以正常输入的<input>、<select>等,
也就是没有灰掉的输入;
:disabled:和:enabled正好相反,选择那些不能输入的。
其他:
$('div:visible'); // 所有可见的div
$('div:hidden'); // 所有隐藏的div
19.2 查找和过滤
不同层级查找:在某个节点的所有子节点中查找,$(selector).find()
在当前节点开始向上查找,$(selector).parent()
同一层级查找:向下查找,$(selector).next()
向上查找,$(selector).prev()
过滤:filter()方法可以过滤掉不符合选择器条件的节点
mar()方法把一个jQuery对象包含的若干DOM节点转化为其他对象
first()、last()、slice()用于处理jQuery对象包含的多余DOM节点。
19.3 操作DOM
修改Text和HTML:text()和html() //无参数调用是获取文本或HTML,传入参数就变成设置文本或HTML
注意:即使选择器没有返回任何DOM节点,调用jQuery对象的方法仍然不会报错。
修改CSS:css('name','value') //name可以用'background-color'和'backgroundColor'两种格式。
hasClass('name') //返回Boolean值,class是否包含name
addClass('name')和removeClass('name') //添加和删除Class
注意:几乎jQuery对象的所有方法都返回一个jQuery对象(可能是新的也可能是自身),
这样我们可以进行链式调用,非常方便。
显示和隐藏DOM:show()和hide() //无参数调用,只影响DOM节点的显示
修改DOM信息:$(selector).width()、$(selector).height()等 //无参数调用为获取,参数则为设置
操作节点属性:attr('name') //存在返回value,不存在返回undefined
removeAttr('name') //删除属性
prop()与attr()类似,不过prop()对checked和selector属性的处理更合理;
不过用is()方法判断更好!
操作表单:val() //无参数调用为获取,参数则为设置
19.4 修改DOM结构
添加DOM:暴力插入 --> html()
子节点插入 --> append()添加到最后;prepend()添加到最前
同级节点 --> after();before()
删除节点;remove()
19.5 事件event
JavaScript在浏览器中以单线程模式运行
鼠标事件:
click: 鼠标单击时触发;
dblclick:鼠标双击时触发;
mouseenter:鼠标进入时触发;
mouseleave:鼠标移出时触发;
mousemove:鼠标在DOM内部移动时触发;
hover:鼠标进入和退出时触发两个函数。
键盘事件:仅作用在当前焦点的DOM上,通常是<input>和<textarea>。
keydown:键盘按下时触发;
keyup:键盘松开时触发;
keypress:按一次键后触发。
其他事件:
focus:当DOM获得焦点时触发;
blur:当DOM失去焦点时触发;
change:当<input>、<select>或<textarea>的内容改变时触发;
submit:当<form>提交时触发;
ready:当页面被载入并且DOM树完成初始化后触发,仅作用于document对象。
例:ready事件的简化写法
$(document).on('ready',function(){...}); ==> $(document)..ready(function(){...}); ==>
$(function(){...});
事件参数:
所有事件都会传入Event对象作为参数
event.pageX:鼠标当前的X坐标;
event.pageY:鼠标当前的Y坐标;
event.which:鼠标左键返回1,中键返回2,右键返回3;
IE8 及其更早版本不支持 which 属性。不支持的浏览器可使用 keyCode 属性
兼容代码:var x = event.which || event.keyCode;
event.type:事件类型;
event.target:触发事件的DOM元素;
等等
取消绑定:
$(selector).off(events[,selector][handler]));
注意对匿名函数的解绑!
事件触发条件:
注意:事件的触发总是由用户操作引发的。
如果用JavaScript代码去改动文本框的值,将不会触发change事件;
代码触发change,可以直接调用无参数的change()方法!相对于.trigger('change')。
浏览器安全限制:
在浏览器中,有些JavaScript代码只有在用户触发下才能执行。如:window.open()函数。
19.6 动画animate
show/hide 与 toggle([duration][,easing][,complete]) //显示和隐藏DOM(从左上角)
slideUp/slideDown 与 slideToggle([duration][,easing][,complete])
//显示和隐藏DOM(从上边放下卷起)
fadeIn/fadeOut 与 fadeToggle([duration][,easing][,complete])
//淡入淡出
自定义动画:animate(peoperties[duration][,easing][,complete])
串行动画:jQuery的动画效果还可以串行执行,通过delay()方法还可以实现暂停。
注意:jQuery也没有实现对background-color的动画效果,用animate()设置background-color也没有
效果。这种情况下可以使用CSS3的transition实现动画效果。
19.7 AJAX
jQuery.ajax(url[,settings])
常用的选项有:
async:是否异步执行AJAX请求,默认为true,千万不要指定为false;
method:发送的Method,缺省为'GET',可指定为'POST'、'PUT'等;
contentType:发送POST请求的格式,默认值为
'application/x-www-form-urlencoded; charset=UTF-8',也可以指定为
text/plain、application/json;
data:发送的数据,可以是字符串、数组或object。如果是GET请求,data将被转换
成query附加到URL上,如果是POST请求,根据contentType把data序列化成合适的格式;
headers:发送的额外的HTTP头,必须是一个object;
dataType:接收的数据格式,可以指定为'html'、'xml'、'json'、'text'等,缺省情况下
根据响应的Content-Type猜测。
注意:jQuery的jqXHR对象类似一个Promise对象,我们可以用链式写法来处理各种回调。
get() 例:查询
var jqxhr = $.get('/path/to/resource', {
name: 'Bob Lee',
check: 1
});
第二个参数如果是object,jQuery自动把它变成query string然后加到URL后面,实际的URL是:
/path/to/resource?name=Bob%20Lee&check=1
post() 例:修改
var jqxhr = $.post('/path/to/resource', {
name: 'Bob Lee',
check: 1
});
传入的第二个参数默认被序列化为application/x-www-form-urlencoded,实际构造的数据
name=Bob%20Lee&check=1作为POST的body被发送。
getJSON() 例:
var jqxhr = $.getJSON('/path/to/resource', {
name: 'Bob Lee',
check: 1
}).done(function (data) {
// data已经被解析为JSON对象了
});
安全限制:如果需要使用JSONP,可以在ajax()中设置jsonp: 'callback',让jQuery实现JSONP跨域加载数据。
19.8 扩展
编写jQuery插件:给jQuery对象绑定一个新方法是通过扩展$.fn对象实现的。
例:编写一个高亮色插件highlight1();
$.fn.highlight = function (options) {
// 合并默认值和用户设定值:
var opts = $.extend({}, $.fn.highlight.defaults, options);
this.css('backgroundColor', opts.backgroundColor).css('color', opts.color);
return this;
}
// 设定默认值:
$.fn.highlight.defaults = {
color: '#d85030',
backgroundColor: '#fff8de'
}