抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

摘要:本文主要介绍了JS中常用的概念,以及基本语法。

1 简介

1.1 是什么

JS全称:JavaScript。

JS是一种脚本语言,命名和Java没有任何关系,用于给网页设置行为,比如点击、弹窗等等。

官方文档地址:

1.2 发展历史

JavaScript是由网景公司在1995年发明的,起初命名为LiveScript,后来由于SUN公司的介入更名为了JavaScript。

在1996年,微软公司在其最新的IE3浏览器中引入了自己对JavaScript的实现JScript。

于是在市面上存在两个版本的JavaScript,网景公司的JavaScript和微软的JScript,为了确保不同的浏览器上运行的JavaScript标准一致,几个公司定制了通用标准,名命为ECMAScript。

在一般情况下,会将这ECMAScript和JavaScript认作同一个意思,实际上JavaScript的含义要大一些,一个完整的JavaScript实现应该由以下三个部分构成:

  • ECMAScript:通用的标准,通常简写为ES。
  • DOM:文档对象模型,操作网页。
  • BOM:浏览器对象模型,操作浏览器。

2 基础

2.1 编写位置

因为JS是运行在浏览器中的,因此需要在网页中编写JS代码。

和CSS类似,JS也有三种位置可以选择。

2.1.1 行内脚本

直接写在元素内部,通过一些特殊的交互属性设置交互行为。

示例:

hello.html
1
<button onclick="alert('点击测试');">按钮</button>

这种方式使用简单,但是功能比较少,并且和网页的结构耦合,不能体现出结构和行为分离的思想,也不利于维护,不建议使用这种方式。

说明:alert()是一个函数,可以将传入的参数通过弹窗显示在页面上。

2.1.2 内部脚本

将JS提取出来,写在页面内部的script元素中。

示例:

hello.html
1
2
3
<script type="text/javascript">
alert('测试');
</script>

理论上可以将script元素放在页面的任何位置,建议放到head元素中。另外,也可以省略type属性。

和行内样式相比,这种方式编写的结构和行为分离,样式也能复用,但也没有做到完全分离。

2.1.3 外部脚本

将JS进一步提取,写在单独的JS文件中,在HTML页面中使用元素引用外部的JS文件。

创建JS文件,后缀为.js格式。示例:

hello.js
1
alert('测试');

在HTML页面引用CSS文件。示例:

hello.html
1
<script src="./hello.js"></script>

这种方式可维护高,并且做到了结构和行为分离,也能被其他页面复用,建议使用这种方式。

2.2 大小写敏感

JavaScript是严格区分大小写的,在编写代码是要注意。

2.3 注释

JavaScript的注释分为单行注释和多行注释:

  • 单行注释:
    js
    1
    2
    // 注释内容
    alert('测试');
  • 多行注释:
    js
    1
    2
    /* 注释内容 */
    alert('测试');

3 语法

3.1 标识符

所谓标识符,就是指变量、函数、属性的名字,以及函数的参数。

标识符可以是按照下列格式规则组合起来的一或多个字符:

  • 第一个字符必须是字母、下划线_或美元符号$
  • 其他字符可以是字母、下划线、美元符号或数字。

按照惯例,ECMAScript标识符采用驼峰命名法,但是JavaScript中的标识符不能是关键字和保留字符。

关键字:

function void return this new with
var instanceof typeof switch case default
if else do while for in
continue break try catch throw finally
delete debugger true false null

保留字符:

import export package public protected private
interface class enum extends implements super
let yield static const

其他不建议使用的标识符:

synchronize volatile abstract final native transient
float double long int short byte
char boolean throws arguments eval goto
undefined encodeURI decodeURI decodeURIComponent encodeURICOmponent isFinite
isNaN parseFloat parseInt NaN Number String
Boolean Object Date Array JSON RegExp
Infinity Function Math Error RangeError SyntaxError
ReferenceError TypeError EvalError URIError

3.2 数据类型

数据类型决定了一个数据的特征,比如123'123',直观上看这两个数据都是123,但实际上前者是一个数字,而后者是一个字符串。

对于不同的数据类型我们在进行操作时会有很大的不同。JavaScript中一共有五种基本数据类型:

  • 字符串型(String)
  • 数值型(Number)
  • 布尔型(Boolean)
  • null型(Null)
  • undefined型(Undefined)

这五种之外的类型都称为Object,所以总的来看JavaScript中共有六种数据类型。

使用typeof关键字检查数据可以得到数据的类型,返回结果是字符串类型:

  • 使用typeof 字符串判断会返回string
  • 使用typeof 数值判断会返回number
  • 使用typeof 布尔型判断会返回boolean
  • 使用typeof null判断会返回object
  • 使用typeof undefined判断会返回undefined

3.2.1 String

在JavaScript中字符串使用String类型表示,都需要使用引号引起来,可以使用单引号,也可以使用双引号,但必须成对匹配,不能混搭使用。

在某些情况下,如果想要将特殊的字符作为字符串,需要使用转义字符\,也可以使用HTML中的实体:

  • 使用&lt;表示<,使用&gt;表示>
  • 使用\'表示',使用\"表示"
  • 使用\n表示换行符
  • 使用\t表示制表符,可以实现缩进的效果
  • 使用\\表示\

转换为String有三种方式:

  • 使用toString()方法:
    js
    1
    2
    3
    4
    5
    6
    7
    8
    9
    var i = 1;
    alert(typeof i);// number
    alert(typeof i.toString());// string
    var m = null;
    alert(m.toString());// 页面报错,Null类型的变量不能调用方法
    alert(typeof m.toString());// 页面报错,Null类型的变量不能调用方法
    var n = undefined;
    alert(n.toString());// 页面报错,Undefined类型的变量不能调用方法
    alert(typeof n.toString());// 页面报错,Undefined类型的变量不能调用方法
  • 使用String()方法:
    js
    1
    2
    3
    4
    5
    6
    7
    8
    9
    var i = 1;
    alert(typeof i);// number
    alert(typeof String(i));// string
    var m = null;
    alert(String(m));// null
    alert(typeof String(m));// string
    var n = undefined;
    alert(String(n));// undefined
    alert(typeof String(n));// string
  • 拼接字符串:
    js
    1
    2
    3
    4
    5
    6
    7
    8
    9
    var i = 1;
    alert(typeof i);// number
    alert(typeof i + '1');// string
    var m = null;
    alert(m + '');// null
    alert(typeof m + '');// string
    var n = undefined;
    alert(n + '');// undefined
    alert(typeof n + '');// string

3.2.2 Number

在JavaScript中所有的数值都是Number类型,包括整数和浮点数:

  • 使用Number.MAX_VALUE表示数值的最大值,使用Number.MIN_VALUE表示数值大于0的最小值。
  • 使用Infinity表示超出数值最大值的正无穷,使用-Infinity表示负无穷。
  • 使用NaN表示非数字的数值,即Not a number

在对Infinity-Infinity以及NaN使用typeof判断时,也能得到number的结果。

有三个方法可以把变量转换为数值:

  • 使用Number()方法可以用来将变量转换为数值:
    js
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    var i = '1';
    alert(typeof i);// string
    alert(typeof Number(i));// number
    var a = true;
    alert(Number(a));// 1 true会返回1,false会返回0
    alert(typeof Number(a));// number
    var x = '1x';
    alert(Number(x));// NaN 非数值字符串会返回NaN
    alert(typeof Number(x));// number
    var m = null;
    alert(Number(m));// 0 null会返回0
    alert(typeof Number(m));// number
    var n = undefined;
    alert(Number(n));// NaN undefined会返回NaN
    alert(typeof Number(n));// number
  • 使用parseInt()方法可以用来将字符串转换为整数:
    js
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    var i = '1';
    alert(typeof i);// string
    alert(typeof parseInt(i));// number
    var f = '1.5';
    alert(parseInt(f));// 1 开头为数值的字符串会返回开头的整数部分,开头非数值的字符串会返回NaN
    alert(typeof parseInt(f));// number
    var x = '1x';
    alert(parseInt(x));// 1 开头为数值的字符串会返回开头的整数部分,开头非数值的字符串会返回NaN
    alert(typeof parseInt(x));// number
    var b = false;
    alert(parseInt(b));// NaN 非字符串会先转为字符串,开头非数值的字符串会返回NaN
    alert(typeof parseInt(b));// number
  • 使用parseFloat()方法可以用来将字符串转换为浮点数:
    js
    1
    2
    3
    4
    5
    6
    7
    8
    9
    var i = '1.5';
    alert(typeof i);// string
    alert(typeof parseFloat(i));// number
    var x = '1.5x';
    alert(parseFloat(x));// 1.5 开头为数值的字符串会返回开头的浮点数部分,开头非数值的字符串会返回NaN
    alert(typeof parseFloat(x));// number
    var b = false;
    alert(parseFloat(b));// NaN 非字符串会先转为字符串,开头非数值的字符串会返回NaN
    alert(typeof parseFloat(b));// number

在对浮点数进行计算时,可能会得到一个不精确的结果,所以在处理浮点数的运算时,需要使用特殊的方式保证得到的结果尽量精确,这里以后再说。

3.2.3 Boolean

在JavaScript中使用Boolean类型表示布尔型的数据,其取值只有truefalse两种。

使用Boolean()方法可以用来将变量转换为布尔值:

js
1
2
3
4
5
6
7
8
9
10
11
12
var i = NaN;
alert(Boolean(i));// false 非NaN且非0的数值会返回false,正数和负数会返回true,Infinity和-Infinity也会返回true
alert(typeof Boolean(i));// boolean
var x = '';
alert(Boolean(x));// false 空字符串会返回false,非空字符串会返回true
alert(typeof Boolean(x));// boolean
var m = null;
alert(Boolean(m));// false null会返回false
alert(typeof Boolean(m));// boolean
var n = undefined;
alert(Boolean(n));// false undefined会返回false
alert(typeof Boolean(n));// boolean

