JavaScript 是 web 开发的一个重要部分,它控制了网页的行为,与 HTML 和 CSS 一起定义了网页。并且 JS 也应用在了很多其他的地方,因为及其重要,所以需要单独进行学习。这里主要研究 html 里使用 js。
JS 写在哪里
执行 js 命令有三种方式,行内 js 、内部 js 、外部 js。
js 同时支持单、双引号成对使用,效果是一样的。
注释
html 的注释使用 <!-- 注释内容 -->
js 的单行注释可以使用两个斜杠 \\ … 注释内容
js 的多行注释使用斜杠加星号 \* … *\
行内 js
js 是事件驱动型,行内 js 一般跟在一个事件定义中,表示触发此事件所进行的行为。行内 js 需要被引号引起来,并且以 javascript:
开头,表示之后是 js 命令。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>js使用方式1:行内js</title>
</head>
<body>
<!--onclick:点击触发一个事件,alert:弹出一个对话框-->
<input type="button" value="点击有惊喜" onclick="javascript:alert('哈哈哈哈')">
<!-- 停止超链接 a 标签的作用 -->
<a href="javascript:void(0)">我是一个超链接</a>
</body>
</html>
行内 js 作用范围只在标签内部。
内部 js
内部 js 会在页面加载后依次执行其代码,而不需要事件。内部 js 的作用范围为整个 html 文档。
内部 js 写在 <script> 块中,而 <script> 块一般包含在 <head> 块或 <body> 块中。通常具体写在哪个块中是没有影响的,但是由于页面的加载和执行是从上到下的,所以写在 head 块中的代码会先于 body 执行(通常 head 块会写在 body 块之前,但如果反过来写也是可以的)。因为加载的同时会执行代码,如果执行 head 块内部的 js 代码时,因为没有加载 body 块,所以一些代码可能会执行出错,例如立刻查找、调用一些元素及其属性等。所以碰到这些情况时需要注意代码写的位置对执行顺序的影响。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>js使用方式2:内部js</title>
<script type="text/javascript">
//声明一个函数(整个文档都可以使用)
function surprise() {
alert('恭喜你中了一百万')/*弹出框*/
}
</script>
</head>
<body>
<input type="button" value="点击有惊喜" onclick="surprise()"><!--调用函数-->
<input type="button" value="点击" onclick="surprise()">
</body>
</html>
外部 js
可以在 <script> 标签内添加 src 属性,指向一个 js 文件,则引入了此外部 js 文件。当此文件被引入时,会依次执行其代码。其作用范围为整个引用的 html 文档。外部的 js 文件是纯 js 代码,不需要使用 <script> 块。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>js使用方式3:外部js</title>
<!-- 在html页面调用外部js文件-->
<script src="../js/test.js" type="text/javascript" charset="utf-8">
</script>
</head>
<body>
<!-- 此时调用的函数为外部js文件中的函数 -->
<input type="button" value="点击" onclick="test()">
</body>
</html>
JS 基础语法
语句
js 的语句由分号;
进行分隔(但是这不是必须的,浏览器中执行JS的引擎会自动补分号),换行和缩进对语句没有影响(如果不使用分号分隔则会有影响),只是方便阅读。由于自动添加分号某些情况下会改变程序的语义,所以推荐不要省略分号。
大小写
js 是大小写敏感的
代码块
js 的代码块,例如函数体、if else 的执行代码等是用花括号 { }
包裹的。
折行
js 可以使用反斜杠进行折行
变量
变量名是大小写英文、数字、 $ 和 _ 的组合,且不能用数字开头。变量名也可以用中文,但是,请不要给自己找麻烦。
声明
js 通常使用 var 来声明一个变量,在 ES6 标准中增加了 const 和 let 声明方式。声明变量时不用声明变量的数据类型,其数据类型在赋值时决定。声明变量时不赋值,则其值为未定义(undefined)。可以在一次声明中确定多个变量,使用逗号分隔(可以跨行)。
var 、let、const 及作用域
在函数外使用 var 声明的变量其作用域是当前文档,即若在 html 文件内是全局的(可以垮 <script> 块),在 js 文件内则只在当前文件有效。
另外创建变量是使用直接赋值的方式(即直接给未声明过的变量赋值,没有使用关键字定义),则创建的变量成为 window 的一个可配置属性,它是全局变量。
函数内使用 var 声明的变量是局部的,作用域为当前函数。对于函数内部的代码块(例如 if else 等),var 声明的变量作用域是当前函数,而使用 let 声明的变量作用域为当前代码块。
另外因为函数能够嵌套,所以内部能够调用外部变量,反之则不行。如果内外部变量名重名,则优先使用内部定义的变量,忽略外部定义的变量。
const 声明的变量必须初始化,即在声明时赋值。const 声明的变量不能够被改变,即成为常量。const 的作用域同 let。需注意 const 声明的常量并非完全无法改变,它声明的对象或数组是可以修改其中的成员或元素的,但是无法修改对象/数组本身(即不能重新给变量赋值)。
strict 模式
由于 js 设计初,为了方便初学者使用并不强制要求声明变量,造成的全局变量容易引起冲突和错误的问题,ECMA 在后续规范中推出了 strict 模式。此模式称为严格模式,在此模式下,未声明的变量进行使用会出错。启用strict模式的方法是在JavaScript代码的第一行写上 'use strict'
。严格模式的限制有:
- 不允许使用未声明的变量
- 不允许删除变量或对象
- 不允许删除函数
- 不允许变量重名
- 不允许使用八进制
- 不允许使用转义字符(非字符串内部)
- 不允许对只读属性赋值
- 不允许对一个使用getter方法读取的属性进行赋值
- 不允许删除一个不允许删除的属性
- 变量名不能使用 “eval” 和 “arguments” 字符串
- 由于一些安全原因,在作用域 eval() 创建的变量不能被调用
- 禁止this关键字指向全局对象
生存周期
变量的生存周期跟随其作用域,全局变量的生存周期直到页面关闭。
解构赋值
ES6 开始支持解构赋值,直接对多个变量同时赋值
var [x, y, z] = ['hello', 'JavaScript', 'ES6'];
如果数组本身还有嵌套,也可以通过下面的形式进行解构赋值,注意嵌套层次和位置要保持一致
let [x, [y, z]] = ['hello', ['JavaScript', 'ES6']];
解构赋值还可以忽略某些元素
let [, , z] = ['hello', 'JavaScript', 'ES6']; // 忽略前两个元素,只对z赋值第三个元素
如果需要从一个对象中取出若干属性,也可以使用解构赋值,便于快速获取对象的指定属性
var person = {
name: '小明',
age: 20,
gender: 'male',
passport: '12345678',
school: 'No.3 middle school'
};
var {name, age, passport} = person;
对一个对象进行解构赋值时,同样可以直接对嵌套的对象属性进行赋值,只要保证对应的层次是一致的
var person = {
name: '小明',
age: 20,
gender: 'male',
passport: 'G-12345678',
school: 'No.4 middle school',
address: {
city: 'Beijing',
street: 'No.1 Road',
zipcode: '100001'
}
};
var {name, address: {city, zip}} = person;
name; // '小明'
city; // 'Beijing'
zip; // undefined, 因为属性名是zipcode而不是zip
// 注意: address不是变量,而是为了让city和zip获得嵌套的address对象的属性:
address; // Uncaught ReferenceError: address is not defined
使用解构赋值对对象属性进行赋值时,如果对应的属性不存在,变量将被赋值为 undefined ,这和引用一个不存在的属性获得 undefined 是一致的。如果要使用的变量名和属性名不一致,可以用下面的语法获取
var person = {
name: '小明',
age: 20,
gender: 'male',
passport: 'G-12345678',
school: 'No.4 middle school'
};
// 把passport属性赋值给变量id:
let {name, passport:id} = person;
name; // '小明'
id; // 'G-12345678'
// 注意: passport不是变量,而是为了让变量id获得passport属性:
passport; // Uncaught ReferenceError: passport is not defined
解构赋值还可以使用默认值,这样就避免了不存在的属性返回 undefined 的问题
var person = {
name: '小明',
age: 20,
gender: 'male',
passport: 'G-12345678'
};
// 如果person对象没有single属性,默认赋值为true:
var {name, single=true} = person;
name; // '小明'
single; // true
有些时候,如果变量已经被声明了,再次赋值的时候,正确的写法也会报语法错误。这是因为JavaScript引擎把 { 开头的语句当作了块处理,于是 = 不再合法。解决方法是用小括号括起来:
// 声明变量:
var x, y;
// 解构赋值:
{x, y} = { name: '小明', x: 100, y: 200};
// 语法错误: Uncaught SyntaxError: Unexpected token =
// 应写为
({x, y} = { name: '小明', x: 100, y: 200});
解构赋值在很多时候可以大大简化代码。例如,交换两个变量 x 和 y 的值,可以这么写,不再需要临时变量。
var x=1, y=2;
[x, y] = [y, x];
快速获取当前页面的域名和路径
var {hostname:domain, pathname:path} = location;
数据类型
js 的数据类型分为 值类型(基本类型) 和 引用数据类型(对象类型) 。
- 值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、空(Null)、未定义(Undefined)、Symbol。
- 引用数据类型(对象类型):对象(Object)、数组(Array)、函数(Function),还有两个特殊的对象:正则(RegExp)和日期(Date)。
js 拥有动态数据类型,即变量可用作不同的数据类型(例如字符串类型的变量赋值为数字时,就变为数值类型)。js 可以使用 typeof 关键字来查看具体的数据类型。
是JavaScript的对象有个小问题,就是键必须是字符串。但实际上Number或者其他数据类型作为键也是非常合理的。为了解决这个问题,最新的ES6规范引入了新的数据类型 Map,类似 python 的字典类型。另外 ES6 也了 Set ,即集合类型。同时为了方便使用 Map 和 Set ,引入了 iterable ,即可迭代类型。
另外还有个特别的数据类型 json 对象。
字符串 string
字符串是引号(单双均可)包裹的任意文本。ES6 中可以使用两个反引号 `
来包裹多行字符串。
拼接字符串
js 可以使用加号 +
来把文本值或字符串变量加起来(连接起来),连接是直接拼接,没有任何分隔。将字符串和数值相加,会将数值转为字符串再进行拼接。
y="5"+5; // 结果 55
z="Hello"+5; // 结果 Hello5
如果有很多变量需要连接,用 + 号就比较麻烦。ES6新增了一种模板字符串,表示方法和上面的多行字符串一样,但是它会自动替换字符串中的变量。
var name = '小明';
var age = 20;
var message = `你好,${name},你今年是不是${age}岁了?`;
alert(message);
字符串的操作
字符串可以当成数组,使用索引(下标)获取具体的字符。需要注意的是字符串是不可变的,如果对字符串的某个索引赋值,不会有错误,但是也没任何效果。
字符串中可以使用一些转义字符
代码 | 输出 |
---|---|
’ | 单引号 |
" | 双引号 |
\ | 反斜杠 |
\n | 换行 |
\r | 回车 |
\t | tab(制表符) |
\b | 退格符 |
\f | 换页符 |
字符串可以当成 String 对象使用,它会有一些属性和方法。调用这些方法本身不会改变原有的字符串,而是返回一个新的字符串。
属性 | 描述 |
---|---|
constructor | 对创建该对象的函数的引用 |
length | 字符串的长度 |
prototype | 允许您向对象添加属性和方法 |
方法 | 描述 |
---|---|
charAt() | 返回在指定位置的字符。 |
charCodeAt() | 返回在指定的位置的字符的 Unicode 编码。 |
concat() | 连接两个或更多字符串,并返回新的字符串。 |
endsWith() | 判断当前字符串是否是以指定的子字符串结尾的(区分大小写)。 |
fromCharCode() | 将 Unicode 编码转为字符。 |
indexOf() | 返回某个指定的字符串值在字符串中首次出现的位置。 |
includes() | 查找字符串中是否包含指定的子字符串。 |
lastIndexOf() | 从后向前搜索字符串,并从起始位置(0)开始计算返回字符串最后出现的位置。 |
match() | 查找找到一个或多个正则表达式的匹配。 |
repeat() | 复制字符串指定次数,并将它们连接在一起返回。 |
replace() | 在字符串中查找匹配的子串,并替换与正则表达式匹配的子串。 |
replaceAll() | 在字符串中查找匹配的子串,并替换与正则表达式匹配的所有子串。 |
search() | 查找与正则表达式相匹配的值。 |
slice() | 提取字符串的片断,并在新的字符串中返回被提取的部分。 |
split() | 把字符串分割为字符串数组。 |
startsWith() | 查看字符串是否以指定的子字符串开头。 |
substr() | 从起始索引号提取字符串中指定数目的字符。 |
substring() | 提取字符串中两个指定的索引号之间的字符。 |
toLowerCase() | 把字符串转换为小写。 |
toUpperCase() | 把字符串转换为大写。 |
trim() | 去除字符串两边的空白。 |
toLocaleLowerCase() | 根据本地主机的语言环境把字符串转换为小写。 |
toLocaleUpperCase() | 根据本地主机的语言环境把字符串转换为大写。 |
valueOf() | 返回某个字符串对象的原始值。 |
toString() | 返回一个字符串。 |
数值 number
js 只有一种数字类型,可以带小数也可以不带,即不区分整数和浮点。注意有几个特殊的 Number 类型:
- NaN : Not a Number,当无法计算结果时用 NaN 表示(例如 0 / 0)
- Infinity : 无限大,当数值超过了 JS 的 Number 所能表示的最大值时就表示为Infinity(例如 2 / 0)
数字对象的常用属性和方法有
属性 | 描述 |
---|---|
constructor | 返回对创建此对象的 Number 函数的引用。 |
MAX_VALUE | 可表示的最大的数。 |
MIN_VALUE | 可表示的最小的数。 |
NEGATIVE_INFINITY | 负无穷大,溢出时返回该值。 |
NaN | 非数字值。 |
POSITIVE_INFINITY | 正无穷大,溢出时返回该值。 |
prototype | 允许您可以向对象添加属性和方法。 |
EPSILON | 表示 1 和比最接近 1 且大于 1 的最小 Number 之间的差别,ES6新增 |
MIN_SAFE_INTEGER | 表示在 JavaScript中最小的安全的 integer 型数字 (-(253 - 1)),ES6新增 |
MAX_SAFE_INTEGER | 表示在 JavaScript 中最大的安全整数(253 - 1),ES6新增 |
方法 | 描述 |
---|---|
isFinite | 检测指定参数是否为无穷大。 |
isInteger | 检测指定参数是否为整数。 |
isNaN | 检测指定参数是否为 NaN。 |
isSafeInteger | 检测指定参数是否为安全整数。 |
toExponential(x) | 把对象的值转换为指数计数法。 |
toFixed(x) | 把数字转换为字符串,结果的小数点后有指定位数的数字。 |
toLocaleString(locales, options) | 返回数字在特定语言环境下的表示字符串。 |
toPrecision(x) | 把数字格式化为指定的长度。 |
toString() | 把数字转换为字符串,使用指定的基数。 |
valueOf() | 返回一个 Number 对象的基本数字值。 |
Number.isInteger() | 用来判断给定的参数是否为整数。 |
Number.isSafeInteger() | 判断传入的参数值是否是一个"安全整数"。 |
Math 对象
Math 对象用于执行数学任务,因为并不像 Date 和 String 那样是对象的类,因此没有构造函数 Math()。
Math 对象常用的属性和方法有
属性 | 描述 |
---|---|
E | 返回算术常量 e,即自然对数的底数(约等于2.718)。 |
LN2 | 返回 2 的自然对数(约等于0.693)。 |
LN10 | 返回 10 的自然对数(约等于2.302)。 |
LOG2E | 返回以 2 为底的 e 的对数(约等于 1.4426950408889634)。 |
LOG10E | 返回以 10 为底的 e 的对数(约等于0.434)。 |
PI | 返回圆周率(约等于3.14159)。 |
SQRT1_2 | 返回 2 的平方根的倒数(约等于 0.707)。 |
SQRT2 | 返回 2 的平方根(约等于 1.414)。 |
方法 | 描述 |
---|---|
abs(x) | 返回 x 的绝对值。 |
acos(x) | 返回 x 的反余弦值。 |
asin(x) | 返回 x 的反正弦值。 |
atan(x) | 以介于 -PI/2 与 PI/2 弧度之间的数值来返回 x 的反正切值。 |
atan2(y,x) | 返回从 x 轴到点 (x,y) 的角度(介于 -PI/2 与 PI/2 弧度之间)。 |
ceil(x) | 对数进行上舍入。 |
cos(x) | 返回数的余弦。 |
exp(x) | 返回 Ex 的指数。 |
floor(x) | 对 x 进行下舍入。 |
log(x) | 返回数的自然对数(底为e)。 |
max(x,y,z,…,n) | 返回 x,y,z,…,n 中的最高值。 |
min(x,y,z,…,n) | 返回 x,y,z,…,n中的最低值。 |
pow(x,y) | 返回 x 的 y 次幂。 |
random() | 返回 0 ~ 1 之间的随机数。 |
round(x) | 四舍五入。 |
sin(x) | 返回数的正弦。 |
sqrt(x) | 返回数的平方根。 |
tan(x) | 返回角的正切。 |
tanh(x) | 返回一个数的双曲正切函数值。 |
trunc(x) | 将数字的小数部分去掉,只保留整数部分。 |
布尔 boolean
即逻辑真假,true 和 false,其常用的对象属性和方法有
属性 | 描述 |
---|---|
constructor | 返回对创建此对象的 Boolean 函数的引用 |
prototype | 使您有能力向对象添加属性和方法。 |
方法 | 描述 |
---|---|
toString() | 把布尔值转换为字符串,并返回结果。 |
valueOf() | 返回 Boolean 对象的原始值。 |
空 null 和未定义 undefined
js 的设计者希望 null 表示一个空的值,Undefined 表示值未定义。事实上,这并没有卵用,区分两者的意义不大。大多数情况下都应该使用 null。 undefined 仅仅在判断函数参数是否传递的情况下有用。
symbol
Symbol 是 ES6 引入了一种新的原始数据类型,表示独一无二的值。
对象 object
JavaScript的对象是一组由键-值组成的无序集合,由花括号包裹。在括号内部,对象的属性以键值对来定义。键都是字符串类型,值可以是任意数据类型。属性由逗号分隔。
var person={
firstname : "John",
lastname : "Doe",
id : 5566
};
对象属性有两种寻址方式:
name=person.lastname;
name=person["lastname"];
使用对象的方法时,类似于函数的使用方式。
JavaScript规定,访问(包括删除)不存在的属性不报错,而是返回 undefined。如果我们要检测对象是否拥有某一属性,可以用 in 操作符(不过如果 in 判断一个属性存在,这个属性不一定是此对象的,它可能是继承得到的。要判断一个属性是否是对象自身拥有的,而不是继承得到的,可以用 Object.hasOwn(obj,name)
方法)。
遍历对象常用的几种方法
for...in
: 常用的方法是for(let key in obj){}
,使用此方法有一个问题,其继承的属性会被遍历。如果不想遍历,可以使用下几种方法Object.keys(obj)
: 此方法可以遍历所有对象本身的可枚举属性,返回值是 key 组成的数组。Object.values(obj)
: 此方法类似于Object.keys(obj)
,区别是返回值为 value 组成的数组。Object.entries(obj)
: 此方法为上两种方法的结合,返回一个嵌套数组,数组内容包括了属性名与属性值。
数组 Array
数组是一组按顺序排列的集合,集合的每个值称为元素。JavaScript的数组可以包括任意数据类型。js 有3种方法创建数组,js 的数组下标从 0 开始。
var cars=new Array();
cars[0]="Saab";
cars[1]="Volvo";
cars[2]="BMW";
var cars=new Array("Saab","Volvo","BMW");
var cars=["Saab","Volvo","BMW"];
因为 js 可以直接使用索引(下标)修改值和赋值(即索引越界不会报错,而是修改数组的大小),所以不建议直接修改数组大小,访问索引时要确保索引不会越界
数组对象的常用的属性和方法有
属性 | 描述 |
---|---|
constructor | 返回创建数组对象的原型函数。 |
length | 设置或返回数组元素的个数。(直接给 Array 的 length 赋一个新的值会导致 Array 大小的变化,多出来的元素为 undefinded) |
prototype | 允许你向数组对象添加属性或方法。 |
方法 | 描述 |
---|---|
concat() | 连接两个或更多的数组,并返回结果。 |
copyWithin() | 从数组的指定位置拷贝元素到数组的另一个指定位置中。 |
entries() | 返回数组的可迭代对象。 |
every() | 检测数值元素的每个元素是否都符合条件。 |
fill() | 使用一个固定值来填充数组。 |
filter() | 检测数值元素,并返回符合条件所有元素的数组。 |
find() | 返回符合传入测试(函数)条件的数组元素。 |
findIndex() | 返回符合传入测试(函数)条件的数组元素索引。 |
forEach() | 数组每个元素都执行一次回调函数。 |
from() | 通过给定的对象中创建一个数组。 |
includes() | 判断一个数组是否包含一个指定的值。 |
indexOf() | 搜索数组中的元素,并返回它所在的位置。 |
isArray() | 判断对象是否为数组。 |
join() | 把数组的所有元素放入一个字符串。 |
keys() | 返回数组的可迭代对象,包含原始数组的键(key)。 |
lastIndexOf() | 搜索数组中的元素,并返回它最后出现的位置。 |
map() | 通过指定函数处理数组的每个元素,并返回处理后的数组。 |
pop() | 删除数组的最后一个元素并返回删除的元素。 |
push() | 向数组的末尾添加一个或更多元素,并返回新的长度。 |
reduce() | 将数组元素计算为一个值(从左到右)。 |
reduceRight() | 将数组元素计算为一个值(从右到左)。 |
reverse() | 反转数组的元素顺序。 |
shift() | 删除并返回数组的第一个元素。 |
slice() | 选取数组的一部分,并返回一个新数组。 |
some() | 检测数组元素中是否有元素符合指定条件。 |
sort() | 对数组的元素进行排序。 |
splice() | 从数组中添加或删除元素。 |
toString() | 把数组转换为字符串,并返回结果。 |
unshift() | 向数组的开头添加一个或更多元素,并返回新的长度。 |
valueOf() | 返回数组对象的原始值。 |
常用的遍历数组的方法
Array.forEach((item, index, array)=>{})
: 此方法传入一个处理回调函数,函数可以有3个参数,分别是元素、索引、数组本身。此方法不返回值。Array.filter((item,index,array)=>{})
: 此方法类似于forEach
方法,区别在于返回一个新的数组。数组的元素为回调函数返回真的原数组元素。也可以使用此方法来去除数组中的某一元素(target):array = array.filter(item=>item !== target)
Array.map((item,index,array)=>{})
: 此方法类似于filter
方法,区别在于返回新的数组其元素为回调函数返回的值,如果回调函数没有返回值则不添加到返回数组中。Array.some((item,index,array)=>{})
: 此方法返回一个布尔值,如果此方法的回调函数返回一个真,则此方法返回真,否则返回假。此方法是懒惰的,即回调函数返回一个真就会停止遍历。Array.every((item,index,array)=>{})
: 此方法和some
相反,即所有回调函数均返回真,则方法返回真。此方法也是懒惰的。
常用的数组判断方法
Array.includes(item)
: 判断数组是否有元素 item ,返回布尔值
函数 function
函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块。
函数的定义
js 的函数是以关键字 function 开头,紧跟的是函数名称(非必要,没有名称的函数是匿名函数),然后是小括号(必要)包裹的形参,多个形参用逗号分隔。函数定义不是一条执行语句,所以完成后不需要分号。再次强调,js 对于大小写敏感。
function myFunction(val1, val2)
{
// 代码
}
JavaScript的函数也是一个对象,而函数名可以视为指向该函数的变量,所以也可以这样定义
var myFunction = function (val1, val2) {
// 函数体
};
即定义匿名函数赋值给变量。需要注意的是第二种方法是一个赋值语句,所以需要分号表示赋值结束。
函数的调用
js 使用函数名称加小括号表示调用函数,调用函数时执行函数内部代码。如果使用函数名但没加括号表示获取函数体代码,并不执行。
带参数的函数
js 使用位置参数,即形参和实参的位置必须一致,如果个数不一致,那么未提供的参数会设置为未定义。js 在函数定义时,不会对参数类型和个数进行检测。ES6 在定义函数时,参数可以定义默认值。js 在调用带参数的函数时,不会检测参数的类型。即函数定义和调用时的参数数量可以不一致。
js 函数有个内置的对象 arguments 对象,包含了函数调用的参数数组。可以直接使用 arguments 对象按照数组使用参数。
带有返回值的函数
js 的函数遇到 return 就会停止执行,并返回 return 后跟随的数据(没有 return 语句函数执行完毕后也会返回结果,只是为 undefined)。需注意的是 return 后的语句不能换行写,如果换行了,return 会被自动添加分号,即函数返回 undefined。
正则 RegExp
正则表达式是描述字符模式的对象,用于对字符串模式匹配及检索替换,是对字符串执行模式匹配的强大工具。其语法为:
var patt=new RegExp(pattern,modifiers);
或者更简单的方式:
var patt=/pattern/modifiers;
- pattern(模式) 描述了表达式的模式
- modifiers(修饰符) 用于指定全局匹配、区分大小写的匹配和多行匹配,包括 i (大小写不敏感) g (全局匹配,即查找所有而不是找到第一个匹配后停止) m (执行多行匹配)
注意:当使用构造函数创造正则对象时,需要常规的字符转义规则(在前面加反斜杠 \)。比如,以下是等价的:
var re = new RegExp("\\w+");
var re = /\w+/;
正则对象的一些常用属性和方法有
属性 | 描述 |
---|---|
constructor | 返回一个函数,该函数是一个创建 RegExp 对象的原型。 |
global | 判断是否设置了 “g” 修饰符 |
ignoreCase | 判断是否设置了 “i” 修饰符 |
lastIndex | 用于规定下次匹配的起始位置 |
multiline | 判断是否设置了 “m” 修饰符 |
source | 返回正则表达式的匹配模式 |
方法 | 描述 |
---|---|
exec | 检索字符串中指定的值。返回找到的值,并确定其位置。 |
test | 检索字符串中指定的值。返回 true 或 false。 |
toString | 返回正则表达式的字符串。 |
另外支持正则表达式的 String 对象的方法有
方法 | 描述 |
---|---|
search | 检索与正则表达式相匹配的值。 |
match | 找到一个或多个正则表达式的匹配。 |
replace | 替换与正则表达式匹配的子串。 |
split | 把字符串分割为字符串数组。 |
日期 Date
Date 对象用于处理日期与时间。常用的创建日期对象的方法有
var d = new Date();
var d = new Date(milliseconds); // 参数为毫秒
var d = new Date(dateString);
var d = new Date(year, month, day, hours, minutes, seconds, milliseconds);
- milliseconds 参数是一个 Unix 时间戳(Unix Time Stamp),它是一个整数值,表示自 1970 年 1 月 1 日 00:00:00 UTC(the Unix epoch)以来的毫秒数。
- dateString 参数表示日期的字符串值。
- year, month, day, hours, minutes, seconds, milliseconds 分别表示年、月、日、时、分、秒、毫秒。
需要注意的是,js 传入的月份范围是 0 - 11,
Date 对象常用的属性和方法有
属性 | 描述 |
---|---|
constructor | 返回对创建此对象的 Date 函数的引用。 |
prototype | 使您有能力向对象添加属性和方法。 |
方法 | 描述 |
---|---|
getDate() | 从 Date 对象返回一个月中的某一天 (1 ~ 31)。 |
getDay() | 从 Date 对象返回一周中的某一天 (0 ~ 6)。 |
getFullYear() | 从 Date 对象以四位数字返回年份。 |
getHours() | 返回 Date 对象的小时 (0 ~ 23)。 |
getMilliseconds() | 返回 Date 对象的毫秒(0 ~ 999)。 |
getMinutes() | 返回 Date 对象的分钟 (0 ~ 59)。 |
getMonth() | 从 Date 对象返回月份 (0 ~ 11)。 |
getSeconds() | 返回 Date 对象的秒数 (0 ~ 59)。 |
getTime() | 返回 1970 年 1 月 1 日至今的毫秒数。 |
getTimezoneOffset() | 返回本地时间与格林威治标准时间 (GMT) 的分钟差。 |
getUTCDate() | 根据世界时从 Date 对象返回月中的一天 (1 ~ 31)。 |
getUTCDay() | 根据世界时从 Date 对象返回周中的一天 (0 ~ 6)。 |
getUTCFullYear() | 根据世界时从 Date 对象返回四位数的年份。 |
getUTCHours() | 根据世界时返回 Date 对象的小时 (0 ~ 23)。 |
getUTCMilliseconds() | 根据世界时返回 Date 对象的毫秒(0 ~ 999)。 |
getUTCMinutes() | 根据世界时返回 Date 对象的分钟 (0 ~ 59)。 |
getUTCMonth() | 根据世界时从 Date 对象返回月份 (0 ~ 11)。 |
getUTCSeconds() | 根据世界时返回 Date 对象的秒钟 (0 ~ 59)。 |
parse() | 返回1970年1月1日午夜到指定日期(字符串)的毫秒数。 |
setDate() | 设置 Date 对象中月的某一天 (1 ~ 31)。 |
setFullYear() | 设置 Date 对象中的年份(四位数字)。 |
setHours() | 设置 Date 对象中的小时 (0 ~ 23)。 |
setMilliseconds() | 设置 Date 对象中的毫秒 (0 ~ 999)。 |
setMinutes() | 设置 Date 对象中的分钟 (0 ~ 59)。 |
setMonth() | 设置 Date 对象中月份 (0 ~ 11)。 |
setSeconds() | 设置 Date 对象中的秒钟 (0 ~ 59)。 |
setTime() | setTime() 方法以毫秒设置 Date 对象。 |
setUTCDate() | 根据世界时设置 Date 对象中月份的一天 (1 ~ 31)。 |
setUTCFullYear() | 根据世界时设置 Date 对象中的年份(四位数字)。 |
setUTCHours() | 根据世界时设置 Date 对象中的小时 (0 ~ 23)。 |
setUTCMilliseconds() | 根据世界时设置 Date 对象中的毫秒 (0 ~ 999)。 |
setUTCMinutes() | 根据世界时设置 Date 对象中的分钟 (0 ~ 59)。 |
setUTCMonth() | 根据世界时设置 Date 对象中的月份 (0 ~ 11)。 |
setUTCSeconds() | setUTCSeconds() 方法用于根据世界时 (UTC) 设置指定时间的秒字段。 |
toDateString() | 把 Date 对象的日期部分转换为字符串。 |
toISOString() | 使用 ISO 标准返回字符串的日期格式。 |
toJSON() | 以 JSON 数据格式返回日期字符串。 |
toLocaleDateString() | 根据本地时间格式,把 Date 对象的日期部分转换为字符串。 |
toLocaleTimeString() | 根据本地时间格式,把 Date 对象的时间部分转换为字符串。 |
toLocaleString() | 根据本地时间格式,把 Date 对象转换为字符串。 |
toString() | 把 Date 对象转换为字符串。 |
toTimeString() | 把 Date 对象的时间部分转换为字符串。 |
toUTCString() | 根据世界时,把 Date 对象转换为字符串。 |
UTC() | 根据世界时返回 1970 年 1 月 1 日 到指定日期的毫秒数。 |
valueOf() | 返回 Date 对象的原始值。 |
map 类型
map 类型类似于 python 的字典。初始化 Map 需要一个二维数组,或者直接初始化一个空 Map。
// 使用二维数组初始化 Map 对象举例
var m = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]);
// 初始化空 Map 对象
var m = new Map();
Map 具有这些方法:
m.set('Adam', 67); // 添加新的 key-value ,或将已存在的 key 设置新的 value
m.has('Adam'); // 是否存在 key 'Adam': true
m.get('Adam'); // 获取 key 的 value
m.delete('Adam'); // 删除key 'Adam'
m.get('Adam'); // undefined
Set 类型
set 类似于集合,其元素是不重复的。要创建一个 Set ,需要提供一个 Array 作为输入,或者直接创建一个空 Set
var s1 = new Set(); // 空Set
var s2 = new Set([1, 2, 3]); // 含1, 2, 3
需注意的是重复元素在 Set 中自动被过滤,且数字和字符串是不同元素。
可以使用 add()
方法添加元素,delete()
方法删除元素
s.add(4);
s.delete(4);
iterable 类型
遍历 Array 可以采用下标循环,遍历 Map 和 Set 就无法使用下标。为了统一集合类型,ES6标准引入了新的 iterable 类型, Array 、 Map 和 Set 都属于 iterable 类型,即可迭代类型。可迭代类型可以通过 ES6 新引入的 for ... of
来循环遍历。
var a = ['A', 'B', 'C'];
var s = new Set(['A', 'B', 'C']);
var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
for (var x of a) { // 遍历Array
console.log(x);
}
for (var x of s) { // 遍历Set
console.log(x);
}
for (var x of m) { // 遍历Map
console.log(x[0] + '=' + x[1]);
}
for ... of
和 for ... in
循环的区别在于,for ... in
循环遍历的实际上是对象的属性名称。当手动给数组对象添加额外的属性后, for ... in
循环将带来意想不到的意外效果
var a = ['A', 'B', 'C'];
a.name = 'Hello';
for (var x in a) {
console.log(x); // '0', '1', '2', 'name'
}
即 for ... in
循环将 name 包括在内(但 length 属性不会包括在内),而 for ... of
循环修复了这些问题,只循环对象其本身的元素。然而更好的方式是直接使用 iterable 内置的 forEach 方法。它接收一个回调函数,每次迭代就会调用此回调函数。
var a = ['A', 'B', 'C'];
a.forEach(function (element, index, array) { // 如果 a 是 map,则参数是 (value, key, map)
// element: 指向当前元素的值
// index: 指向当前索引
// array: 指向 Array 对象本身
console.log(array + '的第' + index + '个元素的值为' + element);
});
需注意的是,set 没有索引,所以回调函数的前两个参数都是元素本身。
json
json 是一个超轻量级的数据交换格式,几乎每种语言都有其支持库。json 规定了使用 utf-8 字符集,且字符串必须使用双引号,object 类型成员的键也必须使用双引号。
把任何JavaScript对象变成JSON,就是把这个对象序列化成一个JSON格式的字符串,这样才能够通过网络传递给其他计算机。收到一个JSON格式的字符串,只需要把它反序列化成一个JavaScript对象,就可以在JavaScript中直接使用这个对象了。
序列化
使用 JSON.stringify()
方法可以将一个对象序列化。此方法有3个参数
- 第一参数为需要序列化的对象
- 第二参数用于筛选对象的键值(例如输出指定属性,则传入指定属性的键数组),或传入一个函数用来处理每个键值对。
- 第三参数一般是4个空格,用以控制输出的格式缩进
如果需要精确控制对象的序列化,可以给对象定义一个 toJSON()
的方法,返回应该序列化的数据。这样此对象传递到 JSON.stringify()
方法中时,序列化的数据就是对象 toJSON()
方法返回的数据了。
// 序列化
var s = JSON.stringify(obj);
反序列化
使用 JSON.parse()
方法可以将 JSON 格式的字符串变成一个 js 对象。也可以接收一个函数,用来转换解析出的属性。
运算符
算术运算符
当 y = 5 时
运算符 | 描述 | 例子 | x 运算结果 | y 运算结果 |
---|---|---|---|---|
+ | 加法 | x=y+2 | 7 | 5 |
- | 减法 | x=y-2 | 3 | 5 |
* | 乘法 | x=y*2 | 10 | 5 |
/ | 除法 | x=y/2 | 2.5 | 5 |
% | 取模(余数) | x=y%2 | 1 | 5 |
++ | 自增 | x=++y | 6 | 6 |
++ | 自增 | x=y++ | 5 | 6 |
-- | 自减 | x=--y | 4 | 4 |
-- | 自减 | x=y-- | 5 | 4 |
赋值运算符
x=10 和 y=5
运算符 | 例子 | 等同于 | 运算结果 |
---|---|---|---|
= | x=y | x=5 | |
+= | x+=y | x=x+y | x=15 |
-= | x-=y | x=x-y | x=5 |
*= | x*=y | x=x*y | x=50 |
/= | x/=y | x=x/y | x=2 |
%= | x%=y | x=x%y | x=0 |
比较运算符
x=5
运算符 | 描述 | 比较 | 返回值 |
---|---|---|---|
== | 等于 | x==8 | false |
== | 等于 | x==5 | true |
=== | 绝对等于(值和类型均相等) | x===“5” | false |
=== | 绝对等于(值和类型均相等) | x===5 | true |
!= | 不等于 | x!=8 | true |
!== | 不绝对等于(值和类型有一个不相等,或两个都不相等) | x!==“5” | true |
!== | 不绝对等于(值和类型有一个不相等,或两个都不相等) | x!==5 | false |
> | 大于 | x>8 | false |
< | 小于 | x<8 | true |
>= | 大于或等于 | x>=8 | false |
<= | 小于或等于 | x<=8 | true |
需要注意的是, == 比较符会自动转换数据类型再进行比较,有时会得到比较诡异的结果,由于这个设计缺陷,所以尽量使用 === 进行比较。
另外就是 NaN 这个特殊的 Number 类型的值与所有其他值都不相等,包括它自己。唯一能够判断 NaN 的方法是通过 isNaN()
函数。
最后需要注意的是浮点数的相等比较(因为 js 不分整形和浮点,所以这个问题可能会经常遇见),由于计算机无法精确运算小数(尤其是位数比较多的小数),所以要比较两个浮点数是否相等,只能计算它们的差的绝对值是否小于某个阈值。
逻辑运算符
x=6 和 y=3
运算符 | 描述 | 例子 |
---|---|---|
&& | and | (x < 10 && y > 1) 为 true |
|| | or | (x==5 || y==5) 为 false |
! | not | !(x==y) 为 true |
js 中的逻辑运算使用的是惰性运算,也叫短路运算。
条件运算符
条件运算符就是三元运算符
variablename=(condition)?value1:value2
即判断 condition,如果为真则赋值 value1 ,否则赋值 value2
条件
js 中使用 if else swith 作为条件语句关键字
if 语句
条件为真则执行代码块,如果代码块只有一行代码,则可以省略花括号,以分号表示语句执行结束。
if (condition)
{
// 当条件为 true 时执行的代码
}
if (condition) 执行代码;
if (condition)
执行代码;
if … else 语句
条件为真执行代码块,否则执行另一个代码块。else 的代码块如果也只包含一条语句,也可以省略花括号。
if (condition)
{
// 当条件为 true 时执行的代码
}
else
{
// 当条件不为 true 时执行的代码
}
if … else if … else 语句
选择多个代码块其中之一进行执行
if (condition1)
{
// 当条件 1 为 true 时执行的代码
}
else if (condition2)
{
// 当条件 2 为 true 时执行的代码
}
else
{
// 当条件 1 和 条件 2 都不为 true 时执行的代码
}
swith 语句
swith 语句执行效果类似于 if ... else if ... else
语句,会将表达式 n 和每一个 case 的值做比较,选择匹配的关联代码执行,遇到 break 则停止继续执行推出代码块。
switch(n)
{
case 1:
// 执行代码块 1
break;
case 2:
// 执行代码块 2
break;
default:
// 与 case 1 和 case 2 不同时执行的代码
}
循环
js 可以使用 for 循环和 while 循环
for 循环
for 循环的语法:
for (语句 1; 语句 2; 语句 3)
{
// 被执行的代码块
}
其中语句1初始化循环中所用的变量(任意数量),如使用已经存在的外部变量此语句可以省略。如果使用 let 定义变量则变量只在代码块中生效。
通常语句 2 用于评估初始变量的条件,当此语句为真时执行循环,否则退出循环。此语句也可以省略(使用 break 用于打破循环)。
通常语句 3 会改变初始变量的值。此语句在每次循环执行完成后执行,也可以进行省略,在循环提内部进行改变。
for … in 循环
js 还支持 for ... in
循环,通常用来遍历对象的属性
var person={fname:"Bill",lname:"Gates",age:56};
for (x in person) // x 为属性名
{
txt=txt + person[x];
}
注意,此方法还遍历了继承的属性。如果要过滤掉对象继承的属性,则需要使用 hasOwnProperty()
方法进行判断
var o = {
name: 'Jack',
age: '20',
city: 'Beijing'
};
for (var key in o) {
if (o.hasWonProperty(key)) {
console.log(key);
}
}
由于数组也是对象,它的每个元素的索引也被视为对象的属性,所以也可以使用 for ... in
循环遍历。需注意的是遍历得到的索引是 String 而不是 Number。
var a = ['A', 'B', 'C'];
for (var i in a) {
console.log(i); // '0', '1', '2'
console.log(a[i]); // 'A', 'B', 'C'
}
for … of 循环
使用 for … of 循环能够遍历数组,或有迭代器的对象(普通对象不行),同 for … in 循环类似。不同处在于当循环对象为数组时,遍历得到的是成员而不是索引。另外 for …in 循环会遍历对象的原型链,而 for … of 不会。
var a = ['a', 'b', 'c'];
for (var i in a) {
console.log(i); // 'a', 'b', 'c'
}
while 循环
while 循环会在指定条件为真时循环执行代码块
while (条件)
{
// 需要执行的代码
}
do … while 循环
do/while 循环是 while 循环的变体。该循环会在检查条件是否为真之前执行一次代码块,然后如果条件为真的话,就会重复这个循环。
do
{
// 需要执行的代码
}
while (条件);
break 和 continue
break 语句可用于跳出循环,继续执行该循环之后的代码(如果有的话)。
continue 语句中断当前的循环中的迭代,然后继续循环下一个迭代。
错误
js 代码出错时,会抛出错误,也可以手动抛出错误。使用 try catch 尝试和捕获错误,使用 throw 抛出错误。 throw 抛出的异常可以是 js 字符串、数字、逻辑值或对象。
try {
... // 尝试执行
throw // 手动抛出错误,非必要
} catch(err) {
... // 异常的捕获与处理
} finally {
... // 结束处理,不管是否有错误均会执行此代码
}
错误也是一个对象,经常使用属性 name 设置或返回一个错误名,且使用属性 message 设置或返回一个错误信息(字符串)
错误的传播
如果在一个函数内部发生了错误,它自身没有捕获,错误就会被抛到外层调用函数,如果外层函数也没有捕获,该错误会一直沿着函数调用链向上抛出,直到被JavaScript引擎捕获,代码终止执行。所以不必在每一个函数内部捕获错误,只需要在合适的地方统一捕获。
异步错误处理
编写JavaScript代码时,我们要时刻牢记,JavaScript引擎是一个事件驱动的执行引擎,代码总是以单线程执行,而回调函数的执行需要等到下一个满足条件的事件出现后,才会被执行。所以,涉及到异步代码,无法在调用时捕获,原因就是在捕获的当时,回调函数并未执行。
调试
js 可以使用调试工具临时查看数据,如果浏览器支持,也可以在浏览器的控制台中进行调试。例如可以使用 console.log()
方法在控制台输出需要的 js 值。
console.log(value);
也可以使用 debugger 关键字手动设置断点,当执行到 debugger 程序会停止往下执行。
debugger;