JavaScript基础篇
# 1. js输出方式
- document.write 向body中写字符串
- console.log 向控制台输出
- alert 弹出警告框输出
# 2. js编写位置
1.外联文件
<script src="引入的文件位置"></script>
2.内联文件
<script type="text/javascript">
js代码编写的位置
</script>
2
3
3.内嵌代码(结构与行为耦合,不使用)
<input type="button" onclick="alert('弹出')"></input>
<a href="javascript:alert('弹出');"></a>
2
可以将js代码编写到外部js文件中,然后通过script标签引入。写到外部文件中可以在不同的页面中同时使用,而且可以利用到浏览器的缓存机制,这是推荐的使用方式。
注意:script标签一旦用于引入外部文件了,该标签内部就不能再用于编写代码了,即使写了浏览器也会忽略。
# 3. js基本语法
js中严格区分大小写
js中每一条语句以分号";"结尾
-如果不写分号,浏览器会自动添加,但会相应地小号一些系统资源
-而且有时候浏览器会加错分号,所以开发中必须写分号
js会忽略多个空格或换行
# 4. 字面量和变量
字面量,即常量,是一些不可改变的值
变量,变量可以用来保存字面量,而且变量值可以任意改变。
在js中使用var关键字声明变量。
# 5. 标识符
所有可以自定义的变量都叫做标识符,并且遵循以下规范:
1.只能以字母数字,下划线,$构成 2.不能以数字开头 3.不能使用ES的关键字和保留字 4.一般使用驼峰命名法,首字母小写,其他单词开头字母大写,其余字母小写
js底层保存标识符时以unicode编码表示,因此可使用UTF-8的所有内容,但是一般只使用英文,不建议使用中文做标识符
# 6. js基本数据类型
数据类型指的就是字面量的类型,js中一共有6种数据类型,即
- String 字符串
- Number 数值
- Boolean 布尔值
- Null 空值
- Undefined 未定义
- Object 对象
其中String、Number、Boolean、Null、Undefined属于基本数据类型,而Object属于引用数据类型
# 6.1 String
- 在js中字符串需要使用引号括起来
- 使用单引号或者双引号都可以,但不要混着用。
- 引号不能嵌套,双引号里不能再有双引号,单引号里不能再有单引号,除非用\表示转义
如\"表示",\'表示',\n表示换行,\t表示制表符等
# 6.2 Number
(1)在js中所有的数值都是Number类型,包括整数和浮点数(小数)
(2)运算符typeof,可以用来检查一个变量的类型,语法:typeof 变量
- 检查字符串时,会返回String
- 检查数值时,会返回Number
(3)js中可以表示的数字最大值和最小值分别是Number.MAX_VALUE(1.7976931348623157e+308)
和-Number.MAX_VALUE,若使用的数字超出了Number.MAX_VALUE,则会返回Infinity,一个特殊的数值字面量
- Infinity表示正无穷
- -Infinity表示负无穷
- 使用typeof检查Infinity也会返回Number
(4)Number.MIN_VALUE(5e-234)表示大于0的最小值
(5)NaN也是一个特殊的数值字面量,表示Not A Number,使用typeof检查NaN也会返回Number
(6)js中整数运算基本能保持精确,但不能超过-Number.MAX_VALUE到Number.MAX_VALUE的范围,而2进制浮点数以 分数表示,不准确,所以不要拿js做精确度要求较高的浮点计算
# 6.3 Boolean
只有两个值:true false,主要用来做逻辑判断,使用typeof检查一个布尔值时会返回boolean,但注意用typeof检查字符串"true"和"false"时只会返回string
# 6.4 Null
- Null(空值)类型的值只有一个,就是null
- null这个值专门用来表示一个为空的对象
- 使用typeof检查一个null值时,会返回object
# 6.5 Undefined
- Undefined(未定义)类型的值只有一个,就undefind
- 当声明一个变量,但是并不给变量赋值时,它的值就是undefined
- 使用typeof检查一个undefined时也会返回undefined
# 7. 强制类型转换
指将一个数据类型强制转换为其他的数据类型
类型转换主要指,将其他的数据类型,转换为String或Number或Boolean
# 7.1 将其他的数据类型转换为String
方式一:
- 调用被转换数据类型的变量的**toString()**方法,该方法不会影响到原变量,它会将转换的结果返回
- 对于Number调用toString()时可以在该方法中传递一个整数作为参数,此时它将会把数字转换为指定的进制,如果不指定则默认转换为10进制
但注意:null和undefined这两个值没有toString()方法,如果调用他们的toString方法,会报错
方式二:
- 调用String()函数,并将被转换的数据作为参数传递给函数
- 使用String()函数做强制类型转换时,对于Number和Boolean实际上就是调用的toString()方法,但是对于null和undefined,就不会调用toString()方法,它会将 null 直接转换为 "null",将 undefined 直接转换为 "undefined"
# 7.2 将其他的数据类型转换为Number
方式一:
使用Number()函数
1.字符串 --> 数字
(1)如果是纯数字的字符串,则直接将其转换为数字
(2)如果字符串中有非数字的内容,则转换为NaN
(3)如果字符串是一个空串或者是一个全是空格的字符串,则转换为0
2.布尔 --> 数字
(1)true 转成数值1
(2)false 转成 0
3.null --> 数字
- 转成数值0
4.undefined --> 数字
- 转成数值NaN
方式二:
这种方式专门用来对付字符串
- parseInt() 将一个字符串中有效的整数内容取出来,然后转换为Number类型的数值
- parseFloat() 将一个字符串中有效的小数内容取出来,然后转换为Number类型的数值
- 如果对非String变量使用parseInt()或parseFloat(),它会先将其转换为String类型然后再操作
# 7.3 将其他的数据类型转换为Boolean
使用Boolean()函数
(1)数字 ---> 布尔
- 0和NaN会被转为false,其余的都是true
(2)字符串---> 布尔
- 除了空串,其余的都会转为true
(3)null和undefined都会转换为false
- 注意null和undefined都是字面量,不是类型Null和Undefined
(4)对象也会转换为true
- 注意这里说的对象都是实例,不是类型object
# 8. 其他进制的数字
(1)16进制在数字前加0x
(2)8进制在数字前加0 在某些浏览器中键入以下代码:
var a = "070";
console.log(parseInt(a));
2
结果会输出56。因为浏览器将其当做8进制,解决方法是输入第二个参数,强制指定数字的进制
parseInt(a, 10);
(3)2进制在数字前加0b 某些浏览器无法解析2进制如IE浏览器,同时这个方式也不常用
# 9. 运算符
运算符也叫操作符,通过运算符可以对一个或多个值进行运算,并获取运算结果
比如typeof就是运算符,可以来获得一个值的类型,它会将该值的类型以字符串的形式返回
- number string boolean undefined object
算术运算符
- 当对非Number类型的值进行运算时,会将这些值转换为Number然后再运算
- 任何值和NaN做运算都得NaN
运算符+
- 可以对两个值进行加法运算,并将结果返回
- 如果对两个字符串进行加法运算,则会做拼串,会将两个字符串拼接为一个字符串,并返回
- 任何的值和字符串做加法运算,都会先转换为字符串,然后再和字符串做拼串的操作
运算符-
- 可以对两个值进行减法运算,并将结果返回
运算符*
- 可以对两个值进行乘法运算
运算符/
- 可以对两个值进行除法运算
运算符%
- 取模运算(取余数)
一些使用技巧:
任何值和字符串相加都会转换为字符串,并做拼串操作
我们可以利用这一特点,来将一个任意的数据类型转换为String
我们只需要为任意的数据类型 + 一个 "" 即可将其转换为String
这是一种隐式的类型转换,由浏览器自动完成,实际上它也是调用String()函数
var c = 123; c = c + "";
1
2
2.任何值做**- 或* 或/**运算时都会自动转换为Number
我们可以利用这一特点做隐式的类型转换
可以通过为一个值 -0或 *1 或/1来将其转换为Number
原理和Number()函数一样,使用起来更加简单
# 10. 一元运算符
一元运算符,只需要一个操作数
正号
- 正号不会对数字产生任何影响
负号
- 负号可以对数字进行负号的取反
一些使用技巧:
- 对于非Number类型的值,一元运算符会将先其转换为Number,然后再运算
- 可以对一个其他的数据类型使用+,来将其转换为number,它的原理和Number()函数一样
# 11. 自增和自减
(1)自增 ++
- 通过自增可以使变量在自身的基础上增加1
- 对于一个变量自增以后,原变量的值会立即自增1
自增分成两种:后++(a++) 和 前++(++a)
- 无论是a++ 还是 ++a,都会立即使原变量的值自增1
- 不同的是a++ 和 ++a这两个表达式的值不同
- a++的值等于变量原来的值(自增前的值)
- ++a的值等于新值 (自增后的值)
(2)自减 --
- 通过自减可以使变量在自身的基础上减1
自减分成两种:后--(a--) 和 前--(--a)
- 无论是a-- 还是 --a,都会立即使原变量的值自减1
- 不同的是a-- 和 --a这两个表达式的值不同
- a--的值等于变量原来的值(自减前的值)
- --a的值等于新值 (自减后的值)
# 12. 逻辑运算符
(1)! 非运算符
!可以用来对一个值进行非运算
- 所谓非运算就是对一个布尔值进行取反操作,true变false,false变true
- 如果对一个值进行两次取反,它不会变化
- 如果对非布尔值进行非运算,则会将其转换为布尔值
(2)&&与运算符
&&可以对符号两侧的值进行与运算并返回结果
运算规则
- 两个值中只要有一个值为false就返回false,
- 只有两个值都为true时,才会返回true
- JS中的“与”属于短路的与,如果第一个值为false,则不会检查第二个值
(3)|| 或运算符
||可以对符号两侧的值进行或运算并返回结果
运算规则:
- 两个值中只要有一个true,就返回true
- 如果两个值都为false,才返回false
- JS中的“或”属于短路的或,如果第一个值为true,则不会检查第二个值
注:js中的短路即当一个值满足要求时才会继续执行第二个操作,第一个值不满足要求时不执行第二个操作
# 13. 非布尔值的与或非运算
(1)如果对非布尔值进行非运算,则最终会将其转换为布尔值
- 所以我们可以利用该特点,来将一个其他的数据类型转换为布尔值,可以为一个任意数据类型取两次反,来将其转换为布尔值,原理和Boolean()函数一样
(2)对于非布尔值进行与或运算时,会先将其转换为布尔值,然后再运算,并且最终返回原值
- 与运算
①如果第一个值为true,则必然返回第二个值
②如果第一个值为false,则直接返回第一个值
2.或运算
①如果第一个值为true,则直接返回第一个值
②如果第一个值为false,则返回第二个值
//false && true
result = 0 && 2;
result = 2 && 0;
//false && false
result = NaN && 0;
result = 0 && NaN;
//true || true
//如果第一个值为true,则直接返回第一个值
result = 2 || 1;
result = 2 || NaN;
result = 2 || 0;
//如果第一个值为false,则直接返回第二个值
result = NaN || 1;
result = NaN || 0;
result = "" || "hello";
result = -1 || "你好";
console.log("result = "+result);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 14. 赋值运算符
有以下几种:=,+=,-=,/=,*=,%=
=运算符可以将符号右侧的值赋值给符号左侧的变量,而以下两行代码
var a += 3;
var a = a + 3;
2
两者等价,对于其他的-=,/=,*=,%=,则与+=的规则相同
# 15. 关系运算符
> 大于号运算符
- 判断符号左侧的值是否大于右侧的值,如果关系成立,返回true,如果关系不成立则返回false
>= 大于等于号运算符
- 判断符号左侧的值是否大于或等于右侧的值
< 小于号
<= 小于等于
非数值的情况
- 对于非数值进行比较时,会将其转换为数字然后在比较
- 如果符号两侧的值都是字符串时,不会将其转换为数字进行比较,而会分别比较字符串中字符的Unicode编码
- 任何值和NaN做任何比较都是false
var result = 5 > 10;//false
result = 5 > 4; //true
result = 5 > 5; //false
result = 5 >= 5; //true
result = 5 >= 4; //true
result = 5 < 4; //false
result = 4 <= 4; //true
//console.log("result = "+result);
//console.log(1 > true); //false
//console.log(1 >= true); //true
//console.log(1 > "0"); //true
//console.log(10 > null); //true
//任何值和NaN做任何比较都是false
//console.log(10 <= "hello"); //false
//console.log(true > false); //true
//console.log("1" < "5"); //true
//console.log("11" < "5"); //true
//比较两个字符串时,比较的是字符串的字符编码
//console.log("a" < "b");//true
//比较字符编码时是一位一位进行比较
//如果两位一样,则比较下一位,所以借用它来对英文进行排序
//console.log("abc" < "bcd");//true
//比较中文时没有意义
//console.log("戒" > "我"); //true
//如果比较的两个字符串型的数字,可能会得到不可预期的结果
//注意:在比较两个字符串型的数字时,一定一定一定要转型
console.log("11123123123123123123" < +"5"); //true
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
# 16. 编码
在字符串中使用转义字符输入Unicode编码
\u四位编码,这里的编码需要的是16进制,例:
console**.**log("\u2620");
在网页中使用Unicode编码
&#编码; 这里的编码需要把Unicode编码转换成10进制数字,例:
<h1 style="font-size: 200px;">☠</h1>
<h1 style="font-size: 200px;">⚀</h1>
2
3
# 17. 相等运算符
==相等运算
- 当使用==来比较两个值时,如果值的类型不同,则会自动进行类型转换,将其转换为相同的类型,然后再比较
!=不相等运算
- 不相等运算用来判断两个值是否不相等,如果不相等返回true,否则返回false
- 不相等运算也会对变量进行自动的类型转换,如果转换后相等它也会返回false
===全等运算
- 用来判断两个值是否全等,它和相等类似,不同的是它不会做自动的类型转换
- 如果两个值的类型不同,直接返回false
!==不全等运算
- 用来判断两个值是否不全等,和不等类似,不同的是它不会做自动的类型转换
- 如果两个值的类型不同,直接返回true
//console.log(1 == 1); //true
var a = 10;
//console.log(a == 4); //false
//console.log("1" == 1); //true
//console.log(true == "1"); //true
//console.log(null == 0); //false
/*
* undefined 衍生自 null
* 所以这两个值做相等判断时,会返回true
*/
//console.log(undefined == null);
/*
* NaN不和任何值相等,包括他本身
*/
//console.log(NaN == NaN); //false
var b = NaN;
//判断b的值是否是NaN
//console.log(b == NaN);
/*
* 可以通过isNaN()函数来判断一个值是否是NaN
* 如果该值是NaN则返回true,否则返回false
*/
//console.log(isNaN(b));
//console.log(10 != 5); //true
//console.log(10 != 10); //false
//console.log("abcd" != "abcd"); //false
//console.log("1" != 1);//false
//console.log("123" === 123);//false
//console.log(null === undefined);//false
console.log(1 !== "1"); //true
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
# 18. 条件(三元)运算符
条件运算符也叫三元运算符
语法:表达式?语句1:语句2;
执行的流程:
1. 条件运算符在执行时,首先对条件表达式进行求值,如果该值为true,则执行语句1,并返回执行结果如果该值为false,则执行语句2,并返回执行结果
2. 如果条件的表达式的求值结果是一个非布尔值,会将其转换为布尔值然后再运算
# 19. 运算符的优先级
(1)","运算符
使用,可以分割多个语句,一般可以在声明多个变量时使用
//使用,运算符同时声明多个变量
//var a , b , c;
//可以同时声明多个变量并赋值
//var a=1 , b=2 , c=3;
//alert(b);
2
3
4
5
6
(2)js运算符优先级
在js中运算符也有优先级,比如:先乘除后加减
- 在js中有一个运算符优先级的表,在表中越靠上优先级越高,优先级越高越优先计算, 样,则从左往右计算
- 但是这个表我们并不需要记忆,如果遇到优先级不清楚,可以使用()来改变优先级
# 20. 代码块
- 我们的程序是由一条一条语句构成的,语句是按照自上向下的顺序一条一条执行的
- 在js中使用大括号{}来为语句进行分组,同一个{}中的语句我们称为是一组语句,它们要么都执行,要么都不执行
- 一个{}中的语句我们也称为叫一个代码块,在代码块的后边就不用再编写;了
- js中的代码块,只具有分组的作用,没有其他的用途
- 代码块的内容,在外部是完全可见的
# 21. 语句
js程序是从上到下一行一行执行的,通过流程控制语句可以控制程序执行流程,使程序可以根据一定的条件来选择执行
语句的分类:
- 条件判断语句
- 条件分支语句
- 循环语句
# 21.1 条件判断语句(if else)
使用条件判断语句可以在执行某个语句之前进行判断,如果条件成立才会执行语句,条件不成立则语句不执行
if语句
(1)语法1:若满足条件则只执行紧接着的第一条语句,后面语句与判断语句无关
if(表达式)
语句1;
2
(2)语法2:满足条件执行代码块中的代码,代码块外的代码与判断语句无关
if(表达式){
语句1;
语句2;
}
2
3
4
(3)语法3:满足条件执行前一个代码块中的代码,否则执行后一个代码块中的代码
if(表达式){
语句...
}else{
语句...
}
2
3
4
5
(4)语法4:从上到下依次判断,当满足一个表达式后后面的代码不再执行
if(表达式){
语句...
}else if{
语句...
}else if{
语句...
}else{
语句...
}
2
3
4
5
6
7
8
9
(5)语法5:条件判断语句可以嵌套
if(表达式){
语句...
}else{
语句...
if(表达式){
语句...
}
}
2
3
4
5
6
7
8
# 21.2 条件分支语句(switch)
条件分支语句也叫switch语句
(1)语法
switch(条件表达式){
case 表达式:
语句...
break;
case 表达式:
语句...
break;
default:
语句...
break;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
(2)执行流程
switch...case..语句
- 在执行时会依次将case后的表达式的值和switch后的条件表达式的值进行全等比较,如果比较结果为true,则从当前case处开始执行代码。
- 当前case后的所有的代码都会执行,我们可以在case的后边跟着一个break关键字,这样可以确保只会执行当前case后的语句,而不会执行其他的case
- 如果比较结果为false,则继续向下比较
- 如果所有的比较结果都为false,则只执行default后的语句
# 21.3 循环语句(for while do...while)
通过循环语句可以反复的执行一段代码多次
(1)while
语法:
while(条件表达式){
语句...
}
2
3
执行流程:
先对条件表达式进行求值判断,如果值为true,则执行循环体。循环体执行完毕以后,继续对表达式进行判断如果为true,则继续执行循环体,以此类推。如果值为false,则终止循环。
(2)do...while
语法:
do{
语句...
}while(条件表达式)
2
3
执行流程:
do...while语句在执行时,会先执行循环体,循环体执行完毕以后,在对while后的条件表达式进行判断,
如果结果为true,则继续执行循环体,执行完毕继续判断以此类推,如果结果为false,则终止循环
不同点:
上述这两个语句功能类似,不同的是while是先判断后执行,而do...while会先执行后判断,do...while可以保证循环体至少执行一次,而while不能。
(3)for
for循环中,为我们提供了专门的位置用来放三个表达式:
- 初始化表达式
- 条件表达式
- 更新表达式
语法:
for(①初始化表达式;②条件表达式;④更新表达式){
③语句...
}
2
3
执行流程:
- ①执行初始化表达式,初始化变量(初始化表达式只会执行一次)
- ②执行条件表达式,判断是否执行循环。
- 如果为true,则执行循环③,如果为false,终止循环
- ④执行更新表达式,更新表达式执行完毕继续重复②
# 22. break和continue
(1)break关键字
- break关键字可以用来退出switch或循环语句
- break关键字,会立即终止离它最近的那个循环语句
(2)continue关键字
- continue关键字可以用来跳过当次循环
- 同样continue也是默认只会对离它最近的那个循环语句起作用
(3)一些使用技巧
- 不能在if语句中使用break和continue,除非该if语句被嵌套在循环语句内
- 可以为循环语句创建一个label,来标识当前的循环。使用break语句时,可以在break后跟着一个label,这样break将会结束指定的循环,而不是最近的那层循环。
outer:
for(var i=0 ; i<5 ; i++){
console.log("@外层循环"+i)
for(var j=0 ; j<5; j++){
break outer;
console.log("内层循环:"+j);
}
}
2
3
4
5
6
7
8
# 23. 对象
基本数据类型都是单一的值如"hello"、123、true等,值和值之间没有任何的联系。如果使用基本数据类型的数据,我们所创建的变量都是独立,不能成为一个整体。
而对象属于一种复合的数据类型,在对象中可以保存多个不同数据类型的属性。
# 23.1 对象的分类
1.内建对象 由ES标准中定义的对象,在任何的ES的实现中都可以使用
比如:Math String Number Boolean Function Object....
2.宿主对象
由JS的运行环境提供的对象,目前来讲主要指由浏览器提供的对象
比如 BOM DOM
3.自定义对象
由开发人员自己创建的对象
# 23.2 创建对象
- 使用new关键字调用的函数,是构造函数constructor
- 构造函数是专门用来创建对象的函数
- 使用typeof检查一个对象时,会返回object
# 23.3 属性
在对象中保存的值称为属性
(1)向对象添加属性
语法:对象.属性名 = 属性值; |
---|
//向obj中添加一个name属性
obj.name = "孙悟空";
//向obj中添加一个gender属性
obj.gender = "男";
//向obj中添加一个age属性
obj.age = 18;
2
3
4
5
6
(2)读取对象中的属性
语法:对象.属性名 |
---|
注:如果读取对象中没有的属性,不会报错而是会返回undefined
(3)修改对象的属性值
语法:对象.属性名 = 新值 |
---|
(4)删除对象的属性
语法:delete 对象.属性名 |
---|
delete obj.name;
# 24. 属性名和属性值规范
(1)属性名规范
向对象中添加属性时,添加的属性名不强制要求遵守标识符的规范,但最好还是尽量按标识符的规范命名。
如果要使用特殊的属性名,不能采用.的方式来操作,需要使用另一种方式:
语法:对象["属性名"] = 属性值 |
---|
读取时也需要采用这种方式,因为使用[]这种形式去操作属性,更加的灵活,在[]中可以直接传递一个变量,这样变量值是多少就会读取那个属性
(2)属性值规范
js对象的属性值,可以是任意的数据类型,甚至也可以是一个对象
obj.test = true;
obj.test = null;
obj.test = undefined;
//创建一个对象
var obj2 = new Object();
obj2.name = "猪八戒";
//将obj2设置为obj的属性
obj.test = obj2;
2
3
4
5
6
7
8
9
10
(3)in运算符
通过in运算符可以检查一个对象中是否含有指定的属性,如果有则返回true,没有则返回false
语法: "属性名" in 对象 |
---|
//检查obj中是否含有name属性
console.log("name" in obj);
2
# 25. 基本和引用数据类型比较
基本数据类型:String Number Boolean Null Undefined
引用数据类型:Object
- js中的变量都是保存到栈内存中的
- 基本数据类型的值直接在栈内存中存储,值与值之间独立存在,修改一个变量不会影响其他的变量
- 对象是保存到堆内存中的,每创建一个新的对象,就会在堆内存中开辟出一个新的空间,
- 而变量保存的是对象的内存地址(对象的引用),如果两个变量保存的是同一个对象引用,当一个通过一个变量修改属性时,另一个也会受到影响
- 当比较两个基本数据类型的值时,就是比较值。
- 而比较两个引用数据类型时,它是在比较对象的内存地址,如果两个对象是一模一样的,但是地址不同,它也会返回false。
console.log(obj3 == obj4);//false
# 26. 对象字面量
使用对象字面量,可以在创建对象时,直接指定对象中的属性
使用对象字面量来创建一个对象
var obj = {};
等同于:
var obj = new Object();
更具体的用法:
语法:{属性名:属性值,属性名:属性值....} |
---|
- 属性名可以加引号也可以不加,建议不加,如果要使用一些特殊的名字,则必须加引号
- 属性名和属性值是一组一组的键值对结构,用:连接,多个键值对之间使用","隔开
- 如果一个属性之后没有其他的属性了,就不要写","
例子:
var obj2 = {
name:"猪八戒",
age:13,
gender:"男",
test:{name:"沙僧"}
};
2
3
4
5
6
# 27. 函数
- 函数也是一个对象
- 函数中可以封装一些功能(代码),在需要时可以执行这些功能(代码)
- 函数中可以保存一些代码在需要的时候调用
- 使用typeof检查一个函数对象时,会返回function
(1)创建函数
方式一(构造函数)
我们在实际开发中很少使用构造函数来创建一个函数对象
//可以将要封装的代码以字符串的形式传递给构造函数
var fun = new Function("console.log('Hello 这是我的第一个函数');");
2
方式二(函数声明)
语法如下:
function 函数名([形参1,形参2...形参N]){
语句...
}
2
3
(2)调用函数
封装到函数中的代码不会立即执行,函数中的代码会在函数调用的时候按顺序执行
调用函数的语法:
函数对象()
# 28. 函数的参数
- 可以在函数的()中来指定一个或多个形参(形式参数)多个形参之间使用,隔开
- 声明形参就相当于在函数内部声明了对应的变量,但是并不赋值
- 在调用函数时,可以在()中指定实参(实际参数),实参可以是任何值,它将会被赋值给函数中对应的形参
- 当我们的参数过多时,可以将实际参数封装到一个对象中,然后通过对象传递
- 调用函数时解析器不会检查实参的类型,所以要注意,是否有可能会接收到非法的参数,如果有可能则需要对参数进行类型的检查,函数的实参可以是任意的数据类型
- 调用函数时,解析器也不会检查实参的数量,多余实参不会被用来赋值,如果实参的数量少于形参的数量,则没有对应实参的形参的值将是undefined
# 29. 函数的返回值
- 可以使用 return 关键字来设置函数的返回值,return后的值将会作为函数的执行结果返回,可以定义一个变量,来接收该结果
- 在函数中return后的语句都不会执行
- return语句后不跟任何值就相当于返回一个undefined,如果函数中不写return,则也会返回undefined
- return后可以跟任意类型的值,也可以是一个对象,也可以是一个函数
/*
* 定义一个函数,可以根据半径计算一个圆的面积,并返回计算结果
* 3.14*r*r
*/
function mianji(r){
return 3.14*r*r;
}
/*
* 实参可以是一个对象,也可以是一个函数
*/
function fun(a){
console.log("a = "+a);
}
/*
* mianji()
* - 调用函数
* - 相当于使用的函数的返回值
*
* mianji
* - 函数对象
* - 相当于直接使用函数对象
*/
fun(mianji(10));
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
# 30. 立即执行函数
函数定义完,立即被调用,这种函数叫做立即执行函数,立即执行函数往往只会执行一次
举例:
(function(a,b){
console.log("a = "+a);
console.log("b = "+b);
})(123,456);
2
3
4
# 31. 方法
- 函数也可以称为对象的属性,如果一个函数作为一个对象的属性保存,这个函数就被称作这个对象的方法
- 调用这个函数就说调用对象的方法(method),但是它只是名称上的区别没有其他的区别
//调方法
obj.sayName();
//调函数
fun();
2
3
4
# 32. 枚举对象中的属性(for...in)
语法:
for(var 变量 in 对象){
语句
}
2
3
for...in语句 对象中有几个属性,循环体就会执行几次,每次执行时,会将对象中的一个属性的名字赋值给变量
var obj = {
name:"孙悟空",
age:18,
gender:"男",
address:"花果山"
};
for(var n in obj){
console.log("属性名:"+n);
console.log("属性值:"+obj[n]);
}
2
3
4
5
6
7
8
9
10
11
# 33. 作用域
作用域指一个变量的作用的范围
js中一共有两种作用域,分别是全局作用域和函数作用域
(1)全局作用域
- 直接编写在script标签中的JS代码,都在全局作用域
- 全局作用域在页面打开时创建,在页面关闭时销毁
- 在全局作用域中有一个全局对象window,它代表的是一个浏览器的窗口,它由浏览器创建,我们可以直接使用
- 全局作用域中的变量都是全局变量,在页面的任意的部分都可以访问的到
在全局作用域中:
- 创建的变量都会作为window对象的属性保存
- 创建的函数都会作为window对象的方法保存
(2)函数作用域
- 调用函数时创建函数作用域,函数执行完毕以后,函数作用域销毁
- 每调用一次函数就会创建一个新的函数作用域,他们之间是互相独立的
- 在函数作用域中可以访问到全局作用域的变量,在全局作用域中无法访问到函数作用域的变量
- 当在函数作用域操作一个变量时,它会先在自身作用域中寻找,如果有就直接使用,如果没有则向上一级作用域中寻找,直到找到全局作用域,如果全局作用域中依然没有找到,则会报错ReferenceError
- 在函数中要访问全局变量可以使用window对象
- 在函数内部,不使用var声明的变量都会成为全局变量
# 34. 声明提前
(1)变量的声明提前
- 使用var关键字声明的变量,会在所有的代码执行之前被声明(但是不会赋值)
- 如果声明变量时不使用var关键字,则变量不会被声明提前
(2)函数的声明提前
- 使用函数声明形式创建的函数 function 函数(){},它会在所有的代码执行之前就被创建,所以我们可以在函数声明前来调用函数
- 使用函数表达式创建的函数,不会被声明提前,所以不能在声明前调用
//变量声明提前,会输出a=undefined
console.log("a = "+a);
var a = 123;
fun();
//函数声明,会被提前创建
function fun(){
console.log("我是一个fun函数");
}
//函数表达式,不会被提前创建
var fun2 = function(){
console.log("我是fun2函数");
};
fun2();
/*
* 在函数作用域也有声明提前的特性,
* 使用var关键字声明的变量,会在函数中所有的代码执行之前被声明
* 函数声明也会在函数中所有的代码执行之前执行
*/
function fun3(){
fun4();
console.log(a);
var a = 35;
function fun4(){
alert("I'm fun4");
}
}
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
# 35. this
解析器在调用函数每次都会向函数内部传递进一个隐含的参数,这个隐含的参数就是this,this指向的是一个对象,这个对象我们称为函数执行的上下文对象。
根据函数的调用方式的不同,this会指向不同的对象
- 以函数的形式调用时,this永远都是指向全局对象window
- 以方法的形式调用时,this就是指向调用方法的那个对象
- 以构造函数调用时,this就是指向新创建的对象
- 以call或apply方法调用时,this指向的是我们指定传入方法中的那个实参
- 箭头函数体内的
this
对象,就是定义该函数时所在的作用域指向的对象,而非使用时所在的作用域指向的对象
注:this
永远指向的是最后调用它的对象
//此时this指向的是window,因为this永远指向的是最后调用它的对象,虽然fn是对象b的方法,但是fn赋值给j时候并没有执行,所以最终指向window
var o = {
a:10,
b:{
a:12,
fn:function(){
console.log(this.a); //undefined
console.log(this); //window
}
}
}
var j = o.b.fn;
j();
2
3
4
5
6
7
8
9
10
11
12
13
# 36. 构造函数
- 构造函数就是一个普通的函数,创建方式和普通函数没有区别,不同的是构造函数习惯上首字母大写
- 构造函数和普通函数的区别就是调用方式的不同,普通函数是直接调用,而构造函数需要使用new关键字来调用
- 使用同一个构造函数创建的对象,我们称为一类对象,也将一个构造函数称为一个类
- 我们将通过一个构造函数创建的对象,称为是该类的实例
构造函数的执行流程:
- 立刻创建一个新的对象
- 将新建的对象设置为函数中this,在构造函数中可以使用this来引用新建的对象
- 逐行执行函数中的代码
- 将新建的对象作为返回值返回
# 36.1 instanceof
使用instanceof可以检查一个对象是否是一个类的实例,如果是,则返回true,否则返回false
语法:
对象 instanceof 构造函数
# 37. 原型对象prototype
- 我们所创建的每一个函数,解析器都会向函数中添加一个属性prototype,这个属性对应着一个对象,这个对象就是我们所谓的原型对象
- 如果函数作为普通函数调用prototype没有任何作用,当函数以构造函数的形式调用时,它所创建的对象中都会有一个隐含的属性,指向该构造函数的原型对象,我们可以通过__proto__来访问该属性
- 原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中(把原型对象想象成Java中的父类,实例和它类似于继承关系)。
- 当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用,如果没有则会去原型对象中寻找,如果找到则直接使用
- 以后我们创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数的原型对象中,这样不用分别为每一个对象添加,也不会影响到全局作用域,就可以使每个对象都具有这些属性和方法了
# 37.1 论证原型的必要性
/*
* 创建一个Person构造函数
* - 在Person构造函数中,为每一个对象都添加了一个sayName方法,
* 目前我们的方法是在构造函数内部创建的,
* 也就是构造函数每执行一次就会创建一个新的sayName方法
* 也是所有实例的sayName都是唯一的。
* 这样就导致了构造函数执行一次就会创建一个新的方法,
* 执行10000次就会创建10000个新的方法,而10000个方法都是一摸一样的
* 这是完全没有必要,完全可以使所有的对象共享同一个方法
*/
function Person(name , age , gender){
this.name = name;
this.age = age;
this.gender = gender;
//向对象中添加一个方法
//this.sayName = fun;
}
/*
* 将函数定义在全局作用域,污染了全局作用域的命名空间
* 而且定义在全局作用域中也很不安全
*/
/*
function fun(){
alert("Hello大家好,我是:"+this.name);
};
*/
//向原型中添加sayName方法
Person.prototype.sayName = function(){
alert("Hello大家好,我是:"+this.name);
};
//创建一个Person的实例
var per = new Person("孙悟空",18,"男");
var per2 = new Person("猪八戒",28,"男");
per.sayName();
per2.sayName();
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
# 37.2 检查对象属性的一些区别
- 使用in检查对象中是否含有某个属性时,如果对象中没有但是原型中有,也会返回true
- 可以使用对象的hasOwnProperty()来检查对象自身中是否含有该属性,使用该方法只有当对象自身中含有属性时,才会返回true
# 37.3 原型的原型
原型对象也是对象,所以它也有原型,当我们使用一个对象的属性或方法时,会现在自身中寻找,自身中如果有,则直接使用,如果没有则去原型对象中寻找,如果原型对象中有,则使用,如果没有则去原型的原型中寻找,直到找到Object对象的原型,Object对象的原型没有原型,如果在Object原型中依然没有找到,则返回undefined
注:仍然是类比Java,这里就相当于多层继承,Object对象就相当于最顶层的根类Object
/*
* 创建一个构造函数
*/
function MyClass(){
}
//向MyClass的原型中添加一个name属性
MyClass.prototype.name = "我是原型中的名字";
var mc = new MyClass();
mc.age = 18;
//使用in检查对象中是否含有某个属性时,如果对象中没有但是原型中有,也会返回true
console.log("name" in mc);
//可以使用对象的hasOwnProperty()来检查对象自身中是否含有该属性
//使用该方法只有当对象自身中含有属性时,才会返回true
console.log(mc.hasOwnProperty("age"));
//验证原型的原型
console.log(mc.hasOwnProperty("hasOwnProperty"));
console.log(mc.__proto__.hasOwnProperty("hasOwnProperty"));
console.log(mc.__proto__.__proto__.hasOwnProperty("hasOwnProperty"));
console.log(mc.__proto__.__proto__.__proto__);
console.log(mc.hello);
console.log(mc.__proto__.__proto__.__proto__)
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
# 38. toString方法
当我们直接在页面中打印一个对象时,事件上是输出的对象的toString()方法的返回值,如果我们希望在输出对象时不输出[object Object],可以为对象添加一个toString()方法
//修改Person原型的toString
Person.prototype.toString = function(){
return "Person[name="+this.name+",age="+this.age+",gender="+this.gender+"]";
};
//创建一个Person实例
var per = new Person("孙悟空",18,"男");
var per2 = new Person("猪八戒",28,"男");
//当我们直接在页面中打印一个对象时,事件上是输出的对象的toString()方法的返回值
//如果我们希望在输出对象时不输出[object Object],可以为对象添加一个toString()方法
//Person[name=孙悟空,age=18,gender=男]
/*per.toString = function(){
return "Person[name="+this.name+",age="+this.age+",gender="+this.gender+"]";
};*/
2
3
4
5
6
7
8
9
10
11
12
13
14
# 39. 垃圾回收(GC)
就像人生活的时间长了会产生垃圾一样,程序运行过程中也会产生垃圾,这些垃圾积攒过多以后,会导致程序运行的速度过慢,所以我们需要一个垃圾回收的机制,来处理程序运行过程中产生垃圾
- 当一个对象没有任何的变量或属性对它进行引用,此时我们将永远无法操作该对象,此时这种对象就是一个垃圾,这种对象过多会占用大量的内存空间,导致程序运行变慢,所以这种垃圾必须进行清理。
- 在JS中拥有自动的垃圾回收机制,会自动将这些垃圾对象从内存中销毁,我们不需要也不能进行垃圾回收的操作,我们需要做的只是要将不再使用的对象设置null即可。
# 40. 数组(Array)
数组也是一个对象,它和我们普通对象功能类似,也是用来存储一些值的,不同的是普通对象是使用字符串作为属性名的,而数组时使用数字来作为索引操作元素,使用typeof检查一个数组时,会返回object
索引:
- 从0开始的整数就是索引
- 数组的存储性能比普通对象要好,在开发中我们经常使用数组来存储一些数据
//创建数组对象
var arr = new Array();
/*
* 向数组中添加元素
* 语法:数组[索引] = 值
*/
arr[0] = 10;
arr[1] = 33;
/*arr[10] = 31;
arr[100] = 90;*/
/*
* 读取数组中的元素
* 语法:数组[索引]
* 如果读取不存在的索引,他不会报错而是返回undefined
*/
//console.log(arr[3]);
/*
* 获取数组的长度
* 可以使用length属性来获取数组的长度(元素的个数)
* 语法:数组.length
*
* 对于连续的数组,使用length可以获取到数组的长度(元素的个数)
* 对于非连续的数组,使用length会获取到数组的最大的索引+1
* 尽量不要创建非连续的数组
*/
console.log(arr.length);
console.log(arr);
/*
* 修改length
* 如果修改的length大于原长度,则多出部分会空出来
* 如果修改的length小于原长度,则多出的元素会被删除
*/
//arr.length = 10;
arr[4] = 50;
arr[5] = 60;
//向数组的最后一个位置添加元素
//语法:数组[数组.length] = 值;
arr[arr.length] = 70;
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
//使用字面量来创建数组
//语法:[]
var arr = [];
//使用字面量创建数组时,可以在创建时就指定数组中的元素
var arr = [1,2,3,4,5,10];
//使用构造函数创建数组时,也可以同时添加元素,将要添加的元素作为构造函数的参数传递
//元素之间使用,隔开
var arr2 = new Array(10,20,30);
//console.log(arr2);
//创建一个数组数组中只有一个元素10
arr = [10];
//创建一个长度为10的数组
arr2 = new Array(10);
//console.log(arr2.length);
//数组中的元素可以是任意的数据类型
arr = ["hello",1,true,null,undefined];
//也可以是对象
var obj = {name:"孙悟空"};
arr[arr.length] = obj;
arr = [{name:"孙悟空"},{name:"沙和尚"},{name:"猪八戒"}];
//也可以是一个函数
arr = [function(){alert(1)},function(){alert(2)}];
//console.log(arr);
//arr[0]();
//数组中也可以放数组,如下这种数组我们称为二维数组
arr = [[1,2,3],[3,4,5],[5,6,7]];
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
# 41. 数组的方法
//创建一个数组
var arr = ["孙悟空","猪八戒","沙和尚","唐僧","白骨精"];
/*
* push()
* - 该方法可以向数组的末尾添加一个或多个元素,并返回数组的新的长度
* - 可以将要添加的元素作为方法的参数传递,
* 这样这些元素将会自动添加到数组的末尾
* - 该方法会将数组新的长度作为返回值返回
*/
var result = arr.push("唐僧","蜘蛛精","白骨精","玉兔精");
//console.log(arr);
//console.log("result = "+result);
/*
* pop()
* - 该方法可以删除数组的最后一个元素,并将被删除的元素作为返回值返回
*/
result = arr.pop();
/*console.log(arr);
console.log("result = "+result);*/
/*
* unshift()
* - 向数组开头添加一个或多个元素,并返回新的数组长度
* - 向前边插入元素以后,其他的元素索引会依次调整
*/
arr.unshift("牛魔王","二郎神");
console.log(arr);
/*
* shift()
* - 可以删除数组的第一个元素,并将被删除的元素作为返回值返回
*/
result = arr.shift();
result = arr.shift();
console.log(arr);
console.log("result = "+result);
/*
* slice()
* - 可以用来从数组提取指定元素
* - 该方法不会改变元素数组,而是将截取到的元素封装到一个新数组中返回
* - 参数:
* 1.截取开始的位置的索引,包含开始索引
* 2.截取结束的位置的索引,不包含结束索引
* - 第二个参数可以省略不写,此时会截取从开始索引往后的所有元素
* - 索引可以传递一个负值,如果传递一个负值,则从后往前计算
* -1 倒数第一个
* -2 倒数第二个
*/
var result = arr.slice(1,4);
result = arr.slice(3);
result = arr.slice(1,-2);
//console.log(result);
/*
* splice()
* - 可以用于删除数组中的指定元素
* - 使用splice()会影响到原数组,会将指定元素从原数组中删除
* 并将被删除的元素作为返回值返回
* - 参数:
* 第一个,表示开始位置的索引
* 第二个,表示删除的数量
* 第三个及以后。。
* 可以传递一些新的元素,这些元素将会自动插入到开始位置索引前边
*
*/
arr = ["孙悟空","猪八戒","沙和尚","唐僧","白骨精"];
var result = arr.splice(3,0,"牛魔王","铁扇公主","红孩儿");
console.log(arr);
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
var arr = ["孙悟空","猪八戒","沙和尚"];
var arr2 = ["白骨精","玉兔精","蜘蛛精"];
var arr3 = ["二郎神","太上老君","玉皇大帝"];
/*
* concat()可以连接两个或多个数组,并将新的数组返回
* - 该方法不会对原数组产生影响
*/
var result = arr.concat(arr2,arr3,"牛魔王","铁扇公主");
/*
* join()
* - 该方法可以将数组转换为一个字符串
* - 该方法不会对原数组产生影响,而是将转换后的字符串作为结果返回
* - 在join()中可以指定一个字符串作为参数,这个字符串将会成为数组中元素的连接符
* 如果不指定连接符,则默认使用,作为连接符
*/
arr = ["孙悟空","猪八戒","沙和尚","唐僧"];
result = arr.join("@-@");
/*
* reverse()
* - 该方法用来反转数组(前边的去后边,后边的去前边)
* - 该方法会直接修改原数组
*/
arr.reverse();
//console.log(arr);
arr = ["b","d","e","a","c"];
/*
* sort()
* - 可以用来对数组中的元素进行排序
* - 也会影响原数组,默认会按照Unicode编码进行排序
*/
arr.sort();
//arr.reverse();
/*
* 即使对于纯数字的数组,使用sort()排序时,也会按照Unicode编码来排序,
* 所以对数字进排序时,可能会得到错误的结果。
*
* 我们可以自己来指定排序的规则
* 我们可以在sort()添加一个回调函数,来指定排序规则,
* 回调函数中需要定义两个形参,
* 浏览器将会分别使用数组中的元素作为实参去调用回调函数
* 使用哪个元素调用不确定,但是肯定的是在数组中a一定在b前边
* - 浏览器会根据回调函数的返回值来决定元素的顺序,
* 如果返回一个大于0的值,则元素会交换位置
* 如果返回一个小于0的值,则元素位置不变
* 如果返回一个0,则认为两个元素相等,也不交换位置
*
* - 如果需要升序排列,则返回 a-b
* 如果需要降序排列,则返回b-a
*/
arr = [5,4,2,1,3,6,8,7];
arr.sort(function(a,b){
//前边的大
/*if(a > b){
return -1;
}else if(a < b){
return 1;
}else{
return 0;
}*/
//升序排列
//return a - b;
//降序排列
return b - a;
});
console.log(arr);
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
# 42. 回调函数
被传递给另一个函数作为参数的函数叫作回调函数,更通俗的理解是:由我们创建但不由我们自己调用的函数,称为回调函数。
在 JavaScript 里创建回调函数的方法是将它作为参数传递给另一个函数,然后当某个任务完成之后,立即调用它。
回调函数确保:
- 函数在某个任务完成之前不运行,在任务完成之后立即运行。它帮助我们编写异步 JavaScript 代码,避免问题和错误。
注:
回调与同步、异步并没有直接的联系,回调只是一种实现方式,既可以有同步回调,也可以有异步回调,还可以有事件处理回调和延迟函数回调,但用处最多的还是异步回调
# 43. forEach
forEach方法可以用来遍历数组,这个方法只支持IE8以上的浏览器,所以如果需要兼容IE8,还是用for循环来遍历
使用细节
数组中有几个元素forEach函数就会执行几次,每次执行时,浏览器会将遍历到的元素,以实参的形式传递进来,我们可以来定义形参,来读取这些内容
浏览器会在回调函数中传递三个参数:
- 第一个参数,就是当前正在遍历的元素
- 第二个参数,就是当前正在遍历的元素的索引
- 第三个参数,就是正在遍历的数组
示例:
var arr = ["孙悟空","猪八戒","沙和尚","唐僧","白骨精"];
arr.forEach(function(value , index , obj){
console.log(value);
});
2
3
4
# 44. 函数的方法(call和apply)
- call()和apply()这两个方法都是函数对象的方法,需要通过函数对象来调用
- 当对函数调用call()和apply()都会调用该函数执行
- 在调用call()和apply()可以将一个对象指定为第一个参数,此时这个对象将会成为函数执行时的this
- call()方法可以将实参在对象之后依次传递
- apply()方法需要将实参封装到一个数组中统一传递
function fun(a,b) {
console.log("a = "+a);
console.log("b = "+b);
//alert(this);
}
var obj = {
name: "obj",
sayName:function(){
alert(this.name);
}
};
//fun.call(obj,2,3);
fun.apply(obj,[2,3]);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 45. arguments
在调用函数时,浏览器每次都会传递进两个隐含的参数:
- 函数的上下文对象 this
- 封装实参的对象 arguments
- arguments是一个类数组对象,它也可以通过索引来操作数据,也可以获取长度
- 在调用函数时,我们所传递的实参都会在arguments中保存,arguments.length可以用来获取实参的长度
- 我们即使不定义形参,也可以通过arguments来使用实参,arguments[0] 表示第一个实参,arguments[1] 表示第二个实参
- arguments对象里边有一个属性叫做callee,这个属性对应一个函数对象,就是当前正在指向的函数的对象
应用举例:
function fun(a,b){
//console.log(arguments instanceof Array);
//console.log(Array.isArray(arguments));
//console.log(arguments[1]);
//console.log(arguments.length);
console.log(arguments.callee == fun);
}
fun("hello",true);
2
3
4
5
6
7
8
9
# 46. Date对象
在js中使用Date对象来表示一个时间,它也是一个内置对象
//创建一个Date对象
//如果直接使用构造函数创建一个Date对象,则会封装为当前代码执行的时间
var d = new Date();
//创建一个指定的时间对象
//需要在构造函数中传递一个表示时间的字符串作为参数
//日期的格式 月份/日/年 时:分:秒
var d2 = new Date("2/18/2011 11:10:30");
/*
* getDate()
* - 获取当前日期对象是几日
*/
var date = d2.getDate();
/*
* getDay()
* - 获取当前日期对象时周几
* - 会返回一个0-6的值
* 0 表示周日
* 1表示周一
* 。。。
*/
var day = d2.getDay();
/*
* getMonth()
* d2 = new Date("12/18/2011 11:10:30");
* - 获取当前时间对象的月份
* - 会返回一个0-11的值
* 0 表示1月
* 1 表示2月
* 11 表示12月
*/
var month = d2.getMonth();
/*
* getFullYear()
* - 获取当前日期对象的年份
*/
var year = d2.getFullYear();
//console.log(d2);
//console.log("date = "+date);
//console.log("day = "+day);
//console.log("month = "+month);
//console.log(year);
/*
* getTime()
* - 获取当前日期对象的时间戳
* - 时间戳,指的是从格林威治标准时间的1970年1月1日,0时0分0秒
* 到当前日期所花费的毫秒数(1秒 = 1000毫秒)
* - 计算机底层在保存时间时使用都是时间戳
*/
var time = d2.getTime();
//console.log(time/1000/60/60/24/365);
/*var d3 = new Date("1/1/1970 0:0:0");
time = d3.getTime();
console.log(time);
*/
//利用时间戳来测试代码的执行的性能
//获取当前的时间戳
var start = Date.now();
for(var i=0 ; i<100 ; i++){
console.log(i);
}
var end = Date.now();
console.log("执行了:"+(end - start)+"毫秒");
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
# 47. Math对象
Math和其他的对象不同,它不是一个构造函数,它属于一个工具类,不用创建对象,它里边封装了数学运算相关的属性和方法
//Math.PI 表示的圆周率
console.log(Math.PI);
/*
* abs()可以用来计算一个数的绝对值
*/
console.log(Math.abs(-1));
/*
* Math.ceil()
* - 可以对一个数进行向上取整,小数位只有有值就自动进1
* Math.floor()
* - 可以对一个数进行向下取整,小数部分会被舍掉
* Math.round()
* - 可以对一个数进行四舍五入取整
*/
console.log(Math.ceil(1.1));
console.log(Math.floor(1.99));
console.log(Math.round(1.4));
/*
* Math.random()
* - 可以用来生成一个0-1之间的随机数
* Math.round()向下取整
* Math.round(Math.random()*x)
* - 生成一个0-x之间的随机数
*
* - 生成一个1-10
* - 生成一个x-y之间的随机数
* Math.round(Math.random()*(y-x)+x)
*/
for(var i=0 ; i<100 ; i++){
console.log(Math.round(Math.random()*10));
console.log(Math.round(Math.random()*20));
console.log(Math.round(Math.random()*9)+1);
console.log(Math.round(Math.random()*8)+2);
//生成1-6之间的随机数
console.log(Math.round(Math.random()*5+1));
}
/*
* max() 可以获取多个数中的最大值
* min() 可以获取多个数中的最小值
*/
var max = Math.max(10,45,30,100);
var min = Math.min(10,45,30,100);
//console.log(min);
/*
* Math.pow(x,y)
* 返回x的y次幂
*/
//console.log(Math.pow(12,3));
/*
* Math.sqrt()
* 用于对一个数进行开方运算
*/
console.log(Math.sqrt(2));
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
# 48. 包装类
JS为我们提供了三个包装类,通过这三个包装类可以将基本数据类型的数据转换为对象
1.String()
- 可以将基本数据类型字符串转换为String对象
2.Number()
- 可以将基本数据类型的数字转换为Number对象
3.Boolean()
- 可以将基本数据类型的布尔值转换为Boolean对象
注1:我们在实际应用中不会使用基本数据类型的对象,如果使用基本数据类型的对象,在做一些比较时可能会带来一些不可预期的结果
注2:方法和属性只能添加给对象,不能添加给基本数据类型,当我们对一些基本数据类型的值去调用属性和方法时,浏览器会临时使用包装类将其转换为对象,然后再调用该对象的属性和方法,调用完以后,再将其转换为基本数据类型
# 49. 字符串的相关方法
//创建一个字符串
var str = "Hello Atguigu";
/*
* 在底层字符串是以字符数组的形式保存的
* ["H","e","l"]
*/
/*
* length属性
* - 可以用来获取字符串的长度
*/
//console.log(str.length);
//console.log(str[5]);
/*
* charAt()
* - 可以返回字符串中指定位置的字符
* - 根据索引获取指定的字符
*/
str = "中Hello Atguigu";
var result = str.charAt(6);
/*
* charCodeAt()
* - 获取指定位置字符的字符编码(Unicode编码)
*/
result = str.charCodeAt(0);
/*
* String.formCharCode()
* - 可以根据字符编码去获取字符
*/
result = String.fromCharCode(0x2692);
/*
* concat()
* - 可以用来连接两个或多个字符串
* - 作用和+一样
*/
result = str.concat("你好","再见");
/*
* indexof()
* - 该方法可以检索一个字符串中是否含有指定内容
* - 如果字符串中含有该内容,则会返回其第一次出现的索引
* 如果没有找到指定的内容,则返回-1
* - 可以指定一个第二个参数,指定开始查找的位置
*
* lastIndexOf();
* - 该方法的用法和indexOf()一样,
* 不同的是indexOf是从前往后找,
* 而lastIndexOf是从后往前找
* - 也可以指定开始查找的位置
*/
str = "hello hatguigu";
result = str.indexOf("h",1);
result = str.lastIndexOf("h",5);
/*
* slice()
* - 可以从字符串中截取指定的内容
* - 不会影响原字符串,而是将截取到内容返回
* - 参数:
* 第一个,开始位置的索引(包括开始位置)
* 第二个,结束位置的索引(不包括结束位置)
* - 如果省略第二个参数,则会截取到后边所有的
* - 也可以传递一个负数作为参数,负数的话将会从后边计算
*/
str = "abcdefghijk";
result = str.slice(1,4);
result = str.slice(1,-1);
/*
* substring()
* - 可以用来截取一个字符串,可以slice()类似
* - 参数:
* - 第一个:开始截取位置的索引(包括开始位置)
* - 第二个:结束位置的索引(不包括结束位置)
* - 不同的是这个方法不能接受负值作为参数,如果传递了一个负值,则默认使用0
* - 而且他还自动调整参数的位置,如果第二个参数小于第一个,则自动交换
result = str.substring(0,1);
/*
* substr()
* - 用来截取字符串
* - 参数:
* 1.截取开始位置的索引
* 2.截取的长度
*/
str = "abcdefg";
result = str.substr(3,2);
/*
* split()
* - 可以将一个字符串拆分为一个数组
* - 参数:
* -需要一个字符串作为参数,将会根据该字符串去拆分数组
*/
str = "abcbcdefghij";
result = str.split("d");
/*
* 如果传递一个空串作为参数,则会将每个字符都拆分为数组中的一个元素
*/
result = str.split("");
//console.log(Array.isArray(result));
//console.log(result[0]);
console.log(result);
str = "abcdefg";
/*
* toUpperCase()
* - 将一个字符串转换为大写并返回
*/
result = str.toUpperCase();
str = "ABCDEFG";
/*
* toLowerCase()
* -将一个字符串转换为小写并返回
*/
result = str.toLowerCase();
//console.log(result);
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
# 50. 正则表达式
正则表达式用于定义一些字符串的规则,计算机可以根据正则表达式,来检查一个字符串是否符合规则,并将字符串中符合规则的内容提取出来
正则表达式的方法:test() 使用这个方法可以用来检查一个字符串是否符合正则表达式的规则,如果符合则返回true,否则返回false
创建正则表达式的方法
(1)创建正则对象
语法:var 变量 = new RegExp("正则表达式","匹配模式"); |
---|
使用typeof检查正则对象,会返回object
var reg = new RegExp("a"); 这个正则表达式可以来检查一个字符串中是否含有a
在构造函数中可以传递一个匹配模式作为第二个参数,i和g可以同时使用
- i 忽略大小写
- g 全局匹配模式
(2)字面量创建正则表达式
语法:var 变量 = /正则表达式/匹配模式 |
---|
使用字面量的方式创建更加简单,使用构造函数创建更加灵活
var reg = new RegExp("ab","i");
var str = "a";
var result = reg.test(str);
2
3
4
var reg = /a/i;
//console.log(typeof reg);
//console.log(reg.test("abc"));
//创建一个正则表达式,检查一个字符串中是否有a或b
/*
* 使用 | 表示或者的意思
*/
reg = /a|b|c/;
/*
* 创建一个正则表达式检查一个字符串中是否有字母
*/
reg = /a|b|c|d|e|f|g/;
/*
* []里的内容也是或的关系
* [ab] == a|b
* [a-z] 任意小写字母
* [A-Z] 任意大写字母
* [A-z] 任意字母
* [0-9] 任意数字
*/
reg = /[A-z]/;
//检查一个字符串中是否含有 abc 或 adc 或 aec
reg = /a[bde]c/;
/*
* [^ ] 除了
*/
reg = /[^ab]/;
reg = /[^0-9]/;
console.log(reg.test("12a3456"));
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
/*
* 创建一个正则表达式检查一个字符串中是否含有aaa
*/
/*
* 量词
* - 通过量词可以设置一个内容出现的次数
* - 量词只对它前边的一个内容起作用
* - {n} 正好出现n次
* - {m,n} 出现m-n次
* - {m,} m次以上
* - + 至少一个,相当于{1,}
* - * 0个或多个,相当于{0,}
* - ? 0个或1个,相当于{0,1}
*/
var reg = /a{3}/;
//ababab
reg = /(ab){3}/;
reg = /b{3}/;
reg = /ab{1,3}c/;
reg = /ab{3,}c/;
reg = /ab+c/;
reg = /ab*c/;
reg = /ab?c/;
//console.log(reg.test("abbc"));
/*
* 检查一个字符串中是否以a开头
* ^ 表示开头
* $ 表示结尾
*/
reg = /^a/; //匹配开头的a
reg = /a$/; //匹配结尾的a
//console.log(reg.test("abcabca"));
/*
* 如果在正则表达式中同时使用^ $则要求字符串必须完全符合正则表达式
*/
reg = /^a$/;
//console.log(reg.test("bbca"));
/*
* 创建一个正则表达式,用来检查一个字符串是否是一个合法手机号
*
* 手机号的规则:
* 1 3 567890123 (11位)
*
* 1. 以1开头
* 2. 第二位3-9任意数字
* 3. 三位以后任意数字9个
*
* ^1 [3-9] [0-9]{9}$
*
*/
var phoneStr = "13067890123";
var phoneReg = /^1[3-9][0-9]{9}$/;
console.log(phoneReg.test(phoneStr));
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
/*
* 检查一个字符串中是否含有 .
* . 表示任意字符
* 在正则表达式中使用\作为转义字符
* \. 表示.
* \\ 表示\
*
* 注意:使用构造函数时,由于它的参数是一个字符串,而\是字符串中转义字符,
* 如果要使用\则需要使用\\来代替
*/
var reg = /\./;
reg = /\\/;
reg = new RegExp("\\.");
reg = new RegExp("\\\\");
/*
* \w
* - 任意字母、数字、_ [A-z0-9_]
* \W
* - 除了字母、数字、_ [^A-z0-9_]
* \d
* - 任意的数字 [0-9]
* \D
* - 除了数字 [^0-9]
* \s
* - 空格
* \S
* - 除了空格
* \b
* - 单词边界
* \B
* - 除了单词边界
*/
reg = /\w/;
reg = /\W/;
reg = /\d/;
reg = /\D/;
reg = /\s/;
reg = /\S/;
/*
* 创建一个正则表达式检查一个字符串中是否含有单词child
*/
reg = /\bchild\b/;
//console.log(reg.test("hello child "));
//接收一个用户的输入
//var str = prompt("请输入你的用户名:");
var str = " he llo ";
//去除掉字符串中的前后的空格
//去除空格就是使用""来替换空格
console.log(str);
//str = str.replace(/\s/g , "");
//去除开头的空格
//str = str.replace(/^\s*/, "");
//去除结尾的空格
//str = str.replace(/\s*$/, "");
// /^\s*|\s*$/g 匹配开头和结尾的空格
str = str.replace(/^\s*|\s*$/g,"");
console.log(str);
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
/*
* 电子邮件
* hello .nihao @ abc .com.cn
*
* 任意字母数字下划线 .任意字母数字下划线 @ 任意字母数字 .任意字母(2-5位) .任意字母(2-5位)
*
* \w{3,} (\.\w+)* @ [A-z0-9]+ (\.[A-z]{2,5}){1,2}
*/
var emailReg = /^\w{3,}(\.\w+)*@[A-z0-9]+(\.[A-z]{2,5}){1,2}$/;
var email = "abc.hello@163.com";
console.log(emailReg.test(email));
2
3
4
5
6
7
8
9
10
11
12
13
# 51. 字符串和正则相关的方法
var str = "1a2b3c4d5e6f7";
/*
* split()
* - 可以将一个字符串拆分为一个数组
* - 方法中可以传递一个正则表达式作为参数,这样方法将会根据正则表达式去拆分字符串
* - 这个方法即使不指定全局匹配,也会全都插分
*/
/*
* 根据任意字母来将字符串拆分
*/
var result = str.split(/[A-z]/);
//console.log(result);
/*
* search()
* - 可以搜索字符串中是否含有指定内容
* - 如果搜索到指定内容,则会返回第一次出现的索引,如果没有搜索到返回-1
* - 它可以接受一个正则表达式作为参数,然后会根据正则表达式去检索字符串
* - serach()只会查找第一个,即使设置全局匹配也没用
*/
str = "hello abc hello aec afc";
/*
* 搜索字符串中是否含有abc 或 aec 或 afc
*/
result = str.search(/a[bef]c/);
//console.log(result);
/*
* match()
* - 可以根据正则表达式,从一个字符串中将符合条件的内容提取出来
* - 默认情况下我们的match只会找到第一个符合要求的内容,找到以后就停止检索
* 我们可以设置正则表达式为全局匹配模式,这样就会匹配到所有的内容
* 可以为一个正则表达式设置多个匹配模式,且顺序无所谓
* - match()会将匹配到的内容封装到一个数组中返回,即使只查询到一个结果
*
*
*/
str = "1a2a3a4a5e6f7A8B9C";
result = str.match(/[a-z]/ig);
//console.log(result[2]);
/*
* replace()
* - 可以将字符串中指定内容替换为新的内容
* - 参数:
* 1.被替换的内容,可以接受一个正则表达式作为参数
* 2.新的内容
* - 默认只会替换第一个
*/
//result = str.replace(/[a-z]/gi , "@_@");
result = str.replace(/[a-z]/gi , "");
//console.log(result);
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
# 52. DOM
DOM全称Document Object Model ①文档(Document) 整个HTML文件就是一个文档 ②对象(Object) HTML文件中的每个节点都在JS中是一个对象 ③模型(Model) JS使用模型来表示各个对象之间的关系
js中有宿主对象document,它是window对象的属性,也就是文档对象本身
DOM中的对象又称为节点对象,共有4种节点,每个节点中都拥有三个属性,分别是:
nodeName | nodeType | nodeValue | |
---|---|---|---|
文档节点 | #document | 9 | null |
元素节点 | 标签名 | 1 | null |
属性节点 | 属性名 | 2 | 属性值 |
文本节点 | #text | 3 | 文本内容 |
常用属性: 1.body 该属性封装的是body元素对象的引用 2.documentElement 属性值为HTML元素对象 3.all 属性值为当前页面中的所有元素节点的数组 这个属性值本身为undefined,它的typeof值也为undefined 4.URL 获取当前页面的url 5.domain 获取当前页面的域名部分 6.referrer 获取是哪个页面链接跳转到当前页面,没有则返回空字符串 常用方法: 语法:
document.方法(); |
---|
1.getElementById() 通过ID值获取对应的节点 IE8中不区分大小写 IE7中会匹配表单元素的name值 2.getElementsByTagName() 通过标签名获取一组节点 返回值是一个HTMLCollection,即使只获取到一个节点时,也封装成HTMLCollection返回 3.getElementsByName() 通过name的值获取一组节点 返回值是一个nodelist,与数组相似,可以使用forEach方法,即使只获取到一个节点时,也封装成nodelist返回 4.getElementsByClassName() 通过class属性获取一组节点 返回值是一个HTMLCollection,即使只获取到一个节点时,也封装成HTMLCollection返回 仅支持IE8以上 5.querySlector() 通过CSS选择器返回一个节点,当能匹配多个节点时,返回满足匹配的第一个节点 仅支持IE7以上 6.querySlectorAll() 通过CSS选择器返回一组节点 返回值是一个nodelist,与数组相似,可以使用forEach方法,即使只获取到一个节点时,也封装成nodelist返回 仅支持IE7以上
- HTMLCollection:支持通过索引或者字符串来查找需要的节点,在后台则分别使用它的item()与namedItem()方法来获取
- NodeList: 与HTMLCollection类似的一个node集合,他们的值都是动态的,每次去取这些值的属性都会引发一次文档查询,因此需要尽量减少直接访问
# 53. 文档加载顺序
浏览器在加载一个页面时,是按照自上向下的顺序加载的,读取到一行就运行一行,如果将script标签写到页面的上边,在代码执行时,页面还没有加载,故DOM对象也没有加载,会导致无法获取到DOM对象
onload事件会在整个页面加载完成之后才触发,为window绑定一个onload事件,该事件对应的响应函数将会在页面加载完成之后执行,这样可以确保我们的代码执行时所有的DOM对象已经加载完毕了
# 54. 事件
事件,就是用户和浏览器之间的交互行为,比如:点击按钮,鼠标移动、关闭窗口。
当用户与浏览器进行任何交互时都会产生相应的事件,js可以通过给事件绑定相应函数来使事件触发时执行相应的函数,相应函数会在执行事件时才会被执行,因此相应函数内部使用的变量可能会与预期不一致
var div = document.getElementByTagName("test");
for(var i = 0; i < div.length; i++){
div[i].onclick = function(){
console.log(i);
}
}
2
3
4
5
6
结果永远会是div的长度的值
绑定事件方法 第一种:
<button id="btn" onclick="alert('a')"></button>
我们称这种方式结构与行为耦合,不推荐使用
第二种:
<button id="btn"></button>
<script>
var btn = document.getElementById("btn");
btn.onclick = function(){
alert("a");
}
</script>
2
3
4
5
6
7
# 55. 元素节点
元素节点拥有一个方法和属性来获取它们内部的节点,除了元素的class属性以外,所有的属性都可以以元素节点对象属性的方式获取,class的值需要用className属性来获取,因为class是js中的保留字
(1)常用方法 1.getElementById()
- 通过ID值获取当前元素节点内部对应的节点
2.getElementsByTagName()
- 用来获取当前元素节点内部的特定标签的元素节点
- 返回值是一个HTMLCollection,与数组相似,不能使用forEach方法,即使只获取到一个节点时,也封装成HTMLCollection返回
3.getElementsByName()
- 通过name的值获取当前元素节点内部的一组节点
- 返回值是一个nodelist,与数组相似,可以使用forEach方法,即使只获取到一个节点时,也封装成nodelist返回
4.getElementsByClassName()
- 通过class属性获取当前元素节点内部的一组节点
- 返回值是一个HTMLCollection,与数组相似,不能使用forEach方法,即使只获取到一个节点时,也封装成HTMLCollection返回
- 仅支持IE8以上
5.querySlector()
- 通过CSS选择器返回当前元素节点内部的一个节点,当能匹配多个节点时,返回满足匹配的第一个节点
- 仅支持IE7以上
6.querySlectorAll()
- 通过CSS选择器返回当前元素节点内部的一组节点
- 返回值是一个nodelist,与数组相似,可以使用forEach方法,即使只获取到一个节点时,也封装成nodelist返回
- 仅支持IE7以上
7.hasChildNodes()
- 返回当前节点内部是否拥有1个或多个子节点
(2)常用属性 1.innerHTML
- 获取当前元素节点中的HTML代码
2.innerText
- 获取当前元素节点中的文本
3.childNodes
- 获取当前元素节点中所有的子节点并以数组形式返回,按照ES标准如果当前元素节点中有空格时也会被包括在内
- IE8及以下浏览器没有实现这一标准,因此只会获取到内部的元素节点
4.children
- 获取当前元素节点中的所有子元素节点
5.firstChild
- 获取当前元素节点中的第一个子节点
6.firstElementChild
- 获取当前元素节点中的第一个子元素节点, 仅支持IE8以上
7.lastChild
- 获取当前元素节点中的最后一个子节点
8.lastElementChild
- 获取当前元素节点中的最后一个子元素节点, 仅支持IE8以上
9.parentNode
- 获取当前元素节点的父节点
10.previousSibling
- 获取当前元素节点的前一个兄弟节点
11.previousElementSibling
- 获取当前元素节点的前一个兄弟元素节点, 仅支持IE8以上
12.nextSibling
- 获取当前元素节点的后一个兄弟节点
13.nextElementSibling
- 获取当前元素节点的后一个兄弟元素节点, 仅支持IE8以上
- 当响应函数给某个节点绑定时,这个响应函数中的this就是这个节点
# 56. DOM的增删改
常用方法: 1.createElement() 新建一个元素节点,参数是元素节点的标签名 语法: document.createElement("标签名"); 2.createTextNode() 新建一个文本节点,参数是文本节点的内容 语法:document.createTextNode("文本内容"); 3.appendChild() 向一个父节点中添加一个子节点 语法:父节点.appendChild(子节点); 4.insertBefore() 向一个子节点前添加一个新的节点 语法:父节点.insertBefore(新节点, 原节点); 5.removeChild() 移除一个子节点 语法:父节点.removeChild(子节点); 6.replaceChild() 将原节点替换成新节点 语法:父节点.replaceChild(新节点, 原节点); 7.cloneNode() 返回值是一个节点的拷贝,接受一个布尔值作为参数,true则为深度拷贝,false为浅拷贝 语法:节点:cloneNode(boolean) 8.normalize() 返回一个经过一定处理后的节点, 这个过程会合并文本节点并删除空白的文本节点 9.splitText(str) 返回一个按照参数进行分割的多个文本节点, 此方法只可被用于文本节点
由于许多方法都要通过父节点调用对应的方法来操作节点,因此可使用: 子节点.parentNode.removeChild(子节点); 类似的方法来对节点进行直接操作而不需要获取它的父节点 对DOM的增删改操作可以用父节点的innerHTML的字符串操作来代替,由于是整体修改所以这个父节点包括它的子节点绑定的函数都会失效 代码1:
<html>
<head>
</head>
<body>
<div>
<input type="checkbox" id="checkallbox"/>AAAAA
</div>
</body>
</html>
<script>
var input = document.createElement("input");
var checkallbox = document.getElementById("checkallbox");
input.type="checkbox";
checkallbox.parentNode.insertBefore(input, checkallbox);
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
代码2
<html>
<head>
</head>
<body>
<div>
<input type="checkbox" id="checkallbox"/>AAAAA
</div>
</body>
</html>
<script>
var div = document.getElementByTagName("div")[0];
div = "<input type='checkbox'/>" + div.innterHTML;
</script>
2
3
4
5
6
7
8
9
10
11
12
13
两部分代码功能基本相同,唯一区别是如果input标签绑定了响应函数,在代码2中会失效
# 57. DOM的遍历
(1)document.createNodeIterator(root, whatToShow, filter, entityReferenceExpansion) ①root: 指定开始遍历的根节点,只能遍历body标签中的节点,其他标签会被跳过 ②whatToShow: 标识要访问标签元素的哪些节点,它是一个数字代码,语义化信息保存在NodeFilter类型中 NodeFilter.SHOW_ALL 显示所有节点 NodeFilter.SHOW_ELEMENT 显示元素节点 NodeFilter.SHOW_ATTRIBUTE 显示属性节点 NodeFilter.SHOW_TEXT 显示文本节点 NodeFilter.SHOW_DOCUMENT 显示文档节点 NodeFilter.SHOW_COMMENT 显示注释节点 ③filter: 是一个NodeFilter对象,或者一个返回接受或拒绝特定标签的函数,也可以是一个与acceptNode方法相似的函数
- NodeFilter对象是一个只有acceptNode方法的对象,该方法是一个迭代回调函数,有一个node参数,迭代器中有几个节点则会被执行几次
- 返回值应是NodeFilter.FILTER_ACCEPT或者NodeFilter.FILTER_SKIP,通过返回值来判断是否能够访问当前回调函数中的标签元素
var filter = {
acceptNode: function(node){
return node.tagName.toLowerCase() == "p" ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP
}
2
3
4
④entityReferenceExpansion: 标识是否要扩展实体引用,在html中没有意义
- nodeIterator有两个方法nextNode()与previousNode()来访问迭代器中的节点
- 刚创建好的迭代器一开始是指向一个标识根节点的指针,第一次调用nextNode会指向第一个子节点
- 当越界时返回值为null
- 支持IE9+和其他浏览器
(2)document.createTreeWalker(root, whatToShow, filter, entityReferenceExpansion)
- 可以实现在经过过滤的root节点中任意跳跃,非常灵活,参数与上一个函数一致,唯一有区别的在于第三个参数的Nodefilter函数增加一个有效的返回值NodeFilter.FILTER_REJECT
- 此时迭代器会跳过这个节点及其后代元素而不是像NodeFilter.FILTER_SKIP那样单纯跳过当前节点,仍然进行深度遍历
- 在createNodeIterator的第三个参数中返回NodeFilter.FILTER_REJECT作用与NodeFilter.FILTER_SKIP相同
相较于NodeIterator对象,TreeWalker对象多出一些重要方法: parentNode() firstChild() lastChild() nextSibling() previousSibling() 通过这些方法可以实现在TreeWalker对象中任意跳转到目标元素
# 58. DOM范围
可以通过范围来选择文档中的一个区域而不必考虑节点的界限(选择在后台完成,对用户是不可见的)
1.以下属性可以获取到当前范围在文档中的位置信息
(1)startContainer
- 包含范围起点的节点,即起点的父节点
(2)startOffset
- 范围起点在startContainer中的偏移量
- 如果起点是文本节点,注释节点,cdata节点则值是范围起点节点距离startContainer需要跳过的字符串
- 如果起点是元素节点,则值是范围起点节点在startContainer中的子节点索引
(3)endContainer 包含范围终点的节点,即终点的父节点
(4)endOffset
- 范围终点在startContainer中的位置
- 值计算规则与startOffset相同
(5)commonAncestorContainer
- 起点节点与终点节点共同的最近的那个祖先节点
2.通过以下方法可以进行选择范围操作
(1)selectNode
- 选中传入参数的那个节点及内部节点
(2)selectNodeContents
- 选中传入参数的那个节点的内部节点
(3)setStartBefore(refnode)
- 将范围起点设置为refnode之前,refnode就成为了范围选区的第一个节点
- startContainer变成refnode的父节点,startOffset的值变成refnode在父节点中的索引
(4)setStartAfter(refnode)
- 将范围起点设置为refnode之后,refnode就成为了范围选区外的节点,下一个节点是范围选区内第一个节点
- startContainer变成refnode的父节点,startOffset的值变成refnode在父节点中的索引加1
(5)setEndBefore(refnode)
- 将范围终点设置为refnode之前,refnode就成为了范围选区的最后一个节点
- startContainer变成refnode的父节点,startOffset的值变成refnode在父节点中的索引
(6)setEndAfter(refnode)
- 将范围起点设置为refnode之后,refnode就成为了范围选区外的节点,下一个节点是范围选区内第一个节点
- startContainer变成refnode的父节点,startOffset的值变成refnode在父节点中的索引加1
(7)setStart()
- 传入两个参数,第一个参数是参照节点,第二个参数是偏移量
- 参照节点会被当做startContainer,偏移量会变成startOffset
(8)setEnd()
- 传入两个参数,第一个参数是参照节点,第二个参数是偏移量
- 参照节点会被当做endContainer,偏移量会变成endOffset
3.创建范围之后可以使用以下方法对选中内容进行操作
(1)deleteContents()
- 将选中的内容从文档中删除
(2)extractContents()
- 将选中的内容从文档中提取出来并作为返回值返回
(3)cloneContents()
- 拷贝一份选中的内容并作为返回值返回
(4)insertNode()
- 将一个节点插入到范围的最开始处
(5)surroundContents()
- 将范围内容插入到这个节点之内
(6)collapse()
- 可以将选中的范围进行折叠,使范围起点与终点都指向同一个位置
- 传入一个布尔值作参数,true表示折叠到原范围的起点,false表示折叠到原范围的终点
(7)compareBoundaryPoints()
- 传入两个参数,第一个参数是需要比较哪两个点的一个常量,值可以Range.START_TO_START,Range.START_TO_END,Range.END_TO_START,Range.END_TO_END
- 第二个参数是需要比较的范围,如果调用这个方法的范围与传入的范围的需要比较的点是前者在前则返回-1,相同返回0,前者在后则返回1
(8)detach()
- 在使用完范围后最好使用此方法来使范围从文档中分离,然后再删除引用,方便垃圾回收机制清理
4.IE8及以下的文本范围
(1)创建文本范围
- 在input,button,textarea,body等几个元素可以使用createTextRange来创建文本节点
(2)选取文本范围 1.findText()
- 传入一个字符串参数,如果找到了对应的范围则返回值为true否则为false同时让范围包围这段文本
2.moveToElementText()
- 传入一个DOM节点,让范围包含这个节点的文本信息与标签信息,与selectNode作用类似
3.move() 4.moveStart() 5.moveEnd() 6.expand() 这些方法都传入两个参数,第一个参数是移动单位,第二个参数是移动单位的数量 移动单位可以是以下值 character:逐个字符移动 word:逐个单词移动 sentence: 逐个句子(一系列以叹号问号句号结尾的字符)移动 textedit:移动到当前选区开始或结束的位置 move会将范围折叠,expand会将部分文本的范围变成完整文本的范围
(3)修改范围内的内容
- 有text与pasteHTML(),前者改变文本,后者可以包括标签
(4)折叠范围
- 与其他浏览器相同,使用collapse()来折叠范围
- 但是没有collapsed属性来判断是否折叠,但是可以使用boundingWidth属性来判断范围宽度是否为0
(5)比较范围
compareEndPoints(),用法与作用同compareBoundaryPoints类似
- 第一个参数是字符串,表示需要比较哪两个点如: StartToEnd等格式
- 第二个参数是待比较的范围
(6)复制范围
- duplicate(),作用与cloneContents()相同
# 59. DOM操作CSS样式
在css的属性中如果有用-来间接的情况,在style需要使用驼峰命名法来修改属性名从而设置或者读取对应的样式
1.style
语法:节点对象.style.属性值 |
---|
- 通过这个属性能够修改和读取到节点的内联样式,当节点没有内联样式时获取到的是空字符串
- 如果在其他地方的css样式中设置了!important,那么通过js操作这个属性会失效
2.currentStyle 此属性只能在IE浏览器中使用并且是只读的,当未给某个节点设置长度值时会返回auto
语法:节点对象.currentStyle.属性值 |
---|
3.getComputedStyle()
- 此方法是window的方法,可以直接使用,而且也是只读的
- 在获取width属性时当未设置具体样式的情况下,会返回节点对象实际呈现的结果而不是auto
- 此方法支持IE8以上以及其他浏览器
语法:getComputedStyle(节点对象, 伪元素(常设置为null))[样式名] |
---|
常用属性
1.clientHeight
- 获取元素的视图高度,包括元素的内容高度与内边距高度,返回值是一个数字,只读, 在根标签的此属性就是指代视口大小,与此规则无关
2.clientwidth
- 获取元素的视图宽度,包括元素的内容宽度与内边距宽度,返回值是一个数字,只读, 在根标签的此属性就是指代视口大小,与此规则无关
3.offsetHeight
- 获取元素的真实高度,包括元素的内容高度,内边距高度与边框高度,当被父元素隐藏或者滚动时不会影响这个值,返回值是一个数字,只读,在IE11以下浏览器中的根标签的此属性就是指代视口大小,与此规则无关
4.offsetWidth
- 获取元素的真实宽度,包括元素的内容宽度,内边距宽度与边框宽度,当被父元素隐藏或者滚动时不会影响这个值,返回值是一个数字,只读,在IE11以下浏览器中的根标签的此属性就是指代视口大小,与此规则无关
5.offsetParent
- 获取当前元素的定位父元素,即设置了position的最近父元素,当所有父元素都没有设置时,返回body元素, 但是在除了火狐的浏览器中当position设置为fixed,返回null.
- 在IE7及以下时,position为absolute与relative时返回html,body与html间的margin清除后可看做body. 在IE7以下时当祖先元素开启hasLayout返回最近开启的元素
6.offsetTop
- 获取当前元素相对于定位父元素的上侧偏移量(相对于offsetParent的内边距),即使父元素自身有偏移量也不改变这个值的大小,返回值是一个数字,只读
7.offsetLeft
- 获取当前元素相对于定位父元素的左侧偏移量(相对于offsetParent的内边距),即使父元素自身有偏移量也不改变这个值的大小,返回值是一个数字,只读
8.scrollHeight
- 获取当前元素的真实高度,包括元素的内容高度与内边距高度,当被父元素隐藏或者滚动时不会影响这个值,返回值是一个数字,只读
9.scrollWidth
- 获取当前元素的真实宽度,包括元素的内容宽度与内边距宽度,当被父元素隐藏或者滚动时不会影响这个值,返回值是一个数字,只读
10.scrollTop
- 获取当前元素的右侧滚动条滚动的像素,返回值是一个数字,只读
11.scrollLeft
- 获取当前元素的下侧滚动条滚动的像素,返回值是一个数字,只读
- 公式:scrollHeight - scrollTop = clientHeight 可以证明滚动条滚动到最底端
12.getBoundingClientRect
- 基于border-box,获取一个元素四个角的相对位置与高宽, 在IE7及以下没有width与height属性
- 获取绝对位置可以让相对位置加上滚动的像素
# 60. 事件对象
当给某个元素对象绑定响应函数后,浏览器在执行这个响应函数后会向这个函数自动传递一个实参,该实参封装了与此事件有关的任何数据,可以给响应函数添加形参来调用这个事件对象
var div = document.getElementByTagName("div")[0];
div.onclick = function(event){}
2
IE8及以下浏览器不会传递此实参,因此会无法获取到 IE与chrome浏览器也会将这个实参保存在window.event中,可以用来兼容IE8及以下浏览器
var div = document.getElementByTagName("div")[0];
div.onclick = function(event){
event = event || window.event;
}
2
3
4
浏览器的滚动条在Chrome中被认为是documentElement的scrollTop和scrollLeft的值,而在IE与Firefox被认为是body的scrollTop和scrollLeft的值 因此可以使用以下代码来兼容三种浏览器
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
var scrollLeft = document.body.scrollLeft || docu·ment.documentElement.scrollLeft;
2
常用属性
1.clientX
- 返回触发此事件时鼠标在视图中的X坐标
2.clientY
- 返回触发此事件时鼠标在视图中的Y坐标
3.pageX
- 返回触发此事件时鼠标在触发此事件的元素中的X坐标,仅支持IE8以上及其他浏览器
4.pageY
- 返回触发此事件时鼠标在触发此事件的元素中的Y坐标,仅支持IE8以上及其他浏览器
1.IE浏览器的浏览器默认行为不能使用return false;来阻止某些浏览器默认行为如文字拖拽
2.在IE浏览器中可以设置obj.setCapture来让所有的操作都被设置的obj捕获,其他对象就不会执行任何响应函数
3.同样可以设置document.releaseCapture来取消事件捕获,这个可以与其他浏览器的在响应函数中return false;一起使用来达到取消浏览器默认行为的作用
4.return false与event.returnValue=false作用相同
5.对于其他默认行为由于IE不支持event.preventDefault,因此可以使用来做到兼容所有浏览器
event.preventDefault && event.preventDefault();
return false;
2
6.当事件由addEventListener绑定时,不能使用return false取消默认行为而需要event.preventDefault,对于不支持此方法的IE,使用event.returnValue=false
# 61. 事件冒泡
- 所谓的冒泡指的就是事件的向上传导,当后代元素上的事件被触发时,其祖先元素的相同事件也会被触发
- 在开发中大部分情况冒泡都是有用的,如果不希望发生事件冒泡可以通过事件对象来取消冒泡
- 当某个元素的事件触发时,相同的事件会一层层向这个元素的父元素传递,如果不希望这个元素向外进行事件冒泡有两种方法来取消冒泡
- 是否传递是根据dom树结构来决定而不是页面上是否包裹,只要是父元素,不管是否与子元素重叠都会将子元素的事件冒泡给父元素
取消事件冒泡
1.event.cancelBubble=true 不属于W3C标准,但是更方便,新版本的chrome与firefox都已经支持 2.event.stopPropogation() W3C标准,但是IE不支持
示例代码:
<html>
<head>
<style>
#outer{
width: 500px;
height: 500px;
padding: 10px;
border: 20px solid gray;
background-color: blue;
position:relative;
}
#inner{
width: 400px;
height: 400px;
padding: 10px;
border: 20px solid rgb(0, 0, 0);
background-color: green;
position:relative;
}
#content{
width: 300px;
height: 300px;
padding: 10px;
border: 20px solid red;
background-color: yellow;
}
</style>
<script>
//结果为弹出两个框分别为content与inner
window.onload=function(){
var outer = document.getElementById("outer");
var inner = document.getElementById("inner");
var content = document.getElementById("content");
content.onclick = function(event){
alert("content");
};
inner.onclick = function(event){
alert("inner");
event.cancelBubble = true;
};
outer.onclick = function(event){
alert("outer");
};
}
</script>
</head>
<body>
<div id="outer"></div>
<div id="inner"></div>
<div id="content"></div>
</body>
</html>
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
# 62. 事件委派
- 指将事件统一绑定给元素的共同的祖先元素,这样当后代元素上的事件触发时,会一直冒泡到祖先元素,从而通过祖先元素的响应函数来处理事件
- 事件委派是利用了冒泡,通过委派可以减少事件绑定的次数,提高程序的性能
- 当事件触发时响应函数的形参属性event.target会指定实际触发此函数的节点
论证事件委派的必要性
<head>
<script type="text/javascript">
window.onload = function(){
var u1 = document.getElementById("u1");
//点击按钮以后添加超链接
var btn01 = document.getElementById("btn01");
btn01.onclick = function(){
//创建一个li
var li = document.createElement("li");
li.innerHTML = "<a href='javascript:;' class='link'>新建的超链接</a>";
//将li添加到ul中
u1.appendChild(li);
};
/*
* 为每一个超链接都绑定一个单击响应函数
* 这里我们为每一个超链接都绑定了一个单击响应函数,这种操作比较麻烦,
* 而且这些操作只能为已有的超链接设置事件,而新添加的超链接必须重新绑定
*/
//获取所有的a
var allA = document.getElementsByTagName("a");
//遍历
/*for(var i=0 ; i<allA.length ; i++){
allA[i].onclick = function(){
alert("我是a的单击响应函数!!!");
};
}*/
/*
* 我们希望,只绑定一次事件,即可应用到多个的元素上,即使元素是后添加的
* 我们可以尝试将其绑定给元素的共同的祖先元素
*/
//为ul绑定一个单击响应函数
u1.onclick = function(event){
event = event || window.event;
/*
* target
* - event中的target表示的触发事件的对象
*/
//如果触发事件的对象是我们期望的元素,则执行否则不执行
if(event.target.className == "link"){
alert("我是ul的单击响应函数");
}
};
};
</script>
</head>
<body>
<button id="btn01">添加超链接</button>
<ul id="u1" style="background-color: #bfa;">
<li>
<p>我是p元素</p>
</li>
<li><a href="javascript:;" class="link">超链接一</a></li>
<li><a href="javascript:;" class="link">超链接二</a></li>
<li><a href="javascript:;" class="link">超链接三</a></li>
</ul>
</body>
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
# 63. 事件绑定
当对同一个节点的事件重复绑定响应函数时后绑定的函数会覆盖前绑定的函数导致前绑定的函数不会被执行
a.onclick = function(){
console.log(1);
};
a.onclick = function(){
console.log(2);
};
//结果为2
2
3
4
5
6
7
使用addEventListener来为节点添加监听函数,响应函数可以绑定多次,并且会按顺序执行,支持IE8以上或者其他的浏览器,响应函数内部的this指向节点对象,解绑使用removeEventListener 参数: --事件名,不带on --响应函数 --布尔值,决定事件是否在捕获阶段执行,默认为false,在冒泡阶段执行
语法:对象.addEventListener("", 响应函数, false/true) |
---|
想要兼容IE8及以下浏览器时使用attachEvent,同样可以绑定多次,但是顺序为后绑定先执行,响应函数内部的this指向window,解绑使用detatchEvent 参数: --事件名,带on --响应函数
语法:对象.addEventListener("", 响应函数) |
---|
可以自定义一个bind函数来兼容两者 参数: --需要绑定响应函数的节点对象 --事件名,不带on --响应函数
function bind(obj, eventStr, func){
obj.addEventListener ? obj.addEventListener(eventStr, func) : obj.attachEvent("on" + eventStr, function(){func.call(obj)});
}
2
3
# 64. 事件传播
关于事件的传播网景公司和微软公司有不同的理解
- 微软公司认为事件应该是由内向外传播,也就是当事件触发时,应该先触发当前元素上的事件,然后再向当前元素的祖先元素上传播,也就说事件应该在冒泡阶段执行
- 网景公司认为事件应该是由外向内传播的,也就是当前事件触发时,应该先触发当前元素的最外层的祖先元素的事件,然后再向内传播给后代元素
W3C综合了两个公司的方案,将事件传播分成了三个阶段 1.捕获阶段
- 在捕获阶段时从最外层的祖先元素,向目标元素进行事件的捕获,但是默认此时不会触发事件
2.目标阶段
- 事件捕获到目标元素,捕获结束开始在目标元素上触发事件
3.冒泡阶段
- 事件从目标元素向他的祖先元素传递,依次触发祖先元素上的事件
注意:
- 如果希望在捕获阶段就触发事件,可以将addEventListener()的第三个参数设置为true,一般情况下我们不会希望在捕获阶段触发事件,所以这个参数一般都是false
- IE8及以下的浏览器中没有捕获阶段
# 65. 滚轮事件和键盘事件
(1)滚轮事件
window.onload = function(){
//获取id为box1的div
var box1 = document.getElementById("box1");
//为box1绑定一个鼠标滚轮滚动的事件
/*
* onmousewheel鼠标滚轮滚动的事件,会在滚轮滚动时触发,
* 但是火狐不支持该属性
*
* 在火狐中需要使用 DOMMouseScroll 来绑定滚动事件
* 注意该事件需要通过addEventListener()函数来绑定
*/
box1.onmousewheel = function(event){
event = event || window.event;
//event.wheelDelta 可以获取鼠标滚轮滚动的方向
//向上滚 120 向下滚 -120
//wheelDelta这个值我们不看大小,只看正负
//alert(event.wheelDelta);
//wheelDelta这个属性火狐中不支持
//在火狐中使用event.detail来获取滚动的方向
//向上滚 -3 向下滚 3
//alert(event.detail);
/*
* 当鼠标滚轮向下滚动时,box1变长
* 当滚轮向上滚动时,box1变短
*/
//判断鼠标滚轮滚动的方向
if(event.wheelDelta > 0 || event.detail < 0){
//向上滚,box1变短
box1.style.height = box1.clientHeight - 10 + "px";
}else{
//向下滚,box1变长
box1.style.height = box1.clientHeight + 10 + "px";
}
/*
* 使用addEventListener()方法绑定响应函数,取消默认行为时不能使用return false
* 需要使用event来取消默认行为event.preventDefault();
* 但是IE8不支持event.preventDefault();这个玩意,如果直接调用会报错
*/
event.preventDefault && event.preventDefault();
/*
* 当滚轮滚动时,如果浏览器有滚动条,滚动条会随之滚动,
* 这是浏览器的默认行为,如果不希望发生,则可以取消默认行为
*/
return false;
};
//为火狐绑定滚轮事件
bind(box1,"DOMMouseScroll",box1.onmousewheel);
};
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
(2)键盘事件
<script>
/*
* 键盘事件:
* onkeydown
* - 按键被按下
* - 对于onkeydown来说如果一直按着某个按键不松手,则事件会一直触发
* - 当onkeydown连续触发时,第一次和第二次之间会间隔稍微长一点,其他的会非常的快
* 这种设计是为了防止误操作的发生。
* onkeyup
* - 按键被松开
*
* 键盘事件一般都会绑定给一些可以获取到焦点的对象或者是document
*/
document.onkeydown = function(event){
event = event || window.event;
/*
* 可以通过keyCode来获取按键的编码
* 通过它可以判断哪个按键被按下
* 除了keyCode,事件对象中还提供了几个属性
* altKey
* ctrlKey
* shiftKey
* - 这个三个用来判断alt ctrl 和 shift是否被按下
* 如果按下则返回true,否则返回false
*/
//console.log(event.keyCode);
//判断一个y是否被按下
//判断y和ctrl是否同时被按下
if(event.keyCode === 89 && event.ctrlKey){
console.log("ctrl和y都被按下了");
}
};
/*document.onkeyup = function(){
console.log("按键松开了");
};*/
//获取input
var input = document.getElementsByTagName("input")[0];
input.onkeydown = function(event){
event = event || window.event;
//console.log(event.keyCode);
//数字 48 - 57
//使文本框中不能输入数字
if(event.keyCode >= 48 && event.keyCode <= 57){
//在文本框中输入内容,属于onkeydown的默认行为
//如果在onkeydown中取消了默认行为,则输入的内容,不会出现在文本框中
return false;
}
};
</script>
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
# 66.BOM
BOM即Browser Object Model,浏览器对象模型
BOM为我们提供了以下对象,让我们用js来完成对浏览器的操作,这些BOM对象在浏览器中都是作为window对象的属性保存的,可以通过window对象来使用,也可以直接使用
1.Window
- 代表浏览器窗口并且保存浏览器的全局对象
- window.open 当弹窗被浏览器内置工具屏蔽时会返回null,被工具屏蔽会报错
2.Navigator
- 代表浏览器信息,通过该对象可以来识别不同的浏览器
- 由于历史原因大部分属性没有意义,只剩下userAgent可以判断浏览器类型,这是一个字符串,其中包含有用来描述浏览器信息的内容
/*
* 火狐的userAgent
* Mozilla/5.0 (Windows NT 6.1; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0
*
* Chrome的userAgent
* Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36
* IE11
* Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; rv:11.0) like Gecko
* - 在IE11中已经将微软和IE相关的标识都已经去除了,所以我们基本已经不能通过UserAgent来识别一个浏览器是否是IE了
*/
//alert(navigator.appName);
var ua = navigator.userAgent;
console.log(ua);
if(/firefox/i.test(ua)){
alert("你是火狐!!!");
}else if(/chrome/i.test(ua)){
alert("你是Chrome");
}else if(/msie/i.test(ua)){
alert("你是IE浏览器~~~");
}else if("ActiveXObject" in window){
alert("你是IE11,枪毙了你~~~");
}
/*
* 如果通过UserAgent不能判断,还可以通过一些浏览器中特有的对象,来判断浏览器的信息
* 比如:ActiveXObject
*/
/*if("ActiveXObject" in window){
alert("你是IE,我已经抓住你了~~~");
}else{
alert("你不是IE~~~");
}*/
/*alert("ActiveXObject" in window);*/
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
3.Location
- 代表浏览器地址栏信息
- 如果直接打印location,则能获取到当前网址栏的信息
- 修改location属性为一个完整路径或相对路径则页面会直接跳转
//如果直接打印location,则可以获取到地址栏的信息(当前页面的完整路径)
//alert(location);
/*
* 如果直接将location属性修改为一个完整的路径,或相对路径
* 则我们页面会自动跳转到该路径,并且会生成相应的历史记录
*/
//location = "http://www.baidu.com";
//location = "01.BOM.html";
/*
* assign()
* - 用来跳转到其他的页面,作用和直接修改location一样
*/
//location.assign("http://www.baidu.com");
/*
* reload()
* - 用于重新加载当前页面,作用和刷新按钮一样
* - 如果在方法中传递一个true,作为参数,则会强制清空缓存刷新页面
*/
//location.reload(true);
/*
* replace()
* - 可以使用一个新的页面替换当前页面,调用完毕也会跳转页面
* 不会生成历史记录,不能使用回退按钮回退
*/
location.replace("01.BOM.html");
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
4.History 代表历史记录,只能前进后退
/*
* length
* - 属性,可以获取到当成访问的链接数量
*/
//alert(history.length);
/*
* back()
* - 可以用来回退到上一个页面,作用和浏览器的回退按钮一样
*/
//history.back();
/*
* forward()
* - 可以跳转下一个页面,作用和浏览器的前进按钮一样
*/
//history.forward();
/*
* go()
* - 可以用来跳转到指定的页面
* - 它需要一个整数作为参数
* 1:表示向前跳转一个页面 相当于forward()
* 2:表示向前跳转两个页面
* -1:表示向后跳转一个页面
* -2:表示向后跳转两个页面
*/
history.go(-2);
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
5.Screen
- 代表用户当前屏幕
# 67. 定时器
(1)定时调用
setInterval(func,num) 定时调用,可以将一个函数,每隔一段时间执行一次
参数分别为: 1.回调函数,该函数会每隔一段时间被调用一次 2.每次调用间隔的时间,单位是毫秒
返回值: 返回一个Number类型的数据,这个数字用来作为定时器的唯一标识
(2)延时调用
window.setTimeout(func, num) 延时调用,不马上执行,经过num毫秒后调用,只调用一次
参数分别为: 1.回调函数 2.延迟调用的时间,单位是毫秒
如何关闭:
- clearTimeout()可以用来关闭一个setTimeout定时器
- 该方法中需要一个定时器的标识作为参数,这样将关闭标识对应的定时器
延时调用和定时调用实际上是可以互相代替的,在开发中可以根据自己需要去选择
# 68. JSON
JavaScript Object Notation:JS对象表示法
- JS中的对象只有JS自己认识,其他的语言都不认识
- JSON就是一个特殊格式的字符串,这个字符串可以被任意的语言所识别,并且可以转换为任意语言中的对象,JSON在开发中主要用来数据的交互
- JSON和JS对象的格式一样,只不过JSON字符串中的属性名必须加双引号,其他的和JS语法一致
JSON分类:
- 对象 {}
- 数组 []
JSON中允许的值:
- 字符串
- 数值
- 布尔值
- null
- 对象
- 数组
JSON字符串和JS中的对象互相转换
在JS中,为我们提供了一个工具类,就叫JSON,这个对象可以帮助我们将一个JSON转换为JS对象,也可以将一个JS对象转换为JSON
var arr = '[1,2,3,"hello",true]';
var obj2 = '{"arr":[1,2,3]}';
var json = '{"name":"孙悟空","age":18,"gender":"男"}';
/*
* json --> js对象
* JSON.parse()
* - 可以将以JSON字符串转换为js对象
* - 它需要一个JSON字符串作为参数,会将该字符串转换为JS对象并返回
*/
var o = JSON.parse(json);
var o2 = JSON.parse(arr);
//console.log(o.gender);
//console.log(o2[1]);
var obj3 = {name:"猪八戒" , age:28 , gender:"男"};
/*
* JS对象 ---> JSON
* JSON.stringify()
* - 可以将一个JS对象转换为JSON字符串
* - 需要一个js对象作为参数,会返回一个JSON字符串
*/
var str = JSON.stringify(obj3);
//console.log(str);
/*
* JSON这个对象在IE7及以下的浏览器中不支持,所以在这些浏览器中调用时会报错
*/
var str3 = '{"name":"孙悟空","age":18,"gender":"男"}';
JSON.parse(str3);
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