3.2.4 Null

使用Null表示空对象。

可以显示的将对象赋值为null来强制将对象设置为Null类型:

js
1
2
3
var person = null;
alert(person);// null
alert(typeof person);// object

3.2.5 Undefined

使用Undefined表示声明但未赋值的变量。

js
1
2
3
var person;
alert(person);// undefined
alert(typeof person);// undefined

3.3 变量

变量的作用是给某一个值或对象标注名称。

使用var关键字声明变量:

js
1
var i;

对声明的变量进行赋值:

js
1
i = 1;

在声明变量时赋值:

js
1
var i = 1;

支持对多个变量同时声明和赋值:

js
1
2
var x, y, z = 'z';
var m = 1, n = 2, l = 3;

3.3.1 重复声明

JavaScript允许对变量进行重复声明和赋值,也允许声明为不同的数据类型:

js
1
2
var i = 1;
var i = 'i';

在ES6以后,还可以使用let声明变量:

js
1
let i = 1;

通过var声明的变量称为全局变量,支持修改值和类型,支持重复声明。通过let声明的变量称为局部变量,局部变量支持修改值和类型,但不支持重复声明,建议在代码块中使用。

3.3.2 常量

在ES6以后,使用const声明常量:

js
1
const i = 1;

varlet声明的变量相比,常量一经声明和赋值,就不再支持修改值和类型,也不支持重复声明。

3.4 运算符

通过运算符可以对一个或多个值进行运算,并获取运算结果。

优先级:

. [] new
()
++ --
! ~
* / %
+ -
<< >> >>>
< <= > >=
== != === !===
&
^
|
&
^
|
&&
||
?:
= += -= *= /= %= <<= >>= >>>= &= ^= |=
,

3.4.1 算数运算符

在JavaScript中提供了以下几种算数运算符:

  • 使用+进行加法或拼接运算,如果拼接的是一个字符串,会将计算结果转为字符串
  • 使用-进行减法运算,如果涉及数值,会将结果转为数值
  • 使用*进行乘法运算,如果涉及数值,会将结果转为数值
  • 使用/进行除法运算,如果涉及数值,会将结果转为数值
  • 使用%进行取模运算

自增和自减运算符:

  • 使用++进行自增运算,根据运算符位置分为前置++i和后置i++
    js
    1
    2
    3
    4
    var i = 0;
    alert(++i);// 1 前置获取的是自增后的值
    alert(i++);// 1 后置获取的是自增前的值
    alert(i);// 2
  • 使用--进行自增运算,根据运算符位置分为前置--i和后置i--
    js
    1
    2
    3
    4
    var i = 2;
    alert(--i);// 1 前置获取的是自减后的值
    alert(i--);// 1 后置获取的是自减前的值
    alert(i);// 0

3.4.2 逻辑运算符

在JavaScript中提供了以下三种逻辑运算符:

  • 使用!表示逻辑非,用于对布尔值进行取反,对于非布尔值的变量会先将其转换为布尔值再取反。
  • 使用&&表示逻辑与,只有两个值都为true时,整个运算为true,返回第二个值。该运算符属于短路与,当第一个值为false时,整个运算为false,返回第一个值,不会判断第二个值。
  • 使用||表示逻辑或,只有两个值都为false时,整个运算为false,返回第二个值。该运算符属于短路或,当第一个值为true时,整个运算为true,返回第一个值,不会判断第二个值。

3.4.3 赋值运算符

在JavaScript中使用=进行赋值运算,可以使用简写:

  • 使用+=先计算后赋值,i += 5等同i = i + 5
  • 使用-=先计算后赋值,i -= 5等同i = i - 5
  • 使用*=先计算后赋值,i *= 5等同i = i * 5
  • 使用/=先计算后赋值,i /= 5等同i = i / 5
  • 使用%=先计算后赋值,i %= 5等同i = i % 5

3.4.4 比较运算符

通过比较运算符可以比较两个变量的大小关系:

  • 使用>大于号判断左侧的变量是否大于右侧的变量,成立返回true,否则返回false。
  • 使用<小于号判断左侧的变量是否小于右侧的变量,成立返回true,否则返回false。
  • 使用==等号判断两侧的变量是否相等,如果类型不一样,会先进行自动类型转换再比较,相等返回true,否则返回false。
  • 使用===全等号判断两侧的变量是否相等,相等返回true,否则返回false。不会进行自动类型转换。
  • 使用!=不等号判断两侧的变量是否不等,如果类型不一样,会先进行自动类型转换再比较,不等返回true,否则返回false。
  • 使用!==不全等号判断两侧的变量是否不等,不等返回true,否则返回false。不会进行自动类型转换。

对于非数值的变量进行比较判断时,会将变量转换为数值再比较,但当两侧的变量都是字符串时,会根据字符串的Unicode编码进行比较。

3.4.5 条件运算符

条件运算符也称为三元运算符,语法:

js
1
条件表达式?语句1:语句2;

运算逻辑:

  • 条件运算符在执行时,首先对条件表达式进行求值。
  • 如果该值为true,则执行语句1,并返回执行结果。如果该值为false,则执行语句2,并返回执行结果。
  • 如果条件表达式的求值结果是一个非布尔值,会将其转换为布尔值然后再运算。

3.4.6 移位运算符

移位运算符一般用于数值类型的变量,作用在数值补码的所有位,按位运算:

  • 使用&进行按位与运算,两个数值的相对位都为1,结果的对应位为1,否则结果的对应位为0
  • 使用|进行按位或运算,两个数值的相对位都为0,结果的对应位为0,否则结果的对应位为1
  • 使用^进行按位异或运算,两个数值的相对位不相同,结果的对应位为1,否则结果的对应位为0
  • 使用~进行按位非运算,对数值的每位都进行反转
  • 使用<<进行带符号左移运算,每位左移,右边补0。
  • 使用>>进行带符号右移运算,每位右移,左边补0,符号位使用原来的。
  • 使用>>>进行无符号右移运算,每位右移,左边补0,符号位补0。

移位运算改变的是数值的补码。对于正数来说,数值的原码是其补码。对于负数来说,数值的反码+1是其补码。

3.5 语句和代码块

表达式和运算符类似于单词和短语,语句是一条完整的命令,通常使用;结尾。

可以使用{}将多条语句包裹起来,称为代码块,只具有分组和排版的作用,没有其他意义。

3.6 条件语句

3.6.1 if…else语句

如果if中的条件成立,返回布尔值为true,则执行if后面代码块里的操作语句,否则执行else后面代码块里的操作语句:

js
1
2
3
4
5
if (条件表达式) {
条件成立的操作
} else {
条件不成立的操作
}

在if和else后面的代码块中,支持嵌套其他语句,如果嵌套的还是if…else语句,可以简写:

js
1
2
3
4
5
6
7
if (条件表达式1) {
条件1成立的操作语句
} else if (条件表达式2) {
条件1不成立但条件2成立的操作语句
} else {
条件1和条件2都不成立的操作语句
}

3.6.2 switch…case语句

也称为条件分支语句,会将switch后面的值同每个case后面的值相比较,相等就执行case后面的操作语句:

js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
switch (值) {
case1:
操作语句1
break;
case2:
操作语句2
break;
case3:
操作语句3
break;
default:
操作语句
break;
}

其中的break用于终止判断,如果没有break会在执行完当前case的操作语句后,继续判断后面case的值,直到遇到break或者判断结束。

如果所有switch的值和case后面的值都不相等,则执行default后面的操作语句。

3.7 循环语句

不管使用那种循环语句,都需要在适当位置跳过循环和终止循环:

  • 跳过循环:跳过本次循环,不执行后面的操作语句,直接进行条件判断,进行下一次循环,使用continue实现,一般在条件语句中使用:
    js
    1
    2
    3
    4
    5
    6
    7
    循环操作语句代码块 {
    操作语句1
    if (条件表达式) {
    continue;
    }
    操作语句2
    }
  • 终止循环:跳出循环,终止整个循环的执行,执行循环后面的代码,使用break实现,一般在条件语句中使用:
    js
    1
    2
    3
    4
    5
    6
    7
    循环操作语句代码块 {
    操作语句1
    if (条件表达式) {
    break;
    }
    操作语句2
    }

3.7.1 while语句

如果while后面的条件成立,则执行代码块中的操作语句,执行后重复判断是否成立,如果成立,则重复执行操作语句,只有当不成立时才终止循环:

js
1
2
3
while (条件表达式) {
条件成立的操作语句
}

还可以使用do…while语句,这种方式会先执行操作语句,然后再循环判断条件是否成立,以及循环执行操作语句,最终终止循环:

js
1
2
3
do {
条件成立的操作语句
} while (条件表达式)

相比较而言,while语句会先判断再执行,do…while语句会先执行再判断,能够保证至少执行一次操作语句。

但不管使用那种循环语句,都需要做好终止循环的判断逻辑,否则会导致死循环,严重情况会导致系统没有足够的资源而崩溃。

3.7.2 for语句

使用for语句可以更加明显的设置循环终止条件,但因此也显得比较繁琐:

js
1
2
3
for(初始化语句; 条件表达式; 更新语句) {
条件成立的操作语句
}

先执行初始化语句,可以省略,将初始化语句放在for循环前面执行。然后判断条件是否成立,可以省略,但需要在操作语句中控制终止循环的条件,类似while语句,否则会导致死循环。如果条件成立,会执行操作语句,否则终止循环。在操作语句执行结束后,执行更新语句,对循环条件更新,并循环判断条件是否成立,如果成立则循环执行操作语句,否则终止循环。

除了for语句代码块中的操作语句外,其他三个部分都是可以省略的,省略后就类似while语句了,需要手动控制循环。

