正则表达式
什么是:定义字符串中字符出现规则的表达式
何时:切割 替换 验证
最简单的正则
关键字原文"xx"->/xx/后缀
后缀:g:global找全部
i:忽略大小写
备选字符集
/^[备选字符集]$/;
强调:
1、一个中括号,只管一个字符
2、正则表达式默认只要满足就不管后续,我们希望从头到尾完全匹配,解决:前加^后加$:/^[备选字符集]$/;
特殊:如果备选字符集中的ascii码是连续的,那么我们可以用-省略中间的部分
比如:一位数字:[0-9];
一位字母:[A-Za-z];
一位字母,数字,下划线[0-9A-Za-z_];
一位汉字:[\u4e00-\u9fa5];
预定义字符集
一位数字:\d
一位字母,数字,下划线:\w
一位空白字符:\s
量词
作用:规定一个字符集出现的次数
1、有明确数量:
字符集{n,m}:前边相邻的字符集,至少n个,最多m个
字符集{n,}:前边相邻的字符集,至少n个,多了不限
字符集{n}:前边相邻的字符集,必须n个
2、没有明确数量
?:前边相邻的字符集,可有可无,最多1个
*:前边相邻的字符集,可有可无,多了不限
+:前边相邻的字符集,至少一个,多了不限
选择和分组
选择:在两个规则中选一个
规则1|规则2
分组:将多个字符集临时组成一组子规则
(规则1|规则2)
指定匹配位置
^:开头
$:结尾
特殊:两者同时使用:前加^后加$:表示从头到尾完全匹配
reg.test(user)//验证ture或false
密码强度
4位密码,数字和字母的组合,至少出现一位数字和一位大写字母 /^[0-9A-Za-z]{4}$/
预判公式:
(?![0-9]+$) -> 不能全由数字组成
(?![a-z]+$) -> 不能全由小写字母组成
(?![0-9a-z]+$) -> 不能全由数字、不能全由小写字母、不能只有他俩的组合组成
/(?![0-9a-z]+$)(?![A-Za-z]+$)[0-9A-Za-z]{4}/;//4位密码,数字和字母的组合,至少出现一位数字和一位大写字母
/(?![0-9a-z]+$)(?![A-Za-z]+$)(?![A-Z0-9]+$)[0-9A-Za-z]{4}/;//4位密码,数字和字母的组合,三者必须都有
支持正则表达式字符串的API
切割
var arr = str.split(reg);
替换
基本替换法:缺陷:替换的东西都是固定的
var Newstr = str.replace(/正则表达式/后缀,"新内容");
//replace支持正则,并且搭配上后缀就可以找到全部
高级替换法:
var newStr=str.replace(/正则表达式/后缀,function(a){
//a代表正则匹配到的当前的关键字
return a.length==2?"**":"***";
});
格式化
var id="5001031xxx022xxx33";
var reg=/\d{6}(\d{4})(\d{2})(\d{2})\d{4}/;
id=id.replace(reg,function(a,b,c,d){
//在replace的时候,正则出现了分组:我们会得到更多的形参
//在形参a的后面就会出现n个形参,就看你有多少个分组
//第一个分组获得的内容会保存在第二个形参中
//第二个分组获得的内容会保存在第三个形参中
//...
return b+"年"+c+"月"+d+"日";
})
console.log(id);
正则对象
创建
直接量方式:var reg=/正则表达式/后缀;
构造函数方式:var reg=new RegExp("正则表达式","后缀");
API
var bool=reg.test(用户输入的内容);
true->验证成功 false->验证失败
Math对象
强调:不需要创建,直接使用
属性:Math.pi===3.1415926
API
上取整
var num = Math.ceil(num);//小数位数不能超过15位
下取整
var num = Math.floor(num);//无论超过多少都会省略小数部分
四舍五入取整
var num = Math.round(num);
以上三个都是垃圾,取整推荐:num.toFixed(d)
笔试题
不允许使用toFixed的情况下,我们自己封装一个函数,实现toFixed的功能,并且最后返回的是一个数字:
思路:看用户想保留的是几位小数,我们就拿着数字*10的几次方,使用Math.round四舍五入取整,最后/10的几次方
function sswr(num,b){
num*=Math.pow(10,d);
num=Math.round(num);
num/=Math.pow(10.d);
return nm.toString();
}
乘方
Math.pow(底数,幂);
开方
Math.sqrt(num);//只能开平方
最大值和最小值
var 最大/最小的=Math.max/min(a,b,c,d);
问题:本身不支持数组参数
解决:固定用法:
var 最大/最小的 = Math.max/min.apply(Math,arr);
apply其中的一个作用是可以将数组打散为单个元素
绝对值
将负数转为正数
Math.abs(-1);//1
随机数
Math.random();在0-1之间取出一个随机小数,可能去到0,但是不可能去到1,意味着取不到最大值
公式:praseInt(Math.random()*(max-min+1)+min);
Date日期对象
创建
创建当前日期时间
var now = new Date();
创建一个自定义时间
var birth = new Date("yyyy/MM/dd hh:mm:ss")
创建一个自定义时间
var birth = new Date(yyyy,MM-1,dd,hh,mm,ss)//修改月份,从0开始的
复制一个日期
为什么:日期的所有的API都是直接修改原日期的,无法获得修改之前的日期,所以,在执行API之前进行赋值,然后再操作复制后的日期。
var end = new Date(start);
操作
两个日期对象之间可以相减,得到一个毫秒差,换算出自己想要的某一部分
创建的最后一个方式: var date = new Date(毫秒数);
API
分量:时间的单位
年月日星期:FullYeat Month Date Day
时分秒毫秒:Hours Minutes Seconds Milliseconds
每一个分量都有一堆getxxx/setxxx
其中getxxx负责获取某一个分量的值
其中setxxx负责设置某一个分量的值
特殊:
1、取值范围:
FullYear:当前年份的数字
Month:0-11
Day:0-6
Hours:0-23
Minutes,Seconds:0-59
2、Day 没有set方法
如果希望对某个分量进行加减计算
date.setxxx(date.getxxx()+/-n)
格式化为字符串
date.toLocaleString();//本地日期格式,有兼容问题,解决:自定义format方法
Error对象
1、语法错误:SyntaxError -多半时你的语法符号写错了
2、引用错误:ReferenceError -没有创建就直接使用了
3、类型错误:TypeError -不是你的方法,你却使用了
4、范围错误:RangeError -只有一个API会碰到:num.toFixed(d)//d的取值范围:0-100之间
只要发生错误就会报错,会导致后续代码终止。
错误处理
就算报错,我们也不希望后续代码终止,而是给一个错误提示,后续代码可以继续执行
语法:
try{
放入你可能出错的代码
}catch(err){
发生错误后才执行
congsole.log(err);//err就是我们的错误提示,英文
console.log("中文错误提示");
}
try...catch...的性能非常差,几乎里面的代码效率都会降到最低
可以用一个技术代替:if...else
抛出自定义错误
throw new Error("自定义错误信息")-只要是报错都会卡住后续代码
Function对象
创建
1、声明方式: function 函数名(形参,...){函数体;return 返回值;}
2、直接量方式:var 函数名 = function(形参,...){函数体;return 返回值;}
3、构造函数: var 函数名 = new Function("形参1","形参2",...,"函数体;return 返回值";)
何时:如果你的函数体不是固定的而是动态拼接的字符串
比如:以下案例,我们让用户来参与到底是顺序还是降序排列
var arr = [321,5,43,65,8];
var user = prompt("排序数组,如果您输入a-b则为升序排列,如果您输入b-a则为降序排列")
var compare = new Function("a","b","return"+user);
arr.sort(compare);
console.log(arr);
调用时,如果有return,记得接住
var result = 函数名(实参,...)
重载
相同的函数名,传入不同的实参,可以自动选择对应的函数执行操作
问题:JS的语法不支持重载
JS不允许有多个同名函数同时存在,如果同时存在,最后的会覆盖之前的所有
解决:在函数中有一个对象 - arguments对象
什么是arguments对象:只能在函数中使用,自动创建,是一个类数组对象
作用:可以接收所有传入的参数
arguments对象是一个类数组对象:长的像一个数组,但是,不是一个数组
只有三点和数组相同:1、使用下标 2、使用length 3、遍历
arguments可以做的事:
1、实现重载:通过函数内部判断arguments,执行不同的操作
2、以后有没有形参都无所谓
3、正式开发中,有可能会将多个函数整合为一个函数
匿名函数
没有名字的函数
1、匿名函数自调:
为什么:节约内存,因为匿名函数没有变量引用着,用完就会立刻释放变量
语法:(function(){
//以后可以代替全局代码写法,尽量不要在外部书写JS
})();
2、匿名函数回调:将函数作为实参,传递给其他函数调用
1、学习回调的目的:只要不是自调,就是回调
arr.sort(function(){})
str.replace(reg,function(){})
btn.onclick = function(){}
函数的执行原理
1、程序加载时
创建执行环境栈(ECS):保存函数调用顺序的数组
首先压入全局执行环境(全局EC)
全局EC引用着全局对象window
window中保存着全局变量
2、定义函数时
创建函数对象:封装代码段
在函数对象中有一个scope(作用域)属性:记录着函数来自的作用域是哪里
全局函数的scope都是window
3、调用前
在执行环境栈(ECS)压入新的EC(函数的EC)
创建活动对象(AO):保存着本次函数调用时用到的局部变量
在函数的EC中有一个scope chain(作用域链)属性引用AO
AO有一个parent属性是函数的scope引用着的对象
4、调用时:正是因为前面三步,我们才有了变量的使用规则:优先使用自己的,自己没有找全局,全局没有就报错
5、调用完:函数的EC会出栈,AO自动释放,局部变量也就自动释放了
***两链一包:
作用域链:以函数的EC的scope chain属性为起点,经过AO,逐级引用,形成的一个链式结构
作用:查找变量,带来变量的使用规则
闭包
希望保护一个可以反复使用的局部变量的一种词法结构
何时使用:希望保护一个可以反复使用的局部变量的时候
如何使用:
1、两个函数进行嵌套
2、外层函数创建出受保护的变量
3、外层函数return出内层函数
4、内层函数要去操作受保护的量
强调:
1、判断是不是闭包,有没有两个函数嵌套,返回内层函数,内层函数在操作受保护的变量
2、外层函数调用了几次,就创建了几个闭包,受保护的变量就有了几个副本
3、同一次外层函数调用,返回的内层函数,都是在操作同一个受保护的变量
缺点:受保护的变量,永远都不会被释放,使用过多,内存泄漏
问题:应该在哪里用?
1、三个事件需要防抖节流
1、elem.onmousemove - 鼠标移入事件
2、input.oninput - 每次输入/改变就会触发
3、window.onresize - 每次窗口的大下发生变化就会触发
防抖节流公式:
elem.on需要防抖节流的事件 = function(){
fdjl();//内层函数只要一旦移动就触发
}
function f1(){
var timer = null;//3
return function(){
if(timer){clearTimeout(timer);timer=null;}
timer = setTimeout(function(){
操作;
},1000)
}
}
var fdjl = f1();
小案例
滚动轮播
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
* {
margin: 0;
padding: 0;
list-style: none;
}
img {
width: 100%;
vertical-align: top;
}
.carousel {
position: relative;
overflow: hidden;
}
.carousel_img{
width: 300%;
overflow: hidden;
position: absolute;
left: 0;
top: 0;
transition: 1s;
}
.carousel_img>img{
width: 33.33%;
float:left;
}
.carousel>button {
width: 50px;
height: 50px;
border-radius: 50%;
border: 1px solid #666;
background: rgba(0, 0, 0, .5);
color: #fff;
font-size: 35px;
cursor: pointer;
position: absolute;
top: 50%;
margin-top: -25px;
}
.carousel>button:nth-of-type(1) {
left: 50px;
}
.carousel>button:nth-of-type(2) {
right: 50px;
}
.carousel>button:hover {
background: rgba(0, 0, 0, .6);
}
.carousel>button:active {
background: rgba(0, 0, 0, 1);
}
.carousel ul {
width: 100px;
text-align: center;
position: absolute;
left: 50%;
margin-left: -50px;
bottom: 50px;
}
.carousel li {
width: 10px;
height: 10px;
border-radius: 50%;
background: #fff;
cursor: pointer;
display: inline-block;
}
li.active {
background: red;
}
</style>
</head>
<body>
<div id="swiper" class="carousel">
<div class="carousel_img">
<img class="active" src="img/1.jpg" />
<img src="img/2.jpg" />
<img src="img/3.jpg" />
</div>
<img src="img/3.jpg" />
<button><</button>
<button>></button>
<ul>
<li dy="0" class="active"></li>
<li dy="1"></li>
<li dy="2"></li>
</ul>
var btns=document.getElementsByTagName("button"),
car_img=document.getElementsByClassName("carousel_img")[0],
lis=document.getElementsByTagName("li"),
j=0;//计数
for(var i in btns){
btns[i].onclick=function(){
if(this.innerText==">"){
animate(1);
}else{
animate(-1);
}
}
}
for(var i in lis){
lis[i].onclick=function(){
animate(0,this);
}
}
timer=setInterval(function(){
animate(1);
},3000)
swiper.onmouseenter=function(){
clearInterval(timer);
}
swiper.onmouseleave=function(){
timer=setInterval(function(){
animate(1);
},3000)
}
function animate(){
if(arguments[0]){
j+=arguments[0];
if(j==lis.length){j=0}else if(j==-1){j=lis.length-1}
}else{
j=parseInt(arguments[1].getAttribute("dy"));
}
for(var i=0;i<lis.length;i++){
lis[i].className="";
}
car_img.style.left=j*-100+"%";
lis[j].className="active";
}
</script>
防抖节流-定时器
d1.onmousemove=function(){
fdjl();//内层函数只要一旦移动就会触发
}
function f1(){
var timer=null;//
return function(){//
if(timer){clearTimeout(timer);timer=null;}
timer=setTimeout(function(){
d1.innerHTML=parseInt(d1.innerHTML)+1
},1000)
}
}
var fdjl=f1();
防抖节流-input
inp.oninput=function(){
fdjl();//内层函数只要一旦移动就会触发
}
function f1(){
var timer=null;//3
return function(){//
if(timer){clearTimeout(timer);timer=null;}
timer=setTimeout(function(){
console.log(inp.value);
},1000)
}
}
var fdjl=f1();
防抖节流-窗口改变大小
window.onresize=function(){
fdjl();//内层函数只要一旦移动就会触发
}
function f1(){
var timer=null;//3
return function(){//
if(timer){clearTimeout(timer);timer=null;}
timer=setTimeout(function(){
if(innerWidth>=1200){
d1.style.background="pink";
}else{
d1.style.background="purple";
}
},1000)
}
}
var fdjl=f1();
Object对象
面向对象:三大特点:封装、继承、多态
开发方式
面向对象和面向过程?
面向过程:经过-开始-结束
面向对象:对象(属性和方法),JS有一句话,万物皆对象
为什么要使用面向对象:现实中所有的数据都必须包含在一个事物中才有意义
何时使用面向对象:以后做任何操作都要封装在一个对象中
封装
创建自定义对象:3种方法
直接量方式
var obj = {
"属性名":属性值,
....
"方法名":function(){},
....
}
强调:1、其实属性名和方法名的""可以不加
2、访问对象的属性和方法
obj.属性名
obj.方法名()
JS种一切都是对象,一切对象的底层都是hash数组
3、访问到不存在的属性,返回undefined
4、可以随时随地的添加新属性和新方法
5、如果我希望遍历出对象所有的东西,使用for in , obj[i]才能拿到 -不要用,会出问题
6、如果你希望在对象的方法里使用对象自己的属性:写为this.属性名
this的指向
1、单个元素绑定事件:this->单个元素
2、多个元素绑定事件:this->当前触发的元素
3、函数中使用this:this->谁在调用此方法,this指的就是谁
4、定时器中this->window
预定义构造函数方式
var obj = new Object();//空对象,需要自己后续慢慢追加属性和方法
obj.属性名 = 属性值
obj.方法名 = function(){}
以上方法都有一个缺陷:一次只能创建一个对象,适合创建单个对象的时候使用
自定义构造函数方式
创建自定义构造函数
function 类名(name,age,salary){
this.name=name;
this.age = age;
this.salary = salary;
}
//千万不要在里面创建方法,每个对象都会创建一个方法,浪费内存
调用构造函数创建出对象
var obj = new 类名(实参1,...)
继承
父对象的成员(属和方法),子对象可以直接使用
为什么:代码重用,节约内存空间,提升网站性能
何时继承:只要多个子对象公用的属性和方法,都要集中定义在父对象中
继承具有非常多的笔试题
1、判断自有还是共有
判断自有:obj.hasOwnPropety("属性名");
如结果为true,说明是自有属性,如果结果为false,有两种可能,共有或者没有
判断共有:
if(obj.hasOwnPropety("属性名")==fasle && "属性名"in obj){// in 会在obj的原型上进行查找
共有
}else{
没有
}
公式:
if(obj.hasOwnPropety("属性名")){
console.log("自有")
}else{
if("属性名"in obj){
console.log("共有")
}else{
console.log("没有")
}
}
2、删除自有和共有
自有:修改:obj.属性名 = 新值;
删除:delete obj.属性名;
共有:修改:obj.共有属性名 = 新值; - 只是在本地添加了一个同名属性
删除:delete obj.属性名; - 无效,本地本来就没有此自有属性
找到原型,修改/删除原型
3、如何为老IE的数组添加indexOf
原理:
if(Array.prototype.indexOf===undefined){//老IE
Array.prototype.indexOf=function(key,starti){
starti==undefined&&(starti=0);
for(var i=starti;i<this.length;i++){
if(this[i]==key){
return i;
}
}
return -1;
}
}
4、如何判断x是不是一个正则:4种方法,千万别用typeof,只能检查原始类型,不能检查引用类型
1、判断x是否继承Array.prototype
Array.prototype.isPrototypeOf(x);//
2、判断x是不是由Array这个构造函数创建
x instanceof Array;
3、Array.isArray(x); - ES5提供的,只是ES5+,老IE不支持,此方法只有数组
4、输出【对象的字符串】形式
在Object的原型上保存着最原始的toString方法
原始的toString输出形式:[object 构造函数名]
多态:子对象觉得父对象的成员不好,在本地定义了同名成员,覆盖了父对象的成员
固定套路:借用:Object.prototype.toString.apply(x);
if(Object.prototype.toString.apply(arr)=="[object Array]"){
console.log("是数组")
}else{
console.log("不是数组")
}
5、实现自定义继承:
1、两个对象之间设置继承:
子对象.__proto__=父对象
2、多个对象之间设置继承:
构造函数名.prototype=父对象
时机:应该在开始创建对象之前设置好继承关系
如何找到父对象(原型对象):保存一类子对象共有属性和共有方法的父对象
1、__proto__;//必须要先有一个对象
2、构造函数名.prototype;//构造函数名,几乎人人都有,除了Math
面试题
两链一包:作用域链、原型链、闭包
每个对象都有一个属性:__proto__,可以一层一层的找到每个人的父亲,形参的一条链式结构,就称之为原型链,可以找到所有父对象的成员(属性和方法),作用:找共有属性和共有方法的
最顶层是Object的原型,上面放着toString,怪不得人人都可以用到toString();
JS万物皆对象
原型对象,设置共有的属性和方法
1、原型对象.属性名 = 属性值;//添加了一个共有属性
2、原型对象.方法名 = function(){};//添加了一个共有方法