目录
什么是函数
什么是函数:函数又叫方法,在程序里面函数是用来执行某些特定功能的代码。为了减少重复使用代码,可以把特定功能的代码做成函数,需要使用时拿出来调用
这里和大家解释一下函数与事件的区别:
事件是在特定条件下触发的行为,函数则是实现特定功能的行为的具体的体现。比如你在人格受到侮辱时你会愤怒,那么“当愤怒时”就是事件,而你愤怒的时候会具体做什么,也就是你对这个事件的具体反映,由函数来完成;比如你愤怒时会打架(fighting),那么打架就是函数。简单来说,事件是 ‘怎么了’,函数就是 ‘怎么办’
如何去创建函数:
1、声明:
function 函数名(参数变量列表){
函数体;
return 返回值;
}
参数:接收传入函数中必要数据的变量 参数用法和普通变量完全一样,只不过不用var声明
什么时候会用到参数:如果一项任务必须某些数据才能正常执行时,就必须定义参数
返回值:函数执行的结果
什么时候会用到返回值:如果调用者需要获得函数的执行结果时,就用return返回结果
return的作用:
1、退出函数执行——可单独使用
2、退出函数时,顺便返回结果 如果函数没有返回任何结果,就返回undefined
2、调用: 让引擎按照函数的步骤清单执行一项任务
什么时候调用:函数只有调用才执行,不调用不执行!
var 返回值=函数名(参数值列表)
作用域 scope: 变量的使用范围
什么是作用域:变量的可用范围 可以避免不同范围的变量之间互相污染
作用域可分为:全局作用域(window)、函数作用域
全局作用域
什么是全局作用域:程序中的任何位置都可以访问的范围 保存全局变量
全局变量:保存在全局作用域中,程序任何位置都可使用的变量 随处可用, 可反复使用 只要希望随处可用的公共变量 只要不属于任何函数的变量,自动都是全局的
优:随处可用, 可反复使用
缺:易造成全局污染
函数作用域
什么是函数作用域:仅函数内可用的范围 保存局部变量
局部变量:保存在函数作用域中,仅函数内可用的变量 仅函数内可用,不可反复使用 只限于当前函数内使用,函数外不可用时
局部变量有两种:1、在函数内声明的变量 2、函数的参数变量也是局部变量
变量使用顺序: 优先使用函数内的局部变量 局部没有,才去全局找
优:仅函数内可用,不会被污染
缺:不可重用
声明提前
什么是声明提前:在程序开始执行前,都会将var声明的变量和function声明的函数,提前到当前作用域的顶部,集中创建。赋值留在原地。再开始执行程序。
但是声明提前破坏了程序默认的执行顺序
解决:
1、将所有的变量和函数声明都集中在当前作用域顶部
2、ES6:let代替var let禁止在声明之前提前使用变量 强制将声明集中在当前作用域顶部创建 限制:不能用let反复创建相同名称的变量
3、函数: 第2种创建函数的方式:
var函数名=function (参数变量列表){... ...}
用以上方式创建的函数不会被声明提前
按值传递
什么是按值传递:两变量间赋值或将变量传入函数作为参数时,其实只是将原变量中的值复制一个副本给对方
原始类型的值:修改新变量,不影响原变量的值
全局函数
什么是全局函数:ES标准中规定的,浏览器已经实现的,不需要任何前缀.就可直接调用的函数
比如:Number() String() Boolean() isNaN() parseFloat() parseInt()
编码解码:特指对地址栏中的url内容进行编码和解码
什么是编码:将url中包含的多字节字符编码为单字节字符
为什么:url规定地址中不能包含多字节字符 如果包含,会乱码
何时:只要url中可能包含多字节字符,都要将其编码为单字节字符
如何:var code=encodeURI(url)
解码:将编码后的单字节字符串解码回多字节原文
何时:只要收到的是编码后的字符串,都要先解码再使用
如何:var str=decodeURI(code)
问题:url中不但不允许多字节字符,而且还不允许出现保留了字符: 比如: / 但是encodeURI无法对保留字编码
解决:用encodeURIComponent代替encodeURI 用decodeURIComponent代替decodeURI
eval:专门执行一个字符串格式的js语句
分支结构
分支结构:让程序根据不同的条件执行不同的操作
什么时候用到:只要让程序根据不同的条件执行不同的操作
怎么用:
1、一个条件,一件事,满足就执行,不满足就不执行:
如果操作简单:短路:条件&&(操作1,操作2,...)
如果操作复杂:if结构
if(条件){
操作;
}
2、一个条件,两件事,二选一执行
如果操作复杂: if...else结构
if(条件){
满足条件才执行的操作
}else{
不满足条件时执行的操作
}
如果操作简单: 三目/三元/条件运算
条件?操作1:操作2;
如果只是根据不同的条件,使用不同的值:
条件?值1:值2
如果满足条件使用值1,否则使用值2
3、多个条件,多件事,多选一执行
如果操作复杂: if...else if...结构
if(条件1){
操作1
}else if(条件2){
操作2
}else if(...){
...
}else{
默认操作
}
注意:
1、如果程序进入后一个条件,则暗示前一个条件不满足
2、最后一个else可省略,后果,如果一个条件都不满足,则什么也不做
如果操作简单:三目
条件1?操作1:
条件2?操作2:
... ? ...:
默认操作 ——不能省略
如果只是根据不同条件选择不同的值:
条件1?值1:
条件2?值2:
... ? ...:
默认值
如果所有条件都是等于比较:还可用switch case结构
switch(表达式){//首先计算表达式的值
case 值1: //如果表达式的值*全等*于值1
操作1; //则执行操作1
break;
case 值2://否则如果表达式的值*全等*于值2
操作2; //则执行操作2
break;
case ... :
... ... ;
break;
default: ——可省略
默认操作;
}
问题:switch意为入口 只要匹配一个case,就进入执行,并触发之后所有case的操作。
解决:打断每个case之间的联系: break; break: 专门负责中止并退出结构
如何:在每个case之间都要加break
循环
循环:让程序反复执行相同代码段
何时:只要让程序反复执行一项任务时
如何:三要素:
1、循环条件:让循环可以继续执行的条件 只要循环条件满足,就可以反复执行循环 直到循环条件不满足时,就退出循环
2、循环变量:循环中用作比较和判断的变量
考虑:1. 从几开始 2. 到几结束 3. 每次递增/递减几
3、循环体:循环要反复执行的代码段
如果循环条件始终为true,则循环永远无法退出——死循环
while循环:先判断循环条件,再决定是否执行循环
何时:要求必须先满足条件,才能执行循环时
//声明并初始化循环变量
var 变量=值;
while(循环条件){
反复执行循环体;
修改循环变量的值;
}
do...while循环:先至少执行一次循环,再判断循环条件,决定是否反复执行
何时:只要希望即使条件不满足,也至少能执行一次时
//声明并初始化循环变量
var 变量=值;
do{
反复执行循环体;
修改循环变量的值;
}while(循环条件) ;//当满足(循环条件)时
while vs do...while
只要第一次条件都满足,则两者完全一样
如果第一次条件不满足,while是一次都不执行 do while至少可执行一次
for循环:其实就是while循环的简化
何时:只要循环变量的变化有规律
for(var 变量=值;循环条件;修改循环变量的值){
反复执行循环体;
}
简写:
1. 分支/循环结构中,如果条件之下只有一条语句,则可省略{}, 但强烈不建议这样做——容易出歧义
2. 其实,第一部分可同时声明并初始化多个变量,多个变量间用逗号分隔:
3. 其实,第三部分可同时执行多个短小的语句,用逗号分隔,但是,简写不能破坏原执行顺序 如果省略循环体,则for循环后必 须加 " ; "
强调:js中没有块级作用域 分支结构/循环结构内声明的变量,出了结构依然可用
循环嵌套
什么是循环嵌套: 一个循环的循环体内,又执行了另一个内层循环
内置对象/包装类型
内置对象
什么是:ES标准中规定的,浏览器已经实现的对象
包括:11个
String Number Boolean ——包装类型
Array Date RegExp Math
Error
Function Object
Global——在浏览器中被window替换
包装类型
什么是:专门封装原始类型的值并提供操作原始类型值的API
为什么:原始类型的值本身不具有任何的功能 才需要包装类型对象的帮助,完成功能
何时:只要试图用原始类型的值调用函数时,都会自动创建对应包装类型的对象,封装要操作的值,并使用函数执行功能。
如何:不用手动使用
比如: n.toFixed(2) => new Number(n).toFixed(2);
"张".charCodeAt() => new String("张").charCodeAt();
String
什么是string:由多个字符组成的只读字符数组
string vs 数组:
相同:1、下标; 2、.length; 3、.slice()
不同:类型不同: API不通用
API
大小写转换:将str中的字母都转为统一的小写/大写
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,只不过不支持负数参数
str.substr(starti,n) 从starti开始,获取n个字符
查找关键词:4种
1、查找一个固定的关键词
var i=str.indexOf("关键词",fromi);
在str中fromi位置之后,查找下一个"关键词"的位置
返回:如果找到,返回关键词的下标位置 i 如果没找到,返回-1
var i=str.lastIndexOf("关键词");
在str中找最后一个关键词的位置i
问题:每次只能查找一种关键词
解决:正则表达式模糊匹配多种关键词:
2、判断是否包含敏感词
var i=str.search(/正则/i);
在str中找第一个符合正则要求的敏感词的位置
返回值:如果找到,返回下标位置 如果没找到,返回-1
问题:默认正则表达式都是区分大小写
解决:在第二个/后加后缀i, ignore,表示忽略大小写
问题:永远只能找第一个,无法找所有 仅返回位置,无法返回内容
3、查找所有敏感词的内容
var kwords=str.match(/正则/ig);
返回值:kwords中保存所有找到的敏感词 如果找不到,返回null
问题:默认正则表达式只匹配第一个符合条件的敏感词
解决:在第二个/后加g, global 全部
问题:只能获得内容,无法获得每个敏感词的位置
4、即查找每个敏感词的内容,又查找位置:regExp.exec()
替换
什么是:将字符串中符合规则的敏感词替换为新内容
如何:2种
1、简单替换: 将所有敏感词替换为同一种新值
str=str.replace(/正则/ig,替换的新值)
强调:所有字符串API都无权修改原字符串,只能返回新字符串
2、高级替换:根据敏感词的不同,动态选择替换为不同的值
str=str.replace(/正则/ig,function(kw){
kw //自动获得本次找到的敏感词
return 根据不同的kw返回不同的值
})
衍生:删除: 将关键词替换为 " "
切割
什么是:将字符串按指定的关键词切割为多段子字符串
如何:2种
1. 简单:分隔符是固定的:
var subStrs=str.split("分隔符")
返回: 多个子字符串的数组
切割后的结果中,不包含分隔符的
2. 复杂:分隔符不是固定的
var subStrs=str.split(/正则/)
固定套路:将字符串打散为字符数组:
var chars=str.split("");
正则表达式
什么是:规定字符串中字符出现规律的规则
何时:2大用途
1. 通过规则,模糊查找多种关键词
2. 验证用户输入的格式
如何:
1. 关键词原文本身就是最简单的正则表达式
2. 字符集
什么是:规定一位字符备选字符列表的集合
何时:只要一位字符有多种可能备选时
如何:[备选字符列表]
强调:不要用逗号分隔 每个[]只规定一位字符的备选字
简写:
1. 如果部分备选字符的unicode是连续的,可用-省略中间字符
比如:一位数字: [0-9]
一位小写字母:[a-z]
一位大写字母:[A-Z]
一位字母: [A-Za-z]
一位汉字:[\u4e00-\u9fa5]
2. 除了xxx
[^xxx] 比如: 除了4和7都行!
3. 预定义字符集
什么是:对常用特定字符集的更简化写法
包括:4个
\d => [0-9]
\w => [A-Za-z0-9_]
\s => 空字符: 空格, Tab...
. 匹配任意字符
4. 量词
什么是:规定一位字符集出现次数的规则
何时:只要规定一位字符集出现的次数
如何:量词紧跟在修饰的字符集之后
2大类
1. 有明确数量边界的:
字符集{n,m} 最少n个,最多m个
字符集{n,} 至少n个,多了不限
字符集{n} 必须n个
2. 没有明确数量边界:
字符集? 可有可无,最多1次
字符集* 可有可无,多了不限
字符集+ 至少一个,多了不限
5. 选择和分组
选择:或
何时:只要在多个规则中任选其一匹配时
如何:规则1|规则2
只要满足两个规则之一即可!
分组:()
何时:只要希望一个量词同时修饰多个字符集时 就要将要修饰的字符集放入一个()中作为一组。再用量词修饰()
为什么:默认一个量词只能修饰相邻的前一个字符集
比如:身份证号:15位数字 2位数字 1位数字或Xx
整体可有可无,最多一次
\d{15} ( \d\d [0-9Xx] ) ?
手机号:
+86或0086 可有可无,最多1次
空格 可有可无,多了不限
1,3,4,5,7,8中挑一个 9位数字 (\+86|0086)?\s*1[34578]\d{9}
(微|w(ei)?)\s*(信|x(in)?)
6. 指定匹配位置:3个
开头:^ 比如: 匹配开头的空字符: ^\s+
结尾:$ 比如: 匹配结尾的空字符: \s+$
比如:开头或结尾的空字符: ^\s+|\s+$
单词边界:\b 包括: 空格, 标点, 开头, 结尾
比如:匹配单词no: \bno\b
RegExp
什么是:专门封装一条正则表达式,并提供用正则表达式执行验证和查找的API
何时:
1. 验证字符串的格式
2. 即查找内容,又查找位置
如何创建:
1. 直接量: var reg=/正则/ig;
何时:如果正则表达式是固定不变的
问题://之中不支持js表达式,也就是不支持动态生成正则表达式
2. 用new: var reg=new RegExp("正则","ig")
何时:如果正则表达式需要动态拼接生成
API:
1. 验证字符串的格式
var bool=reg.test(str);验证str是否符合reg的规则要求
返回:bool,可直接当做判断条件
问题:test默认只要部分匹配就返回true
解决:从头到尾完整匹配: 必须前加^后加$
2. 即查找所有关键词内容,又查找位置
reg.exec(str) 依次查找str中下一个关键词的内容和位置
返回值:数组: [0: 关键词内容, index: 下标位置] 如果找不到, 返回null
问题:每次只返回本次找到的一个关键词
解决:用循环反复调用reg.exec
原理:每次调用exec,做3件事
1. 将本次找到的关键词保存在数组0位置
2. 将本次找到的关键词位置保存在数组index位置
3. 修改reg对象的lastIndex=index+关键词的字数
reg.lastIndex : 记录下次开始查找位置, 默认为0
Math
什么是:专门保存数学计算的常量和函数的对象
何时:只要进行数学计算
如何创建:Math不能new!不用创建!
所有常量和API都用Math直接调用!
API:
取整
1. 上取整: 只要超过,就取下一个整数
Math.ceil(num)
2. 下取整: 舍弃小数部分
Math.floor(num) 只能对纯数字
vs parseInt(str) 能去掉数字之后非数字字符,再取整
3. 四舍五入取整: 够5进1,不够舍弃
Math.round(num) 优: 返回number类型的数值,可直接用于计算。
缺: 不能指定小数位数,只能取整
vs n.toFixed(d) 缺: 返回字符串类型,计算前必须先转换为数字。
优: 可指定小数位数,按任意小数位数四舍五入。
乘方和开平方:
乘方:Math.pow(底数,幂)
比如:10的2次方:Math.pow(10,2)=100
开平方:Math.sqrt(num)
比如:Math.sqrt(9) = 3
最大值/最小值:
Math.max(值1,值2,...)
Math.min(值1,值2,...)
问题:不支持获得数组中的最大值
解决:Math.max.apply(null,arr)
其中:apply表示"调用"的意思 还可自动打散数组类型参数!
随机数:
0<=Math.random()<1
公式:在任意范围min~max内生成随机整数
var r=parseInt(Math.random()*(max-min+1)+min);
简化:如果从0开始
var r=parseInt(Math.random()*(max +1));
Date
什么是:专门封装一个时间点,并提供操作时间的API
何时:只要存储时间或计算时间
如何创建:
1. 创建日期对象并自动获得当前系统时间
var now=new Date();
强调:new Date()只能获得客户端本地时间
2. 创建日期对象并封装自定义时间
var date=new Date("yyyy/MM/dd hh:mm:ss");
new Date(yyyy,MM-1,dd,hh,mm,ss)
3. 复制一个日期对象
为什么:日期计算都是直接修改原日期对象 计算后,无法保存计算前的原日期
何时:如果用户希望同时保留计算前后的开始和结束时间时,都要先将开始时间复制一个副本,再用副本计算结束时间。
如何:var date2=new Date(date1);
4. 用毫秒数创建日期对象
为什么:将来数据库中保存的时间都是毫秒数
何时:只要将毫秒数转化为当地时间格式
var date=new Date(ms)
其中new Date会将ms转化为操作系统当前所在时区的对应时间显示
获得日期中的毫秒数: var ms=date.getTime();
原理:其实日期对象中保存的是1970年1月1日0点至今的毫秒数
为什么:毫秒数不受时区影响
API:
1. 8个单位:
FullYear Month Date Day ——没有s
Hours Minutes Seconds Milliseconds 都以s结尾
2. 每个单位都有一对儿get和set方法
其中:get负责获得指定单位上的数值 set 负责修改指定单位上的数值
比如:date.getFullYear() date.getMonth()...
date.setFullYear(n) date.setMonth(n)...
强调:setXXX(n)可自动调整时间进制:
特例:Day没有set
3. 取值范围
除date外,其余都是从0开始到进制-1结束
date从1开始,到31结束
Month: 0~11 都比现实中小1
Date: 1~31 和现实相同
Day: 0~6和现实相同 星期日为0
Hours: 0~23和现实相同
Minutes/Seconds: 0~59和现实相同
计算:
1. 两日期对象可相减:结果毫秒差
何时:倒计时
2. 对每个单位做加减
1. 取值:var d=now.getDate(); //d=8
2. 做加减:d+=30; //d=38
3. 放回去:now.setDate(d) //自动调整进制 // 6/7
简化:now.setDate(now.getDate()+n)
日期格式化
.toString() 返回当地时间格式的完整版本
.toLocaleString() 返回当地时间格式的简化版本
.toLocaleDateString() 仅保留日期部分
.toLocaleTimeString() 仅保留时间部分
.toGMTString() 获得0时区的标准时间