3.8 嵌套循环

循环语句支持嵌套,在一个循环语句中支持嵌套另一个循环语句。

使用continue和break可以处理当前循环语句的循环逻辑,如果想处理上层循环语句的循环逻辑,需要配合label标签使用:

js
1
2
3
4
5
6
7
8
9
10
11
12
label1:
for(初始化语句; 条件表达式; 更新语句) {
循环1的操作语句
label2:
for(初始化语句; 条件表达式; 更新语句) {
循环2的操作语句
for(初始化语句; 条件表达式; 更新语句) {
循环3的操作语句
break label1;
}
}
}

使用label给循环打标签,在continue和break后面使用标签控制要操作的循环。示例:

js
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
// 大学数组
var universities = ['Peking University', 'Tsinghua University'];
// 学院数组
var colleges = ['College of Foreign Languages', 'College of Mathematics', 'College of Software'];
// 专业数组
var departments = [];
departments[0] = ['English', 'French', 'Russian'];
departments[1] = ['Statistics'];
departments[2] = ['Software Engineering'];
// 循环大学的标签,命名规范同标识符
university:
// 循环遍历大学
for(let l = 0; l < universities.length; l++) {
// 循环学院的标签
college:
// 循环遍历学院
for(let m = 0; m < colleges.length; m++) {
// 循环专业的标签,因为默认continue和break处理的是当前循环,所以这个标签可以省略
department:
// 循环遍历专业
for(let n = 0; n < departments[m].length; n++) {
// 如果是英语专业则进行提示
if (departments[m][n] == 'Russian') {
alert(universities[l] + '-' + colleges[m] + '-' + departments[m][n]);
// 跳过遍历专业,等同于不使用标签
// continue department;
// 跳过遍历学院
// continue college;
// 跳过遍历大学
continue university;
// 终止遍历专业,等同于不使用标签
// break department;
// 终止遍历学院
// break college;
// 终止遍历大学
// break university;
}
// 记录已遍历的专业
console.log(universities[l] + '-' + colleges[m] + '-' + departments[m][n]);
}
}
}

说明:console.log()是一个函数,可以将传入的参数打印到页面的控制台上。

4 对象

4.1 定义

JavaScript中的数据类型有六种,包括五种基本数据类型和一种引用数据类型。

五种基本数据类型:

  • String字符串
  • Number数值
  • Boolean布尔值
  • Null空值
  • Undefined未定义

使用Object对象来表示引用类型的数据,这是一种复合的数据类型,可以保存多个不同数据类型的属性。

4.2 使用

创建对象有两种方式:

  • 先创建,然后对属性赋值:
    js
    1
    2
    3
    4
    5
    6
    7
    var student = new Object();
    student.name = '张三';
    student.sex = '男';
    // 不能赋值特殊的属性名
    // student.'1 2 3' = 123;
    // 可以赋值特殊的属性名
    student['1 2 3'] = 123;
  • 在创建时对属性赋值:
    js
    1
    2
    3
    4
    5
    var student = {
    name:'张三',
    sex:'男',
    '1 2 3':123
    };

访问对象的属性:

js
1
2
3
4
5
6
7
8
9
10
var student = {
name:'张三',
sex:'男',
'1 2 3':123
};
console.log(student.name);// 张三
// 不能访问特殊的属性名
// console.log(student.'1 2 3');
// 可以访问特殊的属性名
console.log(student['1 2 3']);// 123

删除对象属性:

js
1
2
3
4
5
6
7
8
9
var student = {
name:'张三',
sex:'男',
'1 2 3':123
};
console.log(student);// { "name": "张三", "sex": "男", "1 2 3": 123 }
delete student['name'];
delete student['1 2 3'];
console.log(student);// { "sex": "男" }

在JavaScript中,对象的属性可以是任意类型的数据,包括对象的属性时另一个对象:

js
1
2
3
4
5
6
7
8
9
var student = {
name:'张三',
sex:'男'
};
student.friend = {
name:'李四',
sex:'男'
};
console.log(student);// { "name": "张三", "sex": "男", "friend": { "name": "李四", "sex": "男" } }

可以通过in关键字判断对象是否存在指定属性:

js
1
2
3
4
5
6
var student = {
name:'张三',
sex:'男'
};
console.log(student.age);// undefined
console.log('age' in student);// false

可以使用for…in语句循环遍历对象的属性:

js
1
2
3
4
5
6
7
8
var student = {
name:'张三',
sex:'男'
};
for(var attr in student) {
console.log('属性名 ' + attr);
console.log('属性值 ' + student[attr]);
}

4.3 堆栈

JavaScript在运行时数据是保存到栈内存和堆内存当中的。简单来说栈内存保存堆内存中对象的引用和基本类型数据,堆内存保存引用类型数据,也就是对象。

基本数据类型和引用数据类型的区别:

  • 对于基本数据类型的变量来说,在栈上创建栈内存用于存储数据,每个变量都是独立的栈内存,变量的修改互不影响:
    js
    1
    2
    3
    4
    var m = 100;
    var n = 100;
    m = 200;
    console.log(n);// 100
  • 对于引用数据类型的变量来说,在堆上创建堆内存用于存储对象,在栈上创建栈内存用于存储堆内存中对象的引用,对具有相同引用的对象的修改会互相影响:
    js
    1
    2
    3
    4
    5
    6
    7
    var zs = {
    name:'张三',
    age:'18'
    };
    var student = zs;
    student.age = 20;
    console.log(zs.age);// 20

在进行比较运算时的区别:

  • 在比较基本类型数据的时候,比较的是栈内存中的值。
  • 在比较引用类型数据的时候,比较的是栈内存中的引用地址。即使两个对象有完全相同的属性,但因为在堆内存是两个对象,就导致引用地址不同,两个对象也不同:
    js
    1
    2
    3
    4
    5
    6
    7
    8
    9
    var m = {
    name:'张三',
    age:'18'
    };
    var n = {
    name:'张三',
    age:'18'
    };
    console.log(m == n);// false

4.4 垃圾回收

垃圾回收(GC,Garbage Collection),是一种回收不再使用的对象内存的机制。

当一个对象没有任何的变量或属性对它进行引用,会导致无法操作该对象,这种对象就是一个垃圾,垃圾对象过多会占用大量的内存空间,导致程序运行变慢,所以这种垃圾必须进行清理。

JavaScript拥有自动的垃圾回收机制,会自动将这些垃圾对象从内存中销毁,开发人员不需要也不能进行垃圾回收的操作,只需要将不再使用的对象设置为null即可:

js
1
2
var obj = new Object();
obj = null;

4.5 分类

在JavaScript中可以将对象分为内部对象、宿主对象和自定义对象三种。

4.5.1 内部对象

内部对象包括String、Number、Boolean、Object、Function、Array、Date、Math、RegExp、Global,以及各种错误类对象,包括Error、EvalError、RangeError、ReferenceError、SyntaxError、TypeError。

其中Global和Math这两个对象又被称为内置对象,这两个对象在脚本程序初始化时被创建,不必实例化这两个对象。

4.5.2 宿主对象

宿主对象就是执行JavaScript的环境提供的对象。

对于嵌入到网页中的JavaScript来说,其宿主对象就是浏览器提供的对象,所以又称为浏览器对象,如IE、Firefox等浏览器提供的对象。不同的浏览器提供的宿主对象可能不同,即使提供的对象相同,其实现方式也大相径庭,这会带来浏览器兼容问题,增加开发难度。

浏览器对象有很多,如Window和Document等等。

4.5.3 自定义对象

顾名思义,就是开发人员自己定义的对象。JavaScript允许使用自定义对象,使应用及功能得到扩充。

5 内部对象

5.1 函数

5.1.1 定义

函数是封装了多条语句的代码块,这段代码块会让函数具有某种功能。

函数中的语句不会自动执行,需要在有需要的地方显示调用函数,在被调用时才会执行函数中的语句。

函数是一种Function类型的对象,使用typeof检查:

js
1
2
var fun = new Function();
console.log(typeof fun);// function

当将函数赋值给对象的某个属性时,将这个属性称为方法,即对象的方法对应的类型是函数。

5.1.2 使用

创建函数的方式:

  • 使用普通函数,支持多个参数:
    js
    1
    2
    3
    4
    function func(name) {
    console.log('test ' + name);
    }
    func('hello');
  • 使用函数表达式,创建匿名函数,并将函数赋值给变量:
    js
    1
    2
    3
    4
    var func = function(name) {
    console.log('test ' + name);
    };
    func('hello');
  • 使用函数的构造方法,支持多个参数:
    js
    1
    2
    var func = new Function('name',"console.log('test ' + name);");
    func('hello');
  • 使用构造函数,支持多个参数:
    js
    1
    2
    3
    4
    function Func(name) {
    console.log('test ' + name);
    }
    new Func('hello');

函数的组成部分:

  • 函数名:用于显示调用函数,可以省略函数名使用变量名调用,也可以同时省略函数名和变量名使用函数自调用:
    js
    1
    2
    3
    (function(name) {
    console.log(name);
    })('hello');
  • 入参:用于将数据传入到函数中进行处理,支持无参和有参,多个参数用,分隔,参数类型支持任意类型。在执行函数时会从左到右自动匹配参数,缺少的参数按照未定义处理:
    js
    1
    2
    3
    4
    var fun = function(name) {
    console.log(name);
    };
    fun();// undefined
  • 返回值:用于获取函数处理的结果。使用return关键字返回结果,返回结果支持任意类型,无返回结果按照未定义处理:
    js
    1
    2
    3
    4
    var fun = function(name) {
    console.log(name);
    };
    console.log(fun('hello'));// undefined

使用匿名函数自调用(IIFE,Immediately Invoked Function Expression)的好处是隐藏了内部实现,不污染外部命名空间。

