高阶函数
- 函数作为参数
- 函数作为返回值的时候
作为参数
function eat(fn){
setTimeout(function(){
console.log('吃晚饭');
//吃完晚饭之后做的事情
fn();
},2000);
}
eat(function(){
console.log('去唱歌')
});
回调函数
回调函数就是一个参数,将这个函数作为参数传到另一个函数里面,当那个函数执行完之后,再执行传进去的这个函数。这个过程就叫做回调。
//定义主函数,回调函数作为参数
function A(callback){
callback();//需要在主函数内调用
console.log('我是主函数')
}
//定义回调函数
function B(){
setTimeout("console.log('我是回调函数')",3000)
}
//调用主函数,将函数B传进去
A(B);
//--->我是主函数
//--->我是回调函数
//主函数执行完,回调作为参数的B函数,这个过程叫回调
函数作为参数案例
var arr=[5,8,3,12];
//sort()中有个参数为函数,这个函数有2个参数,a,b,这个函数的返回值,返回>0 或<0 或=0
arr.sort(function(a,b){
return a-b;
});
console.log(arr)//-->arr[3,5,8,12]
//自己定义sort(sort的运行原理)
//给Array数组原型对象增加一个方法
Array.prototype.mySort=function(fn){//此处的函数在外部调用时,
//要传两个参数并定义下是返回>0 或<0 或=0,来决定这个数组是从大到小还是从小到大排序
//外层循环控制趟数
for(vari=0;i<this.length-1;i++){
//内层循环
var isSort=true;//假设排好顺序
//是否真的排好序?看内层循环是否交换顺序
//内层循环次数为this.length-i-1
for(var j=0;j<this.length-i-1;j++){
//判断第一项如果比后一项大,就交换顺序
if(fn(this[j],this[j+1])>0){
//fn(a,b),把相邻的两项传给fn,并和0比较
isSort=false;//如果>0,就没排好序,isSort为false
var tmp=this[j];
//定义一个中间变量,并给this[j]重新赋值this[j]=this[j+1];
//交换顺序
this[j+1]=tmp;
}
}
if(isSort){
//排好序就终止循环
break;
}
}
}
函数作为返回值
//函数:生成1-10的随机整数
//Math.random生成的是0-1之间的小数,[0,1)
function getRandom(){
return parseInt(Math.random()*10)+1
}
//生成1-10的随机整数,并且在第一次调用后生成的随机数,以后的每一次调用都返回第一次的随机值
function getRandom(){
var random = parseInt(Math.random()*10)+1
//这个函数返回了一个函数
return function(){
//返回父函数的random
return random;
}
}
//调用getRandom返回的是一个函数,需要用变量接收
var fn=getRandom();
console.log(fn)
//求两个数的和
//100+m 1000+m 10000+m
function getFun(n){//n指的是100/1000/10000
return function(m){
return n+m;
}
}
//求100+m
var fn100=getFun(100);//100-->n
//求1000+m
var fn1000=getFun(1000);
console.log(fn100(1));//1-->m
console.log(fn1000(1));
闭包
闭包就是能够读取其他函数内部变量的函数。
在js中,只有函数内部的子函数才能读取取局部变量
闭包可以在一个作用域中可以访问另一作用域的变量
闭包的用途
- 可以在函数外部读取函数内部成员
- 让函数内成员始终存活在内存中
- 闭包特点:延展了函数的作用域范围
闭包案例
<ul id="heros">
<li>安其拉</li>
<li>李白</li>
<li>诸葛亮</li>
<li>狄仁杰</li>
</ul>
<script>
//方式一,对象的自定义属性:
//给li注册点击事件
var heros = document.getElementById("heros")
var list = heros.children
for(var i = 0; i < list.length; i++){
var li=list[i];
list[i].index=i;//给li用index记录索引,等于循环的每一项i
//第一次循环的i=0,记录给第一个li
list[i].onclick=function(){
//点击li的时候输出当前li对应的索引
// console.log(i);//-->4
//循环的过程中,没有触发函数,就会继续循环,循环到最后,i=4,
//因为此时的function是在for循环结束后调用
console.log(this.index)//-->this是点击的li,index为他的索引
}
}
//方式二,闭包:
var heros = document.getElementById("heros")
var list = heros.children
for(var i = 0; i < list.length; i++){
var li=list[i];
<!--下面这个自调用函数,每循环一次触发调用一次,给每个i的li注册点击事件-->
(function(i){
list[i].onclick=function(i){
//点击li的时候输出当前li对应的索引
}
})(i)//自调用函数
}
</script>
闭包案例
字体大小
<button id="btn1">按钮1</button>
<button id="btn2">按钮2</button>
<button id="btn3">按钮3</button>
<script>
var btn1=documentElementById('btn1')
var btn2=documentElementById('btn2')
var btn3=documentElementById('btn3')
//创建一个函数,设置body字体大小
function makeFun(size){
return function(){ document.body.style.fontSize=size + 'px'
}
}
//函数嵌套函数,内部函数size访问到了外部函数size的变量,产生了闭包。
//btn1.onclick调用makeFun,返回了他内部的函数,并调用这个函数
btn1.onclick=makeFun(12);
btn2.onclick=makeFun(14);
btn3.onclick=makeFun(16);
</script>
递归
递归:函数自己调用自己
//斐波那契数列1,1,2,3,5,8,
//前两个数相加是后一个数
//前两个个数为n-1 ,n-2
function fn(n){
if(n===1 || n===2){
return 1;
}
return fn(n-1) + fn(n-2)
}
对象的拷贝
var obj1={
name:'郑州',
age:19,
sex:'男'
}
var obj2={}
//封装函数 把o1的成员复制给o2
function copy(o1,o2){
for( var key in o1){
o2[key]=o1[key];
}
}
copy(obj1,obj2);
console.dir(obj2)
-
浅拷贝
只能复制对象的第一层属性,当其中的属性又是一个对象时,只能复制这个对象引用,不能创建一个新的对象 -
深拷贝
如果对象的某个属性为数组或对象,就让他这个属性等于空数组或空对象,再让o1的这个属性拷贝到o2的这个对象中 -
为什么先判断数组?因为数组也是对象,当对象放在前面时候,会把数组一起判断为对象。
var obj1={
name:'郑州',
age:19,
sex:'男'
}
var obj2={}
//深拷贝
function deepCopy(o1,o2){
for( var key in o1){
//如果key是数组Array[]
if(o1[key]instanceof Array){
o2[key]=[]; //初始化一个空数组
deepCopy(o1[key],o2[key]);
}else if(o1[key]instanceof Object){
//如果key是复杂类型Object{}
o2[key]={};
deepCopy(o1[key],o2[key]);
}else{
//如果key这个属性时基本类型
o2[key]=o1[key];
}
}}}
copy(obj1,obj2);
console.dir(obj2)
遍历DOM树
//遍历指定元素下所有的子元素
//增加回调函数,
function loadTree(parent,callback){
//循环结束条件:没有子元素parent.children.length=0
for(var i=0; i<parent.children.length; i++){
//遍历第一级子元素
var child=parent.children[i];
<!--console.log(child);-->
//如果有回调函数,回调函数的参数为child
if(callback){
//处理找到的子元素
callback(child)
}
//调用递归
//子元素作为父元素继续循环遍历子元素
loadTree(child);
}
}
<!--loadTree(document.body)-->
<!--//遍历ul中所有的子元素-->
<!--loadTree(document.getElementById('list'))-->
var ul document.getElementById('list');
//调用loadTree ,回调函数function(element),element为上面的child参数,给这个参数获取点击事件,点击打印元素内容
loadTree(ul,function(element){
element.onclick=function(){
console.log(this.innerText)
}
})
正则表达式
作用
- 给定的字符串是否符合正则表达式的过滤逻辑(匹配)
- 可以通过正则表达式,从字符串中获取我们想要的特定部分(提取)
- 强大的字符春替换能力
- 使用正则表达式找到匹配的做过滤
正则表达式组成
-
普通字符
-
特殊字符(元字符):正则表达式中有特殊意义的字符
元字符 说明
\d 匹配数字
\D 匹配任意非数字的字符
\w 匹配字母或数字或下划线
\W 匹配任意不是字母或数字或下划线
\s 匹配任意空白符
. 匹配换行符意外的任意单个字符
^ 匹配以谁开始的文本
$ 匹配以谁结束的文本限定符 说明
重复0次或更多次
重复1次或更多次
? 重复0次或1次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n次到m次
其他
- [] 字符串用中括号括起来,表示匹配其中的任一字符,相当于或的意思
- [^] 匹配除中括号以内的内容
- \ 转义符
- | 或者,选择两者中的一个。注意|将左右两边分为两部分,而不管左右两边有多长多乱
- () 从两个直接量中选择一个,分组
- eg:gr(a|e)y匹配gray和grey
- [\u4e00-\u9fa5] 匹配汉字
练习
正则表达式工具
//邮箱验证 100010 ---> ^[1-9]\d{5}$
//验证手机号 18820288976 ---> ^[1-9]\d{10}$
//验证日期 2018-8-11 ---> ^\d{4}-\d{1,2}-\d{,2}$
//验证邮箱 xx@sss.com.cn ---> ^\w+@\w+(\.\w)+$
JavaScript 中使用正则表达式
创建正则对象
//第一种方式:
//内置对象 RegExp
//第一个参数 模式 pattern
//第二个参数 flag i 忽略大小写 g 全局匹配
var regularExpression = new RegExp('ab[a-z','i');
var str = 'xyz';
var str2 = 'abc';
console.log(regularExpression.test(str));//-->false
console.log(regularExpression.test(str2));//-->true
//第二种方式
var regularExpression = /ab[a-z]/i;
var str2 = 'abc';
console.log(regularExpression.test(str2));//-->true
跟正则表达式相关的方法
==i 忽略大小写==
==g 全局匹配,全局匹配就可以找到所有符合条件的==
- RegExp对象
- test() 匹配
- exec() 提取,只返回第一个匹配到的结果,没有匹配到就是null
- String对象
- match() 提取多个内容
- replace() 替换 replace(被替换的,替换成什么),只能替换掉第一个查找到的元素
- split() 切割,用什么分割成字符串数组
- search()
exec()
var str = '张三:2500,李四:3000,王五:50000'
var reg = /\d+/gi;//全局匹配并且忽略大小写
//循环找到所有匹配条件的
do{
var content = reg.exec(str);//提取字符串
if(content){//判断找到content
console.log(content[0])//content这个数组的第一个是要找的
}
}while(content);//不符合条件跳出循环
match()
var str = '张三:2500,李四:3000,王五:50000'
var reg = /\d+/g;//数字正则表达式
//提取多个内容
console.log(str.match(reg));//-->[2500 ,3000,50000]
分组提取
var dateStr = '2015-1-5';
var reg = /\d{4}-\d{1,2}-d{1,2}/;
reg.test(dateStr);//将dateStr匹配个reg对象,才能使用分组$
console.log(RegExp.$1);//-->2015
console.log(RegExp.$2);//-->1
console.log(RegExp.$3);//-->5
split()
var dateStr = '2015-1-5';
console.log(dateStr.split('-');//-->["2015","1","5"]
var dateStr = '2015-/-5'; //正则表达式分割
console.log(dateStr.split(/[/-]/);//-->["2015","1","5"]
replace()
var str = " 123 aaa ccc";
//trim() 去除前后空格
console.log(str.trim()) //-->"123 aaa ccc"
console.log(str.repalce(/\s/g,'x')//--> "xx123xxaaaxxccc"
console.log(str.split(" "))//-->[" "," ","123"," "," ","aaa"," "," ","ccc"]
console.log(str.split(' ').join(''));//-->"123aaaccc"
//join把split把空去掉,用空连接数组并转为字符串
贪婪模式和非贪婪模式
- 贪婪模式
匹配标签:<.+>会把标签和标签的内容匹配到 - 非贪婪模式:<.+?>不包含标签内容
三元运算符
- 表达式 1 ? 表达式2 :表达式3
-
表达式1:布尔类型表达式-->返回布尔值
-
表达式1 成立 返回表达式2的值
-
表达式1 不成立 返回表达式3的值
//取最大值
var num1 = 3;
var num2 = 6;
console.log(num1>num2 ? num1 : num2)
//如果 num1>num2 返回num1 否则 返回num2
-
隐式类型转换
- false: 0 '' NaN null undefined 其他都为 true
- num=0 --->false
- !true=false
while循环、do...while
while(循环条件){//循环条件为true执行循环体
//循环体
}
//do...while不管条件成立不都会执行一次
do{
//循环体
}while(循环条件)
分隔符
将数组用| 或其他分隔符分割
var arr = ['1','3','5','7']
//方法一:元素后面加分隔符
var seperator = '|'
var str="";//先定义一个空字符串,在拿到每一项拼接到这个字符串中
for(var i=0; i<arr.length; i++){
str=srt+arr[i]+seperator
}
console.log(srt);//--> 1|3|5|7|
//方法二:往第二个元素之前加分隔符
var seperator = '|'
var str = arr[0];//先把第一项存起来,不参与循环
for(var i=1; i<arr.length ;i++){
str += seperator + arr[i]
}
console.log(srt);//--> 1|3|5|7
数组案例
将数组中的0项去掉,并将不为0的存入新数组
var num=[2,7,9,0,1,0,5,0]
var newArray = [];
for(var i=0; i<num.length;i++){
if(num[i] !== 0){
newArray[newArray.length] = numbers[i];
//newArray.length相当于新数组的索引i
}
}
console.log(newArray);//-->[2,7,9,1,5]









网友评论