第五章*****************************************************************************************
什么是索引数组: 下标都是数字的数组
关联数组:
什么是: 可自定义下标名称的数组
为什么: 为了让每个元素都有一个专门的名称
好处: 1. 便于维护;2.快速查找
何时: 1. 希望每个元素都有明确的意义时
2. 快速定位想要的元素时
如何: 2件事(创建、访问)
创建分2步:
1. 先创建空数组:var arr=[];
2.向空数组中添加新元素,要使用自定义的下标名称
EX:ym["name"]="杨幂"
ym["math"]=81;
ym["chs"]=59;
ym["eng"]=89;
访问: 用法和访问索引数组完全一样,同变量的用法,只不过要使用自定义的下标名称
关联数组中.length属性失效,永远等于0
因为关联数组中没有数字下标,length无法+1
遍历关联数组(键值对的集合): 只能用for( in )
for(var key in arr){ /*in:自动依次取出arr中每个下标名称保存在变量key中;key:当前房间号:键*/
arr[key]; //当前元素值: value,当前属性名: key
} /*强调: key不能加引号, 因为每次循环都在变化*/
索引数组:无法提前预知元素的具体位置,只能靠遍历查找,受元素个数和元素存储位置影响极大(慢)
关联数组:直接通过下标定位元素位置,查找速度和元素个数及元素位置无关(快)
关联数组原理:hash算法: 根据一个字符串,计算出尽量不重复的一个序号。相同的字符串计算出的序号一定相同,相同下标的值会覆盖原先的值
向关联数组中保存元素:
将自定义下标名交给hash算法,计算一个散列的位置序号。将元素保存到序号指定位置
从关联数组中取值时:
将自定义下标名交给hash算法,计算出和存入时完全相同的序号,引擎直接去序号位置获得元素
优点: 不受存储位置和元素个数的影响
_______________________________________________________________________________________________
1. 数组API
什么是数组: 存储多个数据,并提供了操作数据的API的对象
API: 别人已经实现的,咱们用现成的程序
将数组转字符串有2种:
String(arr): 将arr中每个元素都转为字符串,用逗号连接
何时: 给数组拍照,查看数组的中间修改状态,判断操作前后数组是否发生了变化
arr.join("自定义连接符"): 将arr中每个元素都转为字符串,用自定义的连接符连接元素
何时: 只要不希望使用逗号连接符时
固定套路: 1. 把单词拼接为句子
2. 无缝拼接:
错误: arr.join() <=> String(arr) =>输出为逗号连接
正确: arr.join("")
重要用途: 判断数组是否为空
3.动态生成页面元素(只会在元素之间添加连接符,所以要在arr.join("...")前后补全标签)
2步:① var html="<ANY>"+arr.join("</ANY><ANY>")+"</ANY>";
或 var html="<ul>"+uls.join("")+"</ul>";
② elem.innerHTML=html;
console.log(String(arr)),console.log(arr),console.dir(arr)
console.log(arr); 先输出dir的结构,刷新后变为String(arr)
仅输出内容,不关心结构: console.log(String(arr))
查看数组存储结构: console.dir(arr) /*dir查看结果时,不遵循先后执行的顺序*/
判断数组中是否含有某个元素:
数组可用indexOf搜索某个元素的下标,返回在数组中找到的给定元素的第一个索引,若不存在,则返回-1,但数组元素需要完全相等(===)才会搜索成功,且不识别NaN
如: var arr = ['啦啦',2,4];
arr.indexOf('啦'); //-1
arr.indexOf('啦啦'); //0
使用ES6的扩展运算符(...)代替cancat,可以更方便的合并数组
如: var arr1 = [1,2,3];
var arr2 = [4,...arr1,5]; //[4,1,2,3,5]
toLocaleString()可将数组中的每个元素用逗号(,)隔开,组成字符串(调用join()方法)
var str = arr.toLocaleString()
_______________________________________________________________________________________________
拼接和选取: 都无权修改原数组,只能返回新数组对象
拼接: 将多个数组或元素,和当前数组拼接为一个新数组
如何:var newArr=arr1.concat(值1,值2,arr2,...);
强调: 1.不修改原数组,只返回新数组
2. 可打散数组类型的参数为单个元素,再拼接 /*concat独有*/
注意: 若是大数组会消耗大量内存,可用arr1.push.apply(arr1, arr2)代替,将arr2合并到arr1中
选取: 复制原数组中指定开始位置到结束位置之间的多个元素,组成新数组———原数组保持不变
如何:var subArr=arr.slice(starti,endi+1);
强调: 1.不修改原数组,仅复制出想要的元素组成新数组
2.如果一个API的两个参数都是下标时,就含头不含尾
简写: 1. 如果参数位置离结尾近,可用负数下标:
arr.length-n 可简写为:-n(倒数第n个(不包含尾))(API自动加length)
2. 可省略第二个参数(-1),表示一直选取到结尾
3. 两个参数都可省略: 完整复制一个数组(地址值不同)
_______________________________________________________________________________________________
两个对象作比较(arr2==arr1):
不做任何转换,直接比较两个对象的地址值,用于判断两个变量是否引用同一个对象
引用类型的对象(arr2=arr1):用新变量修改对象,等效于直接修改原对象,新旧变量都受影响(地址值相同)
复制数组(地址值不同):①选取复制: var arr2=arr1.slice();
②复制索引数组:for(var i=0;i<arr2.length;i++){arr2[i]=arr1[i]};
③复制关联数组:for(var key in arr1){key; arr2[key]=arr1[key]};
_______________________________________________________________________________________________
修改数组: splice(强调: 直接修改原数组)
删除元素:arr.splice(starti,n)
删除starti位置开始的n个元素
强调: 不必考虑含头不含尾(n是个数)
其实有返回值: 返回被删除的元素组成的临时数组
var deletes=arr.splice(starti,n); /*deletes保存了删除的元素*/
简写: 1. 支持负数下标,表示倒数第n个(自动用length-n)
2. 省略n(从starti 删到结尾)
插入新元素:arr.splice(starti,0,值1,值2,...) //删除0个
在starti位置插入新的值1,值2,...
强调: 1.原starti位置的值及其之后的值被向后顺移
2.不支持打散数组类型参数(如果插入一个数组,将变成二维数组)
替换: arr.splice(starti,n,值1,值2,...)
先删除旧的,再在同一位置插入新的
先删除starti开始的n个元素,再在starti位置插入值1,值2,...
强调: 删除的个数和插入的个数不必相同
翻转: arr.reverse();
_______________________________________________________________________________________________
排序:
什么是: 将数组中的元素按从小到大或从大到小的顺序重新排列
何时: 任何数据在给用户展示前,必须先排序
如何:arr.sort(); /*将 arr 数组按字符串升序,直接修改原数组*/
原理: 将所有元素都转为字符串,再按字符串升序排列
何时: 只有按字符串升序排列时,才用默认的sort()
问题: 只能按字符串升序排列
解决:自定义比较器函数:
什么是: 专门比较任意两值大小的函数
何时: 如果sort默认的排序规则不是想要的,可自定义比较器代替sort中默认的排序规则
要求: 2个参数: a,b
返回值: 如果a>b,就返回正数
如果a<b,就返回负数
否则返回0
最简单的数字升序比较器
function cmp(a,b){return a-b;}; /*定义比较器函数*/
arr.sort(cmp); /*传入sort()中*/
简化为:arr.sort(function(a,b){return a-b}); /*cmp=function(a,b){return a-b;}*/
/* 对对象的值进行排序: arr.sort(function(a,b){ return obj[a]-obj[a] }) */
如何使用: 将比较器函数对象作为参数传入sort()函数中
强调:不加() /*cmp: 回调函数callback,不加()*/
回调函数:自己定义的函数,自己不调用,不只调用一次,而是传入另一个函数中,被另一个函数反复调用
何时: 只要对数字元素排序,都要自定义比较器函数
递归调用:函数内又调用了自己(效率极低,几乎所有的递归都可用循环代替)
问题2: 如何降序:
解决: 只要颠倒比较器结果的正负号,就可改升序为降序
最简单的数字降序比较器
function cmp(a,b){return b-a};
arr.sort(cmp);
简化为: arr.sort(function(a,b){return b-a});
_______________________________________________________________________________________________
2. 栈和队列
说明: js中没有专门的栈和队列结构,都是用普通数组模拟的
栈stack:
什么是栈: 一端封闭,只能从另一端进出的数组
栈是限定仅在表头/表尾进行插入/删除操作的线性表
何时: 只要希望始终使用最后进入数组的新元素时(先进后出)
如何:
1. 结尾出入栈:
结尾入栈: arr.push(值)<=> arr[arr.length]=值 /*在末尾追加一个新值*/
强调: 1. 其实push可压入多个值: arr.push(值1, 值2)
2. 不支持打散数组参数 //可用来创建二维数组
结尾出栈: var last=arr.pop(); /*移出数组末尾的最后一个元素*/
2. 开头出入栈:
开头入栈: arr.unshift(值) /*在开头插入一个值*/
强调: 开头入栈后的元素顺序和结尾入栈后的元素顺序是相反的
开头出栈: var first=arr.shift(); /*移出数组开头的第一个元素*/
队列queue:
什么是: 只能从结尾进入,从开头出的数组,是事件循环(Event Loop)的基础结构
何时: 只要希望按照先来后到的顺序使用数组元素时
如何: 1. 从结尾入队列:arr.push(值);
2. 从开头出队列:var first=arr.shift();
堆:
堆数据结构是一种树状结构,它使用key-value的形式存储,是无序的
变量的存放:
基本数据类型: 保存在栈内存中,占有固定大小的空间,通过按值来访问
引用类型: 保存在堆内存中,因为值的大小不固定,所以不能保存到栈内存中,但内存地址大小是固定的,可以保存在栈内存中。当查询引用类型的变量时,先从栈中读取内存地址,然后通过内存地址找到堆中的值,一般叫做按引用访问
_______________________________________________________________________________________________
总结: 向数组中添加元素4种:
1. concat():①不修改原数组,返回新数组
②在结尾拼接元素
③支持打散数组类型参数,另一个是.apply(),只有这两个能打散数组
2. splice():①直接修改原数组
②在任意位置插入新元素
③不支持打散数组类型参数
3. push():①直接修改原数组
②只能在结尾拼接元素
③不支持打散数组类型参数
4. shift():①直接修改原数组
②只能在开头拼接元素
③不支持打散数组类型参数
取出数组元素: 4种:
1. slice():①可获取任意位置的任意个元素
②不修改原数组,返回选中的元素组成的新数组
2. splice():①删除任意位置的任意个元素
②直接修改原数组
③返回被删除的元素组成的新数组
3. pop():只能从结尾删除一个元素,并返回
4. shift():只能从开头删除一个元素,并返回
_______________________________________________________________________________________________
3.二维数组
什么是: 数组中的元素,又引用了另一个子数组
何时:
1. 保存横行竖列的二维数据
2. 一个大的数组中,还需要对元素进行更细致分类
如何创建: 2种:
1. 先创建空数组,再添加子数组:
var arr=[];
arr[0]=[0,0,0,0];
arr[1]=[0,0,0,0];
...
2. 创建数组同时,初始化子数组
var arr=[
[0,0,0,0],
... ,
[0,0,0,0]
];
访问:arr[r][c](r行号,c列号) 用法和普通数组的元素及变量完全一样
越界: 二维数组的行下标r,不能越界,越界报错
遍历二维数组:
for(var r=0;r<data.length;r++){ //外层循环控制行
for(var c=0;c<data[r].length;c++){ //内层循环控制列
data[r][c] //获得当前元素
} }
创建二维数组:
var arr=[];
for (var i=0;i<N;i++ ){
arr[i]=[]; //创建一个二维数组,内容为空
for (var j=0;j<M;j++){ //为二维数组赋值 或填充n个空元素: arr1[i]=new Array(n);
arr[i][j]=0;
} }
冒泡排序算法(一维数组):
function bubblesort(arr){
for(varr=1;r<arr.length;r++){ //外层循环控制轮数
for(vari=0;i<arr.length-r;i++){ //内层循环控制每轮中的比较次数
if(arr[i]>arr[i+1]){ //如果i位置的值>i+1位置的值
arr[i]^=arr[i+1]; //交换两位置的值
arr[i+1]^=arr[i];
arr[i]^=arr[i+1];
} } } }
第六章*****************************************************************************************
三、String类型
什么是: 由多个字符组成的"只读"字符数组
String API: 强调: 所有String API都无权修改原字符串,只能返回新字符串
VS 数组: 相同: 1. 下标;如:str[1] 2. .length
3.var subArr=arr.slice(starti,endi+1);(选取,无权修改原数组)
不同: 类型不同, API不通用
内置对象: ES标准中规定的,浏览器厂商已经实现的对象
包括11个:
String Number Boolean ————— 这3个是包装类型
Array Date Math RegExp
Error
Function Object
Global (在浏览器中被window代替)
包装类型
什么是:专门包装原始类型的值,并提供操作原始类型值的API
为什么: 原始类型的值本身不具有任何功能,才需要包装类型对象的帮助,完成功能
何时: 一般不必手动使用
只要试图用原始类型的值调用函数时,都会自动创建包装类型的对象,调用对象的函数执行操作
注意: 只要引用了字符串的属性(.属性),字符串就会通过调用new String(str)的方式转换成对象,这个对象继承了字符串的方法,并被用来处理属性的引用,一旦属性引用结束,这个新创建的对象就会销毁(实质上并不一定创建和销毁,但整个过程看起来是这样的)
比如: n.toFixed(2) => typeof n => number
<=>new Number(n).toFixed(2)
str.charCodeAt() =>typeof str =>string
<=>new String(str).charCodeAt()
大小写转换
将字符串中所有字母,统一转为大写或小写
str.toLowerCase() 转小写
str.toUpperCase() 转大写
何时: 不区分大小时,都要先转为一致的大小写,再比较或判断: 验证码,用户名,电子邮件
获得指定位置的字符: str.charAt(i) => str[i]
获得指定位置字符的unicode号: str.charCodeAt(i) 获得str中i位置的字符的unicode号
将unicode号,反向转回文字: String.fromCharCode(unicode号) 一次只能转一个字,要用循环
获取子字符串:3种
str.slice(starti, endi+1)
str.substring(starti, endi+1) 用法同slice,但不支持负数参数(负数自动转为0,取较小的值作为开始位置)
str.substr(starti, n) 从starti开始,获取n个字符,n是个数,省略则到结尾为止
_______________________________________________________________________________________________
查找关键词: 4种:
1. 查找一个固定关键词的位置(仅查找规则内的第一个)
var i=str.indexOf("关键词",fromi)
在str中fromi位置之后,查找下一个"关键词"的位置
返回值: 找到的关键词的下标位置i
如果没找到,返回-1
简写: 省略fromi,默认从0开始
var i=-1;
do{
i=str.indexOf("关键词",i+1);
if(i!=-1)
console.log("在位置"+i+"发现关键词");
else break;
}while(true);
2. 查找最后一个关键词的位置
var i=str.lastIndexOf("关键词");
用于获取文件的扩展名(取最后一个.后的剩余字符串)
indexOf的问题: 只能查找一个固定关键词的位置
解决: 正则表达式模糊匹配多种关键词
3. 判断字符串中是否包含符合规则的关键词
var i=str.search(/reg/i) /*reg: 正则表达式,在str中找到第一个符合正则要求的敏感词的位置*/
返回值: 返回关键词的下标位置i
如果没找到返回-1
问题: 正则表达式默认都是区分大小写的
解决:在第二个/后加i,表示忽略(ignore)大小写
何时: 只要仅判断有没有关键词时,首选search
问题: 1. 只能查找第一个关键词,无法找所有
2. 仅返回位置,无法返回关键词内容
4. 查找所有关键词的内容
var kwords=str.match(/reg/ig); //也可使用字符串,结果为查找到的字符串
返回值: 返回所有关键词组成的数组
如果没找到,返回null
使用正则时: 数组的第一个元素(下标为0)表示第一个分组,下标为2的是第二个分组
使用/g时: 下标为0的是找到的第0个分组,下标为1的是第一个分组,下标为2的是第二个分组
使用字符串时,下标为0的是找到的字符串,index是下标,input是要查找的字符串
问题: 正则表达式默认只匹配第一个符合条件的敏感词
解决:在第二个/后加g,表示查找全部(global)
何时: 仅希望获得关键词内容时
问题: 只能获得内容,无法获得每个敏感词的位置
解决: 查找每个关键词内容,又查找位置: regExp.exec()
_______________________________________________________________________________________________
替换: 将字符串中找到的关键词,替换为指定的新内容(2种), (无权修改原字符串,只能返回新字符串)
1. 简单替换: 将所有关键词都替换为同一种新值
str=str.replace(/reg/ig,"新值");
2. 高级替换: 根据每个关键词的不同,动态选择替换不同的新值
str=str.replace(/reg/ig,function(kw){ /*回调函数,kw 自动获得本次找到的关键词*/
return /*根据不同的kw,动态返回不同的值*/
})
衍生:删除: 将关键词替换为""
str=str.replace(/reg/ig,"")
str.replace(/(^\s+)|(\s+$)/g, "") //去掉字符串首尾的空字符
切割: 按指定关键字,将一个字符串切割为多段子字符串(2种)
返回: 返回的是多个子字符串组成的数组,切割后的结果中,不包含分隔符
注意:当分隔符不为空字符("")时,分隔符在边界或连续出现两个时,会形成一个空字符
分隔符的个数 = str.split("分隔符").length-1 //字符串分隔后组成的数组长度-1
1. 简单: 分隔符是固定的:
var subStrs=str.split("分隔符") //不修改原字符串
2. 复杂: 分隔符不是固定的:
var subStrs=str.split(/reg/i);
固定套路: 将字符串打散为字符数组: var chars=str.split("");
多字符切割: var newStr = oldStr.split(/\:|\./g);
var newStr = oldStr.split(/[共]|[注]|[元]/g);
function zhao(str){ //查找一个字符串中每个字符连续出现的次数
var arr1=str.split("");
arr1.sort(); //查找一共出现的次数用arr.sort()先排序再查找
for(var i=0,j=1;i<arr1.length;i++){
if(arr1[i]===arr1[i+1]){
j++;
}else{
console.log(arr1[i]+":"+j);
j=1;
} } }
//截取url的后lastNum*2个字段
function getUrlInfo(lastNum){
var infoArr = location.href.split(/\?|\/|\&|\=/g);
var arr = infoArr.slice(-lastNum*2);
var result = new Object();
for(var i=0; i<arr.length; i+=2){
result[arr[i]] = arr[i+1];
}
return result;
}
_______________________________________________________________________________________________
正则表达式:Regular Expression
什么是: 规定一个字符串中字符出现规律的规则
何时:2种: 1.模糊查找多种关键词
2.验证用户输入的格式
如何:
1.最简单的正则表达式,就是关键词原文本身
2.字符集
什么是: 规定一位字符 备选字符列表 的集合
何时: 只要一位字符,有多种可能备选时
如何:[备选字符列表] // 表示选择其中之一
强调: 中间不要加逗号(,)
一个字符集([])只能规定一位字符的备选字
简写: 如果字符列表中 部分备选字符的unicode是连续的,可用-省略中间字符
比如: [0-9] 一位数字
[a-z] 一位小写字母
[A-Z] 一位大写字母
[A-Za-z] 一位字母
[0-9A-Za-z] 一位字母或数字
[\u4e00-\u9fa5] 一位汉字
特殊:[^字符列表] 除了××
3.预定义字符集
什么是: 对常用特定字符集的更简化写法:4个:
\d 一位数字 => [0-9]
\w 一位字母,数字或_ => [0-9A-Za-z_]
\s 一位空字符: 空格,Tab...
. 通配符(匹配除回车、换行\n\r外的任意字符)
\D 类似[^0-9],非数字
\W 类似[^0-9A-Za-z_],除\w外的符号
\S 非\s的所有内容
\***: 是转义字符,表示引用符 比如: \. 匹配点字符 \$匹配美元符号
空字符和空字符串不一样,空字符用|表示
4.量词
什么是: 规定一位字符集出现次数的规则
何时: 只要规定一位字符集出现的位数/次数
如何: 量词必须紧跟在修饰的字符集之后,用来修饰相邻的前一个字符集
包括: 2大类:
① 有明确数量边界的:
字符集{n,m} 至少n个,最多m个
字符集{n,} 至少n个,多了不限
字符集{n} 必须n个
② 没有明确数量边界的:
字符集? 可有可无,最多1个
字符集* 可有可无,多了不限
字符集+ 至少一个,多了不限
5.选择和分组
选择:或
何时: 只要在多个规则中,任选其一匹配时
规则1|规则2|规则三... (只要满足3个规则之一即可) /*|在正则中,优先级最低*/
分组: 用()将多个规则分为一组
何时: 只要希望一个量词同时修饰多个字符集时,就要先将多个字符集分为一组(),再用量词修饰分组
为什么: 默认字符集仅修饰相邻的前一个字符集
比如: var reg=/(\d{2})\/(\d{2})\/(\d{4})/g; //将'07/29/2017'分为3组
反向引用:
var str = '2017-07-29'.replace(/(\d{4})-(\d{2})-(\d{2})/g, '$2/$3/$1'); //str: 07/29/2017
忽略分组: 不希望捕获某些分组,只需要在分组内加上?:即可
var str = '2017-07-29'.replace(/(?:\d{4})-(\d{2})-(\d{2})/g,'$2/$1'); //str: 29/07
$1~$9存放着正则表达式中最近的9个正则表达式的提取结果,这些结果按照子匹配的出现顺序依次排列
语法: RegExp.$n
这些属性是静态的,除了replace中的第二个参数可以省略RegExp外,其它地方使用都要加上RegExp
身份证号: 15位数字 2位数字 1位数字或Xx /*后两部分,可有可无,最多1次*/
reg = \d{15} (\d\d [0-9Xx]) ?
reg = /(^[1-9]\d{5} (18|19|([23]\d))\d{2} ((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31) \d{3}[0-9Xx]$)|(^[1-9]\d{5} \d{2} ((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31) \d{2}$)/
手机号: +86或0086 可有可无,最多一次
空格 可有可无,多了不限
1
3,4,5,7,8 选一个
9位数字
(\+86|0086)?\s*1[34578]\d{9}
reg = /^0?(13[0-9]|14[57]|15[012356789]|17[013678]|18[0-9])\d{8}$/
微 信 wei xin w x
(微|w(ei)?)\s*(信|x(in)?)
6.指定匹配位置:3种:
^字符串开头,比如: 字符串开头的空字符:^\s+
$字符串结尾,比如: 字符串结尾的空字符:\s+$
比如: 开头或结尾的空字符:^\s+|\s+$
\b单词边界:包括: ^$ 空格 标点符号,比如: 查找单词no,匹配单词no: \bno\b
纯英文格式电子邮件: var reg = /^[0-9A-Za-z_-]+@[0-9A-Za-z_-]+(\.[0-9A-Za-z_-]+)+$/
银行卡: 借记卡、储蓄卡19位, 贷记卡、信用卡16位, 存折17位
\B 非单词边界
var reg = /([a-z])\1*/ig; //定义正则表达式变量
var reg =new RegExp("^[a-zA-Z]{9,20}$");
var kw = str.match(reg); //使用此变量时,不需使用斜杠
判断是否是图片(带参数): /\.(png|jpe?g|gif|svg)(\?.*)?$/.test(str)
判断是否是视频(带参数): /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/.test(str)
_______________________________________________________________________________________________
/([a-z])\1*/ //表示: 第一位必须是小写字母,\1表示匹配和第一个()中完全相同的内容
*表示可有可无,多了不限,就算没有和它匹配的也选择它
+表示至少一个,多了不限,有一个和它匹配的才选择它
当 ? 紧跟在任何一个其他限制符(* + ? {n} {n,} {n,m})后面时,匹配模式是非贪婪的,会尽可能少的匹配所搜索的字符串
默认的贪婪模式则尽可能多的匹配所搜索的字符串
例如: 对于字符串"oooo","o+"将尽可能多的匹配"o",得到结果 ['oooo'],而 "o+?" 将尽可能少的匹配"o",得到结果 ['o','o','o','o']
m 多行,将开始和结束字符(^和$)视为在多行上工作,也就是分别匹配每一行的开始和结束(由 \n 或 \r 分割),而不只是只匹配整个输入字符串的最开始和最末尾处
s 与m相反,单行匹配
第七章*****************************************************************************************
四、RegExp类型
什么是: 专门封装一条正则表达式,并提供使用正则表达式执行查找和验证的API
何时: 1. 使用正则表达式验证用户输入的字符串格式
2. 即查找关键词内容,又查找关键词位置
如何:
创建: 2种
① 直接量(字面量)
var reg=/正则/ig; //i: 忽略(ignore)大小写;g: 查找全部(global)
何时: 如果正则表达式是固定不变的
强调: //之中不支持js表达式,不支持动态生成正则表达式,如果再出现/,就必须改为\/
② 使用正则表达式的构造函数
var reg=new RegExp("正则","ig");
如: var reg=new RegExp("^[a-zA-Z]","g") //使用引号时,不加斜杠
var reg=new RegExp(/^[a-zA-Z]/,"gi") //有斜杠时,不加引号
何时: 如果正则表达式需要动态拼接生成
强调: ""中再出现\或",都要改为\\和\"
API: 2个
① 即查找内容,又查找位置
var arr=reg.exec(str) /*在str中依次查找下一个符合reg规则的关键词的内容和位置*/
返回值: 返回一个数组arr: 与正则表达式匹配的文本,后面依次为各个子表达式()的文本,用逗号分隔
最后一个arr["input"] 是要查找的内容str
arr[0]本次找到的关键词的内容
arr["index"]本次找到的关键词的下标位置
如果没找到,就返回null
问题: 每次只返回本次找到的一个关键词
解决: 用循环反复调用reg.exec
原理: 每次调用exec,做3件事:
1. 将本次找到的关键词保存在arr的0位置
2. 将本次找到的关键词位置保存在arr的index位置
3. 每个reg对象都有一个.lastIndex属性, 标识下次开始的查找位置,开始时为0
每执行完一次exec,exec会自动修改为: reg.lastIndex=当前位置index+关键词长度
function cha(str){
var reg=/./g; //在全局查找关键词
for(var i=0;i<str.length;i++){ //str.length: 字符串的长度
var arr=reg.exec(str);
console.log(arr[0]); //关键词的内容
console.log(reg.lastIndex-1); //关键词的下标位置
} }
② 验证字符串的格式
var bool=reg.test(str); /*验证str是否符合reg的规则要求*/
验证通过返回true,不通过返回false,可直接当做判断条件
问题: test默认只要部分匹配就返回true
解决:从头到尾完全匹配(验证),必须在正则表达式中: 前加^,后加$
_______________________________________________________________________________________________
五、Math类型
什么是: 专门保存数学计算的常量和函数的对象 的API
何时: 只要进行数学计算
如何:
创建: Math不用创建,不能new,直接使用
所有常量和API都用Math直接调用
API
取整: 3种:
1.上取整: 只要超过,就取下一个整数
Math.ceil(num)
2.下取整: 只要超过,就省略小数部分
Math.floor(num)
Math.floor(num) VS parseInt(str)
只能对纯数字 能先去掉数字之后的非数字字符,再取整
3.四舍五入取整
Math.round(num)
Math.round VS n.toFixed(d)
缺: 只能取整,不能指定小数位数 优: 可指定任意小数位数四舍五入
金钱: Number(parseFloat(num).toFixed(2))
优: 将返回number,可直接计算 缺: 将返回字符串类型,需要先转换为数字类型,再计算
可自定义round函数
4. 乘方和开平方
Math.pow(底数,幂); 乘方
Math.sqrt(n); 开平方
5. 最大值和最小值
Math.max(值1,值2,值3,...)
Math.min(值1,值2,值3,...)
问题: max/min不支持获得数组中的最大/小值,求出数组中的最大/最小值
解决:Math.max.apply(null,arr) /*apply: 调用,可自动打散数组类型参数*/
6. 随机数
Math.random() 取值: 0~1,默认得到一个随机小数
公式:在任意[min,max]之间生成一个随机整数:var r=parseInt(Math.random()*(max-min+1)+min)
简写: 如果min=0,即[0, max]之间: var r=parseInt( Math.random()*(max+1) )
例: 随机数组中的数:var index = parseInt(Math.random()*arr.length)
_______________________________________________________________________________________________
六、Date类型
什么是: 专门封装一个时间点,并提供操作时间的API
何时: 只要存储时间或者计算时间
如何:
创建: 4种
1. 创建日期对象,并自动获得当前系统时间
var now=new Date();//强调: 只能获得客户端本地时间,标准格式,即格林尼治标准时(GMT)
2. 创建日期对象,并封装自定义时间点
var date=new Date("yyyy/MM/dd hh:mm:ss"); /*字符串中的月份为自动-1后的值*/
//时间格式也可为: '2017-12-30 21:15:00'
//或: 2018-03-06T17:12(部分浏览器有时差问题)
部分手机(如iPhone)获取时间的方式与其它浏览器不同,需要兼容处理:
new Date("2017-02-05 12:10:10.12")可能会发生错误,函数返回错误是"Invalid Date"
var str = "2018-04-13 22:45:00";
var arr = str.split(/[- : \/]/);
var date = new Date(arr[0], arr[1]-1, arr[2], arr[3], arr[4] || '00', arr[5] || '00');
因为iOS不能识别 - 形式,也可以替换为斜杠形式:
date = date.replace(/-/g, '/'); // 2018/06/03 00:00:00
若不是字符串: var date=new Date(yyyy, MM-1,dd,hh,mm,ss);
如果只关心日期,不关心时间,后半部分时分秒可省略。省略后,默认是00:00:00
3. 用毫秒数创建日期对象
原理: 日期对象中保存的是1970年1月1日0点至今的毫秒数———整数
为什么: 时间段,不受时区影响
相同的毫秒数: 在不同时区可显示不同的时间点
总结: 将来数据库中保存的时间都是毫秒数,不要用文字
何时: 只要将毫秒数转化为当地时间格式时
var ms=date.getTime(); /*将标准格式的date转化为毫秒数 ms*/
var now=new Date().getTime(); //获取客户端1970年1月1日0点至今的毫秒数(缩写),时间戳
//注意时区问题
// +new Date()、Date now() 返回毫秒数
var date1=new Date(ms); //将毫秒数 ms 转化为操作系统当前所在时区的对应时间(必须是Number类型)
4. 复制一个日期对象:
为什么: 日期的计算只能直接修改原日期对象
后果: 计算后,无法保存计算前的原日期
何时: 如果用户希望同时保留计算前后的开始时间和结束时间时,都要先将开始时间复制一份,再用副本计算结束时间
如何:
var date2=new Date(date1);
_______________________________________________________________________________________________
API: 3句话:
1. 8个单位: FullYear年 Month月 Date日 Day星期 ———没有s
Hours小时 Minutes分钟 Seconds秒 Milliseconds毫秒 ———都以s结尾
2. 每个单位都有一对儿getXXX()/setXXX()方法
getXXX() 负责获得指定单位上的数值
setXXX(n) 负责修改指定单位上的数值,可自动调整时间进制
特例: Day(星期)没有setXXX()方法
3. 取值范围:除date(从1开始,31结束)外,其余都是从 0 开始到进制减 1 结束
FullYear: 和现实中年份一致
Month: 0~11 现实中: 1~12,计算机中的月份值比现实中少1,需要修正
Date: 1~31 和现实一样
Day: 0~6 现实: 日~六,和现实中一致
Hours: 0~23 和现实一样
Minutes/Seconds: 0~59 和现实一样
_______________________________________________________________________________________________
日期计算
1. 两日期对象可相减: 结果是毫秒差(ms),可用于倒计时
2. 对任意单位做加减:3步:
①取值: var date1=now.getDate();
②做加减: date1+=30;
例如: 16+30=46
③放回去: now.setDate(date1); /*setDate可自动调整进制*/
简写:now.setDate(now.getDate()+n);
问题: setDate直接修改原日期对象,无法保留开始时间
解决: 在计算前,都要先将开始时间复制一个副本,再用副本计算结束时间
倒计时:
now/=1000, end/=1000;
放在定时器中:
now++;
varT = parseInt((end-now)/1000); //共剩多少时间(单位:秒)
var d = parseInt(T/(3600*24)); //剩多少天
var h = parseInt(T%(3600*24)/3600); //剩多少小时
var m = parseInt(T%(3600)/60); //剩多少分钟
var s =T%60; //剩多少秒
日期格式化(new Date()系统时间,转字符串)
date.toString() 返回当地时间格式的完整版本(系统时间格式)
date.toLocaleString() 返回当地时间格式的简化版本(有时分秒),不同平台有可能不一样
date.toLocaleDateString() 仅保留了日期部分
date.toLocaleTimeString() 仅保留了时分秒部分
date.toGMTString() 获得 0 时区的国际标准时间
_______________________________________________________________________________________________
new Date($.ajax({async: false}).getResponseHeader("Date")); //获取服务器相应头附带的时间
输出客户端时间:
var weeks=["星期日","星期一","星期二","星期三","星期四","星期五","星期六"];
function fillTime(time){ return time>=10?time:"0"+time; } //补全时间
var now = new Date();
var day = now.getDay();
var year = now.getFullYear(); //年份
var month = fillTime(now.getMonth()+1); //月份
var date = fillTime(now.getDate()); //日期
var hours = fillTime(now.getHours()); //小时
var minutes = fillTime(now.getMinutes()); //分钟
var seconds = fillTime(now.getSeconds()); //秒
var dateTime=year+'-'+month+'-'+date+' '+hours+':'+minutes+':'+seconds+'('+weeks[day]+')';
console.log(dateTime); //2017-09-02 13:21:06(星期六)
const formatNumber = n =>{
n = n.toString()
return n[1] ? n : '0' + n
}
const formatTime = date =>{
const year = date.getFullYear()
const month = date.getMonth() + 1
const day = date.getDate()
const hour = date.getHours()
const minute = date.getMinutes()
const second = date.getSeconds()
return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':')
}
获取相邻的一段天数:
var base = +new Date(2018, 1, 1); //获取时间的毫秒数
var oneDay = 24 * 3600 * 1000;
for (var i = 0; i < 500; i++){
var now = new Date(base += oneDay);
date.push([now.getFullYear(), now.getMonth() + 1, now.getDate()].join('/'));
}
UTC时间和GMT(本地)时间之间的转换:
GMT转为UTC:
var now = new Date();
var nowUTC = new Date(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(),
now.getUTCHours(), now.getUTCMinutes(), now.getUTCSeconds());
UTC转为GMT:
var nowGMT = Date.UTC(nowUTC.getFullYear(), nowUTC.getMonth(), nowUTC.getDate(),
nowUTC.getHours(), nowUTC.getMinutes(), nowUTC.getSeconds());
var now = new Date(nowGMT)
注: 以北京时间为准,UTC总是比GMT小8个小时
常用API***************************************************************************************
Math.atan(n) //返回'反正切函数'arctan(n)的值,单位弧度,可转换为角度
例: (Math.atan(a/b))*180/Math.PI
Math.abs(x) //返回数字的绝对值
例: Math.abs(a) || 1;
Math.min(x,y) //返回指定的数字中带有最低值的数字
stringObject.substr(start,length) //从字符串中抽取从start下标开始的指定数目(length)的字符
+str+1 //+可使字符串变为数字类型再计算
x=Number(x); //手动将字符串类型的数字转换成Number类型,不直接修改原变量的值,而是返回新值