5.1.3 作用域

作用域通常用于形容变量,指的是变量的有效范围。

在JavaScript中一共有两种作用域:

  • 全局作用域,在script元素内部声明的变量,而不是在某个方法内部声明的变量,都在全局作用域,这种变量称为全局变量。
  • 局部作用域,在方法内部创建的变量,只在方法内部有效,这种变量称为局部变量。

全局变量的特点:

  1. 在页面打开时创建,在页面关闭时销毁。
  2. 可以直接使用由浏览器创建的window全局对象,代表浏览器的窗口,可以直接使用其属性和方法。
  3. 全局变量在页面的任意地方都可以访问。

局部变量的特点:

  1. 在方法调用时创建,在方法执行结束后销毁。
  2. 只能在方法内部使用。

只有在方法内部使用关键字声明变量,该变量才是局部变量,否则就是全局变量:

js
1
2
3
4
5
6
7
8
9
10
11
var name = '张三';
var sex = '男';
function fun() {
console.log(name);// undefined 使用局部变量,声明提升但未初始化
var name = '李四';
console.log(sex);// 男 未声明变量,使用全部变量
sex = '女';
}
fun();
console.log(name);// 张三 全局变量未被修改
console.log(sex);// 女 全局变量被修改

当全局变量和局部变量名称相同时,在方法中使用的是局部变量:

js
1
2
3
4
5
6
7
var name = '张三';
function fun() {
console.log(name);// undefined 使用局部变量,声明提升但未初始化
var name = '李四';
}
fun();
console.log(name);// 张三 全局变量未被修改

常用的全局函数:

js
1
2
3
4
// 对URI进行编码
console.log(encodeURIComponent('localhost:8080/test?name=test'));// localhost%3A8080%2Ftest%3Fname%3Dtest
// 对URI进行解码
console.log(decodeURIComponent('localhost%3A8080%2Ftest%3Fname%3Dtest'));// localhost:8080/test?name=test

5.1.4 声明提升

在JavaScript中,函数及变量的声明都将被提升到函数的最顶部,变量可以先使用再声明。

在ES6引入let和const的声明方式后,只有var声明的变量才支持声明提升,并且使用函数表达式声明的函数变量也不支持声明提升。

声明提升只是将声明提前了,并没有将初始化的操作提前:

js
1
2
console.log(name);// undefined
var name = '张三';

5.1.5 内部属性

在函数内部,有两个特殊的对象:

  • arguments:该对象实际上是一个类数组对象,有数组的特性,但本质上是Object对象,用于保存函数的参数,同时该对象还有一个属性callee来表示当前函数。
  • this:引用的是一个对象,用来表示函数执行的上下文,一般是函数的调用者。根据函数调用方式的不同,引用对象也会有所不同。

通过arguments对象可以获取传入的参数,即使函数没有定义入参:

js
1
2
3
4
5
6
7
8
9
10
11
function test() {
console.log(arguments);// Arguments []
console.log(arguments instanceof Array);// false
console.log(arguments instanceof Object);// true
console.log(arguments[0]);// 1
console.log(arguments[1]);// 2
console.log(arguments.length);// 5
console.log(arguments.callee);// function test() {}
console.log(arguments.callee == test);// true
}
test(1, 2, 3, 4, 5);

说明:instanceof关键字可以用来判断左侧的变量是否属于右侧的类型。

5.1.6 构造函数

构造函数就是一个普通的函数,创建方式和普通函数没有区别,不同的是,构造函数习惯上首字母大写:

js
1
2
function Student() {
}

在调用函数时,普通函数可以直接调用,构造函数需要使用new关键字调用:

js
1
2
3
4
5
6
7
8
function Student(name, sex) {
this.name = name;
this.sex = sex;
}
var student = new Student('张三', '男');
console.log(student);// { "name": "张三", "sex": "男" } 构造函数调用
var student = Student('张三', '男');
console.log(student);// undefined 普通函数调用,this表示window对象,没有name属性

也可以通过instanceof关键字判断是不是构造函数调用:

js
1
2
3
4
5
6
7
8
9
10
11
function Student(name, sex) {
if (this instanceof Student) {
console.log('构造函数调用');
this.name = name;
this.sex = sex;
} else {
console.log('普通函数调用');
}
}
new Student('张三', '男');// 构造函数调用
Student('张三', '男');// 普通函数调用

使用同一个构造函数创建的对象,称为一类对象。所以也将构造函数称为类,同时将通过构造函数创建的对象,称为该类的实例。

5.1.7 原型对象

JavaScript是一门面向对象的语言,而且它还是一个基于原型的面向对象的语言。

原型:

  • 所有函数都有prototype属性的对象,称为原型。
  • 所有对象(包括原型和函数,函数也是对象)都有__proto__属性的对象,可以通过这个对象访问其构造方法的原型。
  • 通过函数prototype属性获取原型的方式称为显示调用,通过对象__proto__属性获取原型的方式称为隐式调用。
  • 默认情况下,原型是一个Object对象,该对象只包含constructor属性和__proto__属性:
    001-原型

说明:

  • 原型的constructor属性指向函数:
    js
    1
    2
    function func() {}
    console.log(func.prototype.constructor === func);// true
  • 原型的__proto__属性在浏览器里显示为[[Prototype]]属性,对应Object的prototype属性:
    js
    1
    2
    function func() {}
    console.log(func.prototype.__proto__ === Object.prototype);// true

原型链:

  • 原型链又称为隐式原型链,隐式调用的原型会形成原型链,顶端是Object显示调用的原型,该原型如果继续通过隐式调用获取原型会返回null:
    js
    1
    console.log(Object.prototype.__proto__);// null
  • 所有对象(包括原型和函数,函数也是对象)都是Object的实例,任何对象的原型链都能追溯到Object显示调用的原型:
    js
    1
    2
    3
    function func() {}
    console.log(func.__proto__ === Function.prototype);// true
    console.log(func.__proto__.__proto__ === Object.prototype);// true
  • 所有方法(包括Object和Function)都是Function的实例,任何方法隐式调用的原型都是Function显示调用的原型:
    js
    1
    2
    3
    function func() {}
    console.log(func.__proto__ === Function.prototype);// true
    console.log(Object.__proto__ === Function.prototype);// true

当访问对象的属性和方法时,首先在对象自身空间中寻找,如果没有,会在原型链上寻找,如果找不到会返回undefined:

js
1
2
3
4
5
6
7
8
9
function Student() {
}
Student.prototype.name = '学生类';
Student.prototype.age = 18;
var student = new Student();
student.name = '学生实例';
console.log(student.name);// 学生实例
console.log(student.age);// 18
console.log(student.test);// undefined

在调用toString()方法时,在没有重写的情况下,调用的实际上是Object的原型对象的方法:

js
1
2
3
4
5
function Student() {
}
var student = new Student();
console.log(student.toString());// [object Object]
console.log(student.hasOwnProperty('toString'));// false

在使用in关键字和for…in语句循环遍历对象的属性时,也会访问原型对象中的属性。

可以使用hasOwnProperty()方法判断对象自身是否包含指定属性:

js
1
2
3
4
5
6
7
8
function Student() {
}
Student.prototype.name = '学生类';
Student.prototype.age = 18;
var student = new Student();
student.name = '学生实例';
console.log(student.hasOwnProperty('name'));// true
console.log(student.hasOwnProperty('age'));// false

5.1.8 函数对象方法

当将函数作为对象赋值给变量时,这个对象即使函数对象,函数对象可以通过自身调用函数,也可以通过call()方法和apply()方法调用。

通过方法调用时,传入的第一个参数会被作为函数的调用者,即作为函数里的this对象:

js
1
2
3
4
5
6
7
8
var test = function() {
console.log(this);
}
test();// Window {}
test.call();// Window {}
test.apply();// Window {}
test.call(123);// Number {123}
test.apply(123);// Number {123}

两个方法的区别在于对入参上的处理,第二个参数会作为入参:

js
1
2
3
4
5
var test = function(first, last) {
console.log(first + ' ' + last);
}
test.call(test, 'John', 'Smith');// John Smith 入参是可变参数
test.apply(test, ['John', 'Smith']);// John Smith 人参是数组

5.1.9 箭头函数

箭头函数是在ES6中添加的一种规范:

  • 省略了function关键字,箭头左侧表示入参,只有当入参只有一个时,才可以省略小括号
  • 省略了return关键字,箭头右侧是返回语句,只有当函数直接返回表达式时,才可以省略大括号

使用:

js
1
2
3
4
5
6
// 使用箭头函数
var func = (x) => x * x;
// 使用普通函数
var func = function(x) {
return x * x;
}

如果返回值是对象,需要使用括号包裹:

js
1
2
var func = (x) => ({result: x * x});
console.log(func(5));// {result: 25}

5.2 数组

5.2.1 定义

数组也是对象的一种,数组是一种用于表达有顺序关系的数据的集合的语言结构。

数组和普通对象功能类似,也用来存储多个值。不同的是普通对象使用字符串作为属性名,而数组使用数字来作为索引操作元素。

索引是从0开始的整数,用于获取数组对应位置的数据。

数组可以存放任意类型的数据,可以在一个数组中存放不同类型的数据。

5.2.2 使用

创建数组有两种方式:

  • 先创建,然后插入数据:
    js
    1
    2
    3
    4
    5
    6
    var arr = new Array();
    arr[0] = 1;
    arr[1] = 2;
    arr[2] = 3;
    console.log(arr);// [1, 2, 3]
    console.log(typeof arr);// object
  • 在创建时插入数据:
    js
    1
    2
    3
    4
    5
    var arr = new Array(1, 2, 3);
    // 也可以使用这种方式
    // var arr = [1, 2, 3];
    console.log(arr);// [1, 2, 3]
    console.log(typeof arr);// object

删除数组数据:

js
1
2
3
4
var arr = [1, 2, 3];
console.log(arr);// [1, 2, 3]
delete arr[1];
console.log(arr);// [1, 空, 3]

访问数组数据:

js
1
2
3
var arr = [1, 2, 3];
console.log(arr[0]);// 1
console.log(arr[3]);// undefined

遍历数组数据:

  • 使用for…in循环遍历:
    js
    1
    2
    3
    4
    var arr = [1, 2, 3];
    for (var i in arr) {
    console.log(arr[i]);
    }
  • 使用forEach循环遍历:
    js
    1
    2
    3
    4
    var arr = [1, 2, 3];
    arr.forEach(function(i, e) {
    console.log(i + ' > ' + e);
    });

数组的属性:

js
1
2
3
4
var arr = [1, 2, 3];
console.log(arr.constructor);// Array() {[native code]}
console.log(arr.length);// 3
console.log(arr.__proto__);// []

数组的方法:

js
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
var arr = [1, 2, 3];
// 删除数组的最后一个元素,并返回删除的元素
var del = arr.pop();
console.log(del);// 3
console.log(arr);// [1, 2]
// 向数组的末尾添加元素,并返回数组的新的长度
var len = arr.push(4, 5);
console.log(len);// 4
console.log(arr);// [1, 2, 4, 5]
// 删除数组的第一个元素,并返回删除的元素
var del = arr.shift();
console.log(del);// 1
console.log(arr);// [2, 4, 5]
// 向数组开头添加元素,并返回新的数组长度
var len = arr.unshift(-2, -1);
console.log(len);// 5
console.log(arr);// [-2, -1, 2, 4, 5]
// 颠倒数组顺序
arr.reverse();
console.log(arr);// [5, 4, 2, -1, -2]
// 对数组元素进行排序,默认按照字母顺序
arr.sort();
console.log(arr);// [-1, -2, 2, 4, 5]
// 对数组元素进行排序,指定排序方式
arr.sort(function(m, n) {
return m - n;
});
console.log(arr);// [-2, -1, 2, 4, 5]
// 选择指定范围的字符串,前闭后开,不改变原数组,第一个参数是起始位置,第二个参数是结束位置
console.log(arr);// [-2, -1, 2, 4, 5]
// 空参选择全部
var sli = arr.slice();
console.log(sli);// [-2, -1, 2, 4, 5]
// 一个参数,选择起始位置及其之后的元素
var sli = arr.slice(1);
console.log(sli);// [-1, 2, 4, 5]
// 参数是负数则加上长度计算
var sli = arr.slice(-1);
console.log(sli);// [5]
// 两个参数,选择定位之间的元素
var sli = arr.slice(1, 3);
console.log(sli);// [-1, 2]
// 删除数组中的指定元素,并返回删除的元素,第一个参数是起始位置,第二个参数是删除数量,第三个及以后的参数是插入到起始位置之前的元素
console.log(arr);// [-2, -1, 2, 4, 5]
// 空参不删除任何元素
var spli = arr.splice();
console.log(spli);// []
// 一个参数,删除起始位置的元素
// var spli = arr.splice(1);
// console.log(spli);// [-1, 2, 4, 5]
// 参数是负数则加上长度计算
// var spli = arr.splice(-1);
// console.log(spli);// [5]
// 两个参数,删除起始位置之后数量的元素
// var spli = arr.splice(1, 3);
// console.log(spli);// [-1, 2, 4]
// 两个参数,删除起始位置之后数量的元素,插入元素到起始位置之前
// var spli = arr.splice(1, 3, 0, 1);
// console.log(spli);// [-1, 2, 4]

5.3 日期

在JavaScript中使用Date对象表示日期:

js
1
2
3
4
5
6
7
var now = new Date();
console.log(typeof now);// object
console.log(now);// Wed Jul 03 2024 10:30:10 GMT+0800 (中国标准时间)
now = new Date('1/31/2008');// 入参支持MM/dd/yyyy日期格式
console.log(now);// Thu Jan 31 2008 00:00:00 GMT+0800 (中国标准时间)
now = new Date('1/31/2008 10:00:00');// 入参支持MM/dd/yyyy HH:mm:ss日期时间格式
console.log(now);// Thu Jan 31 2008 10:00:00 GMT+0800 (中国标准时间)

日期的属性:

js
1
2
3
var now = new Date();
console.log(now.constructor);// ƒ Date() {[native code]}
console.log(now.__proto__);// {}

日期的方法:

js
1
2
3
4
5
6
7
8
9
10
var now = new Date();
console.log(Date.now());// 时间戳,获取从1970年1月1日至今所过的毫秒数
console.log(now.getFullYear());// 2024 获取Date对象的年份
console.log(now.getDay());// 3 获取Date对象的星期,0表示周日
console.log(now.getMonth());// 6 获取Date对象的月份,0表示1月
console.log(now.getDate());// 3 获取Date对象在月份的第几日
console.log(now.getHours());// 10 获取Date对象的小时,0表示0点和24点
console.log(now.getMinutes());// 30 获取Date对象的分钟,0表示0分和60分
console.log(now.getSeconds());// 10 获取Date对象的秒数,0表示0秒和60秒
console.log(now.getMilliseconds());// 100 获取Date对象的毫秒

5.4 数学相关

JavaScript为数学计算封装了一个Math对象,和其他的对象不同,Math不是一个构造函数,属于一个工具类,不用创建对象,里边封装了数学运算相关的属性和方法。

Math的属性:

js
1
2
3
4
5
6
7
8
9
console.log(typeof Math);// object
console.log(Math.E);// 2.718... 获取算术常量e,即自然对数的底数
console.log(Math.LN2);// 0.693... 获取2的自然对数
console.log(Math.LN10);// 2.302... 获取10的自然对数
console.log(Math.LOG2E);// 1.442... 获取以2为底的e的对数
console.log(Math.LOG10E);// 0.434... 获取以10为底的e的对数
console.log(Math.PI);// 3.141... 获取圆周率
console.log(Math.SQRT1_2);// 0.707... 获取2的平方根的倒数
console.log(Math.SQRT2);// 1.414... 获取2的平方根

Math的方法:

js
1
2
3
4
5
6
7
console.log(Math.abs(-1));// 1 获取绝对值
console.log(Math.ceil(-1.2));// -1 向上取整
console.log(Math.floor(-1.2));// -2 向下取整
console.log(Math.round(-1.2));// -1 四舍五入
console.log(Math.random());// 0.5 生成0到1的随机数,不包括0和1
console.log(Math.max(0, 1, 2));// 2 获取最大值
console.log(Math.min(0, 1, 2));// 0 获取最小值

5.5 包装类

JavaScript提供了三个包装类,通过这三个包装类可以将基本数据类型的数据转换为对象:

  • String:可以将基本数据类型字符串转换为String对象。
  • Number:可以将基本数据类型的数字转换为Number对象。
  • Boolean:可以将基本数据类型的布尔值转换为Boolean对象。

在实际应用中不会使用基本数据类型的对象,如果使用基本数据类型的对象,因为对象在栈中存储的是对象的引用,所以在进行比较时会导致与预期不一致的结果:

js
1
2
3
console.log(1 == 1);// true 基本数据类型之间的比较使用栈上的值
console.log(1 == new Number(1));// true 基本数据类型与包装类之间的比较会发生自动拆箱,比较栈上的值
console.log(new Number(1) == new Number(1));// false 包装类之间的比较使用栈上的引用。

5.5.1 布尔值

布尔值的属性:

js
1
2
3
var boo = new Boolean(true);
console.log(boo.constructor);// ƒ Boolean() {[native code]}
console.log(boo.__proto__);// Boolean {}

布尔值的方法:

js
1
2
var boo = new Boolean(true);
console.log(boo.valueOf());// true 获取原始值

5.5.2 数字

数字的属性:

js
1
2
3
4
5
var num = new Number(0);
console.log(num.constructor);// ƒ Number() {[native code]}
console.log(num.__proto__);// Number {}
console.log(Number.MIN_VALUE);// 5e-324
console.log(Number.MAX_VALUE);// 1.7976931348623157e+308

数字的方法:

js
1
2
3
4
5
6
7
8
9
10
11
console.log(Number.isNaN('1'));// false 判断指定参数是否为NaN,只有当参数是数字且为NaN才会返回true,参数非数字和非NaN的数字会返回false
console.log(Number.isFinite(1));// false 判断指定参数是否为无穷大
console.log(Number.isInteger(1));// true 判断指定参数是否为整数
console.log(new Number(1.159).toFixed(2));// 1.16 获取指定小数位数的字符串,采用四舍五入(银行家舍入)策略,无参会返回整数字符串,参数范围是1到100
console.log(new Number(1.615).toFixed(2));// 1.61 不是严格的四舍五入,严格四舍五入可以使用Math.round()方法实现,或者缩放某个倍数
console.log(new Number(10).toFixed(4));// 10.0000 精度不足时会进行补位,常用于需要统一精度的场景
console.log(new Number(1.159).toPrecision(3));// 1.16 获取指定位数的字符串,采用四舍五入(银行家舍入)策略,无参会返回原数字字符串,参数范围是1到100
console.log(new Number(1.615).toPrecision(3));// 1.61 不是严格的四舍五入,严格四舍五入可以使用Math.round()方法实现,或者缩放某个倍数
console.log(new Number(0.159).toPrecision(2));// 0.16 整数部分为0时,指定位数不包括整数部分
console.log(new Number(10).toPrecision(6));// 10.0000 精度不足时会进行补位,常用于需要统一精度的场景
console.log(new Number(10).valueOf());// 10 获取原始值

5.5.3 字符串

字符串的属性:

js
1
2
3
4
var str = new String('hello');
console.log(str.constructor);// ƒ String() {[native code]}
console.log(str.length);// 5
console.log(str.__proto__);// String {}

字符串的方法:

js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var str = new String('hello');
console.log(str.indexOf('l'));// 2 获取首次出现的位置,找不到返回-1
console.log(str.indexOf('l', 3));// 3 获取首次出现的位置,从指定位置开始,包含指定位置
console.log(str.lastIndexOf('l'));// 3 获取最后出现的位置,从右往左查找,找不到返回-1
console.log(str.lastIndexOf('l', 2));// 2 获取最后出现的位置,从右往左查找
console.log(str.charAt(1));// e 获取指定位置的字符,指定位置超出长度返回空串
console.log(str.charCodeAt(1));// 101 获取指定位置的字符编码,即Unicode编码
console.log(str.match('l'));// ['l', ...] 查找匹配的字符串,返回匹配的数组,支持正则表达式,找不到返回null
console.log(str.search('l'));// 2 获取首次出现的位置,支持正则表达式,找不到返回-1
console.log(str.replace('l', ''));// helo 查找首个匹配第一个参数的字符串,并替换为第二个参数指定的字符串,不改变原字符串
console.log(str.replaceAll('l', ''));// heo 查找全部匹配第一个参数的字符串,并替换为第二个参数指定的字符串,不改变原字符串
console.log(str.concat(' ', 'world'));// hello world 获取拼接字符串,支持可变参数,不改变原字符串
console.log(str.slice(1, 3));// el 获取指定范围的字符串,不改变原字符串,第一个参数是起始位置,第二个参数是结束位置,前闭后开
console.log(str.slice(1));// ello 获取指定范围的字符串,不改变原字符串,只有一个参数会获取到末尾
console.log(str.slice(-1));// o 获取指定范围的字符串,不改变原字符串,负数参数会从后往前查找
console.log(str.substring(1, 3));// el 和slice类似,区别是不支持负数参数,负数参数会替换为0,并且参数会自动排序,保证前小后大
console.log(str.split());// ['hello'] 根据字符将字符串拆分为数组,无参或字符不存在会将整个字符串作为数组的一个元素,支持正则表达式
console.log(str.split(''));// ['h', 'e', 'l', 'l', 'o'] 空串将每个字符串作为数组的一个元素
console.log(str.split('ell'));// ['h', 'o'] 拆分后指定的字符被删除
console.log(str.toLowerCase());// hello 获取小写字符串,不改变原字符串
console.log(str.toUpperCase());// HELLO 获取大写字符串,不改变原字符串

5.6 正则表达式

5.6.1 定义

在JavaScript中使用RegExp对象表示正则表达式,正则表达式是用于从字符串中选择特定字符串的文本。

5.6.2 创建

创建正则表达式有两种方式:

  • 使用构造方法创建,第一个参数是表达式,第二个参数是可选的修饰符,如果表达式有特殊字符,需要使用\进行转义:
    js
    1
    2
    3
    // var patt = new RegExp(pattern, modifiers);
    var reg = new RegExp('123');
    console.log(typeof reg);// object
  • 直接创建,同样需要两个参数,但是使用/分隔:
    js
    1
    2
    3
    // var reg = /pattern/modifiers;
    var reg = /123/;
    console.log(typeof reg);// object

如果需要动态创建正则表达式,需要使用构造方法创建。

在创建正则表达式以后,其内部维护了一个lastIndex索引,记录下一次匹配从哪个位置开始。

5.6.3 方法

使用test()方法判断是否匹配内容:

js
1
2
3
var reg = /123/;
var result = reg.test('123a4a123a5a');// 判断参数是否包含正则表达式匹配的字符串,返回true表示包含,返回false表示不包含
console.log(result);// true

使用exec()方法获取匹配内容:

js
1
2
3
4
5
6
7
var reg = /123/;
var result = reg.exec('123a4a123a5a');// 返回从参数中匹配到的字符串,返回值是数组对象,对象内容和全局匹配修饰符有关
console.log(result);// ['123', index: 0, input: '123a4a123a5a', groups: undefined]
console.log(result.length);// 1 返回对象的数组长度
console.log(result.index);// 0 返回匹配到的起始位置
console.log(result.groups);// undefined 返回匹配到的捕获分组
console.log(reg.lastIndex);// 0 未使用全局匹配修饰符时,匹配到就结束了,不会匹配下一个

使用字符串的match()方法获取匹配内容,和正则表达式的exec()方法相同:

js
1
2
3
var reg = /123/;
var result = '123a4a123a5a'.match(reg);
console.log(result);// ['123', index: 0, input: '123a4a123a5a', groups: undefined]

5.6.4 修饰符

修饰符用于对匹配方式进行说明,修饰符可以省略,但修饰符之前的/不能省略:

  • i:执行对大小写不敏感的匹配,默认大小写敏感
  • g:执行全局匹配,默认匹配到第一个停止
  • m:执行多行匹配,默认匹配第一行

如果没有使用g全局修饰,会在匹配到第一个停止,返回包含匹配信息的数组对象,并且exec()方法和match()方法获取的结果相同。

如果使用了g全局修饰,会匹配所有满足的内容,但是exec()方法和match()方法获取的结果不同。

使用exec()方法执行有全局修饰的正则表达式,返回从lastIndex开始匹配到的内容数组,匹配一次后返回匹配的内容并暂停:

js
1
2
3
4
5
6
7
8
9
10
var reg = /123/g;
var result = reg.exec('123a4a123a5a');
console.log(result);// ['123', index: 0, input: '123a4a123a5a', groups: undefined]
console.log(reg.lastIndex);// 3 记录本次匹配结束时的索引,下次匹配从这个位置开始
var result = reg.exec('123a4a123a5a');
console.log(result);// ['123', index: 6, input: '123a4a123a5a', groups: undefined]
console.log(reg.lastIndex);// 9 记录本次匹配结束时的索引,下次匹配从这个位置开始
var result = reg.exec('123a4a123a5a');
console.log(result);// null 匹配结束
console.log(reg.lastIndex);// 0 匹配结束

使用test()方法也会更新lastIndex的值,如果不注意这一点,可能会出问题:

js
1
2
3
4
5
6
7
var reg = /123/g;
var result = reg.test('123a4a123a5a');
console.log(reg.lastIndex);// 3 第一次匹配
var result = reg.exec('123a4a123a5a');
console.log(reg.lastIndex);// 9 第二次匹配
var result = reg.exec('123a4a123a5a');
console.log(reg.lastIndex);// 0 匹配结束 虽然执行了一次exec()方法,但实际上已经匹配两次了

使用字符串的match()方法执行有全局修饰的正则表达式,返回匹配到的内容数组,匹配全部后结束:

js
1
2
3
4
var reg = /123/g;
var result = '123a4a123a5a'.match(reg);
console.log(result);// ['123', '123']
console.log(reg.lastIndex);// 0 匹配结束

5.6.5 字符串方法

字符串中可以使用正则表达式的方法:

js
1
2
3
4
5
6
7
var str = new String('hello');
console.log(str.match(/l/));// ['l', index: 2, input: 'hello', groups: undefined]
console.log(str.match(/l/g));// ['l', 'l'] 全局匹配会获取全部匹配的内容
console.log(str.search(/l/));// 2
console.log(str.replace(/l/, ''));// helo
console.log(str.replaceAll(/l/g, ''));// heo 替换全部时,修饰符必须有全局匹配
console.log(str.split(/ll/));// ['he', 'o']

5.6.6 量词

表达式中可以使用量词,使用n表示任意字符:

js
1
2
3
4
5
6
7
8
9
10
11
12
13
var str = 'hello';
console.log(str.match(/el+/g));// ['ell'] 使用n+匹配包含至少一个n的字符串
console.log(str.match(/hl+/g));// null 至少包含一个n
console.log(str.match(/el*/g));// ['ell'] 使用n*匹配包含零个或多个n的字符串
console.log(str.match(/hl*/g));// ['h'] 可以不包含n
console.log(str.match(/el?/g));// ['el'] 使用n?匹配包含零个或一个n的字符串
console.log(str.match(/hl?/g));// ['h'] 可以不包含n
console.log(str.match(/l{2}/g));// ['ll'] 使用n{X}匹配包含X个n的字符串
console.log(str.match(/l{1,2}/g));// ['ll'] 使用n{X,Y}匹配至少包含X个至多包含Y个n的字符串,Y可以省略
console.log(str.match(/lo$/g));// ['lo'] 使用n$匹配任何结尾为n的字符串
console.log(str.match(/^he/g));// ['he'] 使用^n匹配任何开头为n的字符串
console.log(str.match(/e(?=l)/g));// ['e'] 使用?=n匹配任何后面紧跟n的字符串
console.log(str.match(/h(?!l)/g));// ['h'] 使用?=n匹配任何后面紧跟n的字符串

在具有量词匹配的表达式中,使用贪婪模式和非贪婪模式:

js
1
2
3
var str = '123123';
console.log(str.match(/1.*3/g));// ['123123'] 默认开启贪婪模式,获取能匹配到的最多的内容
console.log(str.match(/1.*?3/g));// ['123', '123'] 使用?开启非贪婪模式,获取能匹配到的最少的内容

5.6.7 范围

表达式中可以使用方括号限制查找某个范围的字符串,实际上比较的是ASCII码:

js
1
2
3
4
5
6
7
var str = 'ab12CD';
console.log(str.match(/[abCD]/g));// ['a', 'b', 'C', 'D'] 查找方括号之间的任何字符
console.log(str.match(/[^abCD]/g));// ['1', '2'] 查找不在方括号之间的任何字符
console.log(str.match(/[0-9]/g));// ['1', '2'] 查找0-9之间的数字
console.log(str.match(/[a-z]/g));// ['a', 'b'] 查找a-z之间的字符,即小写英文字母
console.log(str.match(/[A-Z]/g));// ['C', 'D'] 查找A-Z之间的字符,即大写英文字母
console.log(str.match(/[A-z]/g));// ['a', 'b', 'C', 'D'] 查找A-z之间的字符,即所有英文字母,因为在ASCII码中,大写字母在小写字母前面

5.6.8 特殊字符

表达式中可以使用元字符替代特殊字符进行查找:

js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
console.log('ab12_!+'.match(/./g));// ['a', 'b', '1', '2', '_', '!', '+'] 查找单个字符,除了换行和行结束符
console.log('ab12_!+'.match(/\w/g));// ['a', 'b', '1', '2', '_'] 查找单词字符,包括数字、字母、下划线
console.log('ab12_!+'.match(/\W/g));// ['!', '+'] 查找非单词字符
console.log('ab12_!+'.match(/\d/g));// ['1', '2'] 查找数字字符
console.log('ab12_!+'.match(/\D/g));// ['a', 'b', '_', '!', '+'] 查找非数字字符
console.log('ab12_!+'.match(/\s/g));// null 查找空白字符,包括空格符、回车符、换行符、换页符、制表符、垂直制表符
console.log('ab12_!+'.match(/\S/g));// ['a', 'b', '1', '2', '_', '!', '+'] 查找非空白字符
console.log('hello world'.match(/\bwo/g));// ['wo'] 查找单词边界字符,即位于单词开头和结尾的字符
console.log('hello world'.match(/\Blo/g));// ['lo'] 查找非单词边界字符
console.log(''.match(/\0/g));// null 查找NULL字符
console.log(''.match(/\n/g));// null 查找换行符
console.log(''.match(/\r/g));// null 查找回车符
console.log(''.match(/\f/g));// null 查找换页符
console.log(''.match(/\t/g));// null 查找制表符
console.log(''.match(/\v/g));// null 查找垂直制表符

5.6.9 捕获分组

在正则表达式中使用()有两个作用:

  • 将被包裹的内容进行单独匹配,用于形成捕获分组
  • 括号后的量词会将括号视为整体

在未使用全局修饰的情况下,使用exec()方法获取匹配内容:

js
1
2
3
var reg = /(123)(a.a)/;
var result = reg.exec('123a4a123a5a');// 在使用捕获分组时,数组第一个元素是完整的匹配内容,后面的元素是捕获的元素
console.log(result);// ['123a4a', '123', 'a4a', index: 0, input: '123a4a123a5a', groups: undefined]

在未使用全局修饰的情况下,使用字符串的match()方法获取匹配内容,和正则表达式的exec()方法相同:

js
1
2
3
var reg = /(123)(a.a)/;
var result = '123a4a123a5a'.match(reg);
console.log(result);// ['123a4a', '123', 'a4a', index: 0, input: '123a4a123a5a', groups: undefined]

在使用全局修饰的情况下,使用exec()方法获取匹配内容:

js
1
2
3
4
5
6
7
8
9
10
var reg = /(123)(a.a)/g;
var result = reg.exec('123a4a123a5a');
console.log(result);// ['123a4a', '123', 'a4a', index: 0, input: '123a4a123a5a', groups: undefined]
console.log(reg.lastIndex);// 6 记录本次匹配结束时的索引,下次匹配从这个位置开始
var result = reg.exec('123a4a123a5a');
console.log(result);// ['123a5a', '123', 'a5a', index: 6, input: '123a4a123a5a', groups: undefined]
console.log(reg.lastIndex);// 12 记录本次匹配结束时的索引,下次匹配从这个位置开始
var result = reg.exec('123a4a123a5a');
console.log(result);// null 匹配结束
console.log(reg.lastIndex);// 0 匹配结束

在使用全局修饰的情况下,使用字符串的match()方法获取匹配内容:

js
1
2
3
4
var reg = /(123)(a.a)/g;
var result = '123a4a123a5a'.match(reg);
console.log(result);// ['123a4a', '123a5a']
console.log(reg.lastIndex);// 0 匹配结束

6 文档对象模型

6.1 定义

文档对象模型(DOM,Document Object Model),在JavaScript中通过DOM操作HTML页面。

DOM将HTML页面映射为一个多节点模型,每个元素和属性都是节点:

  • 文档本身就是文档节点,使用document对象表示,作为window对象的属性存在的,不用获取可以直接使用。
  • 注释是注释节点。
  • 元素是元素节点。
  • 元素内的属性是属性节点。
  • 元素内的文本是文本节点。元素之间的空白也是文本节点。

当网页被加载时,浏览器会创建页面的DOM树:
002-页面DOM树

节点的通用属性:

  • nodeName:代表当前节点的名字,只读属性。元素节点返回大写的标签名,属性节点返回属性名,文本节点返回#text字符串。
  • nodeType:返回一个整数,这个数值代表着给定节点的类型,只读属性。元素节点返回1,属性节点返回2,文本节点返回3。
  • nodeValue:返回给定节点的当前值,可读写的属性。元素节点返回null,属性节点返回属性值,文本节点返回文本节点的内容。

6.2 节点

6.2.1 文档节点

查询元素节点的方法,需要使用文档节点document对象调用:

js
1
2
3
4
var home = document.getElementById('home');// 通过元素的id属性查找元素节点
home = document.getElementsByName('home');// 通过元素的name属性查找元素节点,返回多个匹配的节点
home = document.getElementsByClassName('home');// 通过元素的calss属性查找元素节点,返回多个匹配的节点,支持元素节点调用
home = document.getElementsByTagName('div');// 通过元素的标签名查找元素节点,返回多个匹配的节点,支持元素节点调用

除了通过id属性查找返回的是对象外,其余三个返回的均为伪数组:

js
1
2
3
4
5
6
7
8
9
10
11
var home = document.getElementById('home');
console.log(home);// <span id="home">home-id</span>
home = document.getElementsByName('home');
console.log(home);// NodeList [span]
console.log(Array.prototype.slice.call(home));// [span]
home = document.getElementsByClassName('home');
console.log(home);// HTMLCollection [span.home]
console.log(Array.prototype.slice.call(home));// [span.home]
home = document.getElementsByTagName('div');
console.log(home);// HTMLCollection [div]
console.log(Array.prototype.slice.call(home));// [div]

文档节点的属性:

js
1
2
3
4
console.log(document.title);// 获取文档标题
console.log(document.URL);// 获取文档URL
console.log(document.referrer);// 获取文档referrer,即前文档的URL
console.log(document.domain);// 获取文档域名

使用文档节点操作节点:

js
1
2
3
4
5
console.log(document.querySelector('#home'));// 使用CSS选择器查找元素节点,返回第一个元素节点
console.log(document.querySelectorAll('#home'));// 使用CSS选择器查找元素节点,返回全部元素节点
var newDiv = document.createElement('div');// 创建元素节点,入参是标签名
var newName = document.createAttribute('name');// 创建属性节点,入参是属性名
var newText = document.createTextNode('text');// 创建文本节点,入参是文本内容

6.2.2 元素节点

元素节点的属性:

js
1
2
3
4
5
6
7
8
var home = document.getElementById('home');
console.log(home.children);// 获取当前节点的所有子节点,只获取元素节点
console.log(home.childNodes);// 获取当前节点的所有子节点,包括元素节点和非元素节点
console.log(home.firstChild);// 获取当前节点的第一个子节点,包括元素节点和非元素节点
console.log(home.lastChild);// 获取当前节点的最后一个子节点,包括元素节点和非元素节点
console.log(home.parentNode);// 获取当前节点的父节点
console.log(home.previousSibling);// 获取当前节点的前一个兄弟节点,包括元素节点和非元素节点
console.log(home.nextSibling);// 获取当前节点的后一个兄弟节点,包括元素节点和非元素节点

通过元素节点获取其他节点:

  • 通过firstChild属性获取的第一个节点通常是文本节点
  • 通过getAttributeNode(属性名)方法获取指定属性节点,通常不使用属性节点

获取和修改元素节点的属性:

js
1
2
3
4
5
var home = document.getElementById('home');
console.log(home.id);// 获取id属性
console.log(home.class);// 获取class属性
home.id = 'home-id';// 修改id属性
home.id = 'home-class';// 修改class属性

操作元素节点:

js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var home = document.getElementById('home');
// 操作属性
console.log(home.getAttribute('id'));// 通过属性名获取属性
console.log(home.getAttributeNode('id'));// 通过属性名获取属性节点
home.setAttribute('name', 'home');// 通过属性名设置属性
home.setAttributeNode(document.createAttribute('name'));// 设置属性节点
home.removeAttribute('name');// 通过属性名删除属性
home.removeAttributeNode(home.getAttributeNode('name'));// 删除属性节点
// 操作子节点
var newDiv = document.createElement('div');// 创建元素节点
var newText = document.createTextNode('text');// 创建文本节点
home.appendChild(newDiv);// 添加子节点,新的字节点会添加到末尾子节点的后面
home.insertBefore(newText, home.childNodes[0]);// 添加子节点,新的字节点会添加到首位子节点的前面
home.removeChild(home.childNodes[0]);// 删除子节点
home.replaceChild(newText, home.childNodes[0]);// 替换子节点

操作元素样式:

js
1
2
3
4
5
6
7
8
9
10
11
12
13
var home = document.getElementById('home');
home.style['fontSize'] = "16px";// 修改行内样式
console.log(home.style.fontSize);// 获取行内样式,需要将分隔命名转为驼峰命名
// 获取元素样式,包括内部样式和外部样式,兼容写法,不支持修改
if (window.getComputedStyle) {
// 大部分浏览器兼容的方式,第二个参数是伪元素
var fontSize = getComputedStyle(home, null)['fontSize'];
console.log(fontSize);
} else {
// IE8及以下
var fontSize = home.currentStyle['fontSize'];
console.log(fontSize);
}

6.2.3 属性节点

属性节点的属性:

js
1
2
3
4
5
var home = document.getElementById('home');
var homeName = home.getAttributeNode('name');
console.log(homeName.name);// 获取属性名
console.log(homeName.value);// 获取属性值
homeName.value = 'name';// 设置属性值

6.3 事件

6.3.1 使用

事件就是用户和浏览器之间的交互行为,比如点击、移动。

事件可以写在HTML的元素内,也可以写在JavaScript里:

  • 写在HTML的元素里,不建议使用这种方式:
    html
    1
    <span id="home" onclick="alert('span');">
  • 写在JavaScript里,建议使用这种方式:
    js
    1
    2
    3
    4
    var home = document.getElementById('home');
    home.onclick = function() {
    alert('span');
    }

当事件的响应函数被触发时,浏览器每次都会将一个事件对象作为实参传递给响应函数,在事件对象中封装了当前事件相关的一切信息。

在使用IE浏览器时,如果版本小于IE8,响应函数被触发时,浏览器不会传递事件对象,而是将事件对象作为window对象的属性保存。

兼容IE和其他浏览器的方式:

js
1
2
3
4
5
6
7
// 获取事件对象,兼容写法
event = event || window.event;
var home = document.getElementById('home');
// 传入事件对象,可以省略
home.onclick = function(event) {
alert('span');
}

常用事件:

js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var home = document.getElementById('home');
// 鼠标点击时执行
home.onclick = function() {
alert('span');
}
// 元素获取焦点时执行
home.onfocus = function() {
alert('span');
}
// 元素失去焦点时执行
home.onblur = function() {
alert('span');
}
// 页面加载完后执行
window.onload = function() {
alert('span');
}

使用target属性获取触发事件的元素:

js
1
2
3
4
5
6
7
// 获取事件对象,兼容写法
event = event || window.event;
var home = document.getElementById('home');
home.onclick = function(event) {
var obj = event.target;
alert(obj.tagName);
}

6.3.2 事件的传播

关于事件的传播网景公司和微软公司有不同的理解:

  • 微软公司认为事件应该是由内向外传播,也就是当事件触发时,应该先触发当前元素上的事件,然后再向当前元素的祖先元素上传播,也就说事件应该在冒泡阶段执行。
  • 网景公司认为事件应该是由外向内传播的,也就是当前事件触发时,应该先触发当前元素的最外层的祖先元素的事件,然后在向内传播给后代元素。

W3C综合了两个公司的方案,将事件传播分成了三个阶段:

  • 捕获阶段:在捕获阶段时从最外层的祖先元素,向目标元素进行事件的捕获,但是默认此时不会触发事件。
  • 目标阶段:事件捕获到目标元素,捕获结束开始在目标元素上触发事件。
  • 冒泡阶段:事件从目标元素向他的祖先元素传递,依次触发祖先元素上的事件。

IE8及以下的浏览器中没有捕获阶段,其他浏览器在调用方法时处理。

6.3.3 事件的冒泡

事件的冒泡,指的是事件的向上传导,当后代元素上的事件被触发时,其祖先元素的相同事件也会被触发。

如果不希望发生事件冒泡可以取消冒泡:

js
1
2
3
4
5
6
7
8
9
10
// 获取事件对象,兼容写法
event = event || window.event;
var home = document.getElementById('home');
home.onclick = function(event) {
alert('span');
// 已弃用,不建议
event.cancelBubble = true;
// 建议
event.stopPropagation();
}

取消冒泡并不会取消元素的默认动作,比如超链接的默认跳转,可以使用preventDefault()方法取消默认动作:

js
1
2
3
4
5
6
7
8
// 获取事件对象,兼容写法
event = event || window.event;
var home = document.getElementById('home');
home.onclick = function(event) {
alert('a');
// 取消跳转,但不能阻止冒泡
event.preventDefault();
}

既可以取消冒泡,又可以取消默认动作:

js
1
2
3
4
5
6
7
8
// 获取事件对象,兼容写法
event = event || window.event;
var home = document.getElementById('home');
home.onclick = function(event) {
alert('a');
// 取消跳转,阻止冒泡
return false;
}

6.3.4 事件的绑定

给元素绑定事件有两种方式:

  • 通过元素.事件 = 函数的方式绑定,一个事件只支持绑定一个函数,后面的会覆盖前面的:
    js
    1
    2
    3
    4
    var home = document.getElementById('home');
    home.onclick = function() {
    alert('span');
    }
  • 通过方法绑定,一个事件可以绑定多个函数,但是需要兼容不同的浏览器:
    js
    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
    var home = document.getElementById('home');
    // 在页面加载后绑定
    window.onload = function() {
    bindClick(home, 'click', 'first');
    bindClick(home, 'click', 'last');
    };
    // 通用的绑定方法,将handle()方法绑定到传入的对象上
    function bindClick(obj, eventStr, name) {
    if (obj.addEventListener) {
    // 大部分浏览器兼容的方式,需要使用没有on前缀的事件
    obj.addEventListener(eventStr, function() {
    console.log(this);// 在addEventListener()方法中,this对象是绑定的事件对象
    handle(name);
    }, false);// 如果希望在捕获阶段就触发事件,可以设置为true,一般为false
    } else {
    // IE8及以下,需要使用有on前缀的事件
    obj.attachEvent("on" + eventStr, function() {
    console.log(this);// 在attachEvent()方法中,this对象是window对象
    handle.call(obj, name);// 调用回调函数,强制将this对象设为绑定的事件对象
    });
    }
    }
    // 通用的执行方法
    function handle(name) {
    console.log(name);
    }

7 浏览器对象模型

7.1 定义

浏览器对象模型(BOM,Browser Object Model),允许JavaScript与浏览器交互。

BOM提供了一组对象用于对浏览器进行操作:

  • Window:代表的是整个浏览器的窗口,同时window也是网页中的全局对象。
  • Navigator:代表的当前浏览器的信息,通过该对象可以来识别不同的浏览器。
  • Location:代表当前浏览器的地址栏信息,通过Location可以获取地址栏信息,或者操作浏览器跳转页面。
  • History:代表浏览器历史记录,可以通过该对象来操作浏览器的历史记录。由于隐私原因,该对象不能获取到具体的历史记录,只能操作浏览器向前或向后翻页。而且该操作只在当次访问时有效。
  • Screen:代表用户的屏幕的信息,通过该对象可以获取到用户的显示器的相关的信息。

这些BOM对象(全局对象)在浏览器中都是作为window对象的属性保存的,可以通过window对象来使用,也可以直接使用。

7.2 使用

7.2.1 Window对象

Window对象的属性和方法可以省略直接使用。

Window对象属性:

js
1
2
3
4
5
console.log(window.document);// 返回Document对象的只读引用
console.log(window.navigator);// 返回Navigator对象的只读引用
console.log(window.location);// 返回Location对象的只读引用
console.log(window.history);// 返回History对象的只读引用
console.log(window.screen);// 返回Screen对象的只读引用

Window对象方法:

js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 关闭浏览器窗口
close();
// 打开新的浏览器窗口
open('','_blank','width=200,height=100');
// 显示带有消息和确认按钮的警告框
alert('警告框');
// 显示带有消息以及确认按钮和取消按钮的对话框
confirm('确认框');
// 按照指定的时间执行定时函数
var obj = setTimeout(function(name) {
console.log('3秒后打印 ' + name);
}, 3000, 'test');
// 取消设置的定时函数,在执行前有效
clearTimeout(obj);
// 按照指定的时间(以毫秒计)重复调用函数
var id = 1;
var obj = setInterval(function(name) {
console.log(id++ + ' ' + name);
if (id > 5) {
// 取消设置的重复调用函数
clearInterval(obj);
}
}, 100, 'test');

7.2.2 Navigator对象

Navigator对象属性:

js
1
2
3
4
5
6
7
console.log(navigator.appName);// 返回浏览器的名称
console.log(navigator.appCodeName);// 返回浏览器的代码名
console.log(navigator.lappVersioncation);// 返回浏览器的平台和版本信息
console.log(navigator.platform);// 返回运行浏览器的操作系统平台
console.log(navigator.userAgent);// 返回由客户机发送服务器的代理信息
console.log(navigator.language);// 返回浏览器使用的语言
console.log(navigator.product);// 返回浏览器使用的引擎(产品)

由于历史原因,Navigator对象中的大部分属性都已经不能识别浏览器了,一般只使用userAgent来判断浏览器的信息。

7.2.3 Location对象

Location对象属性:

js
1
2
3
4
5
6
7
8
console.log(location.hash);// 返回URL的锚部分
console.log(location.host);// 返回URL的主机名和端口
console.log(location.hostname);// 返回URL的主机名
console.log(location.href);// 返回完整的URL
console.log(location.pathname);// 返回的URL路径名
console.log(location.port);// 返回URL服务器使用的端口号
console.log(location.protocol);// 返回URL协议
console.log(location.search);// 返回URL的查询部分

Location对象方法:

js
1
2
3
location.assign();// 载入新的文档,相当于给location对象赋值
location.reload(true);// 重新加载当前页面,相当于刷新,参数为true表示清空缓存
location.replace();// 用新的文档替换当前文档,不能使用历史记录,不能使用后退

7.2.4 History对象

History对象属性:

js
1
console.log(location.length);// 返回历史列表中的网址数

History对象方法:

js
1
2
3
location.back();// 加载历史列表中的前一个URL
location.forward();// 加载历史列表中的下一个URL
location.go(1);// 加载历史列表中的某个具体页面,参数大于0时前进,参数小于0时后退

7.2.5 Screen对象

Screen对象属性:

js
1
2
console.log(screen.height);// 返回屏幕的总高度
console.log(screen.width);// 返回屏幕的总宽度

评论