day1
1.数据类型转换:
1.转字符串:
1.xx.toString();
2.string(xx);
原因:1.从页面获取的都是字符串
2.String();完全相当于隐式转换,还不如+“”;
2.转数字:
1.parseInt/Float(str);
原理:从左向右一次读取每个字符,碰到第一个不是数字的字符就停止,开始就遇到不认识的字符则为NaN
int 不认识小数点,float认识第一个小数点
2.Number:万能的,但是没什么用,完全相当于隐式转换 - 还不如-0 *1 /1
3.转布尔:
Boolean(x);
***只有6个会为false:0,"",undefined,null,NaN,false,其余都为true
在分支、循环的条件之中,以后不管代老师写的是什么,他都会悄悄的隐式转换为布尔值,你只需要考虑为true还是为false
2.运算符和表达式:
1. *算术运算符:+ - * / %
特殊:1、%:取余,判断奇偶性
2、隐式转换:默认转为数字,在运算
true->1
false->0
undefined->NaN
null->0
特殊:1、+运算,碰到字符串,拼接
2、-*/%:字符串可以转为数字,但是纯数字组成才行,但凡包含一个非数字字符,则为NaN
2. *比较运算符:> < >= <= == != === !==
结果:布尔值
隐式转换:默认,转为数字,再比较大小
特殊:1.如果参与比较的两边都是字符串,则按位PK每一位的Unicode号
0-9<A-Z<a-z<汉字:第一个汉字:一:Unicode:4E00 - ascii:19968
最后一个汉字:龥:Unicode:9FA5 - ASCII:40869
3.undefined==null;
区分:undefined===null;
=== !==:不带隐式转换的等值比较和不等比较,要求数值相同,并且数据类型也要相同
function String(x){
if(x===undefined){
return "undefined";
}else if(x===null){
return "null";
}else{
return x.toString();
}
}
3.逻辑运算
&&:全部满足,才true
一个不满足,则false
||:全部不满足,才false
一个不满足,则true
!:颠倒布尔值
特殊:短路逻辑:如果前一个条件,已经能够得出最后结论了,则不看后续
&&短路:如果前一个条件满足,才执行后续操作,如果前一个条件不满足,则不管后续操作
目的:简化【简单的】分支:1、一个条件一件事满足就做,不满足就不做 if(){} 2、操作只能有一句话
条件&&(操作);
举例:原来:if(money>=500){money*=0.8};
现在:money>=500&&(money*=0.8);
day2
1.自定义function:
什么是函数:需要先定义好,可以反复使用的代码段
何时使用:1.不希望一打开页面立刻就执行,2.以后可以反复使用,3.希望可以绑定在页面元素上
如何使用:
1.创建并调用:
1.创建:
1.【声明方式】创建函数
function xx(){
函数体;
return ;
}
2.【直接量方式】创建函数
var xx=function(){
函数体;
return ;
}
2.调用:
var 接住返回的结果= 函数名(实参)
2.作用域:
1、全局作用域:全局变量 和 全局函数,在页面的任何一个位置都可以使用
2、函数/局部作用域:局部变量 和 局部函数,在【当前函数调用时内部可用】
*变量的使用规则:优先使用自己的,自己没有找全局,全局没有报错
特殊:缺点:1、千万不要再函数中对着未声明的变量直接赋值 - 全局污染
2、局部可以用全局的,但是全局不能用局部的 - 解决:看上面return
3.声明提前:
在程序正式执行之前:
将var声明的变量(轻)和function声明的函数(重)
都会悄悄集中定义在当前作用域顶部
但是赋值留在原地
声明方式创建的函数会整个提前(第一种创建方式)
直接量方式创建的函数不会整个提前,只会将变量部分提前
何时使用:永远不会主动使用,干扰我们判断! - 只会在笔试中遇到,为什么平时开发中跟本遇不到?
原因:只要你遵守以下规则:
1.变量名和函数名尽量不要重复
2.先创建后使用
3.如果笔试中,先使用后声明多半是考变量提前
4.按值传递:两个变量之间赋值,分两种情况
1.如果传递的两个是原始类型的值:
修改一个变量的值,另一个变量不会受到影响,其实是复制了一个副本给对方
2.如果传递的是引用类型的值:
修改一个变量的值,另一个也会受到影响,引用类型其实根本没有保存到变量中,仅仅是保存了一个变量值,
两者使用的是同一个地址值,所以会相互影响
2.预定义全局函数:前辈们定义好的,我们只负责学习如何使用
*parseInt/Float/isNaN等等都是预定义全局函数
1、编码和解码
问题:url中不允许出现多字节字符(汉字,utf-8编码格式下,一个汉字占3字节),如果出现会乱码
解决:发送前,前端将多字节字符编码为单字节字符(数字、字母、符号)
发送后,后端将单字节字符在解码为多字节原文
如何:
编码:var 不认识=encodeURIComponent("大梵");
解码:var 原文=decodeURIComponent(不认识);
这个东西没有用,在某一次浏览器更新后,当前就被淘汰了,浏览器自带此功能 - 唯一的用处,现在就是玩了:悄悄话
2.2、isFinite(num):判断num是不是有效范围 - 垃圾并不能用于判断是不是NaN,因为有三个人会是false
哪些会为false:NaN,Infinity,分母为0
3、分支结构:根据条件的不同,选择部分代码执行
1、if分支
2、三目&短路
3、switch...case...语法
switch(变量/表达式){
case 值1:
操作1;
case 值2:
操作2;
case 值3:
操作3;
default:
默认操作;
}
特殊:1、不具备隐式转换
2、问题:默认只要一个case满足后,就会将后面所有操作全部做一次
解决:break;
建议:每一个case的操作后都要跟上一个break
有的地方可以不加break:
1、最后一个操作default可以省略break
2、如果中间连续的多个操作,是相同的,也可以省略掉中间部分
***面试题:if vs switch
1.switch:缺点:必须要直到最后结果才使用,不能做范围判断
优点:执行效率相对较高
2.if:优点:可以做范围运算
缺点:执行效率相对较低
建议:代码优化:尽量将if 替换为switch,三目或者短路
day3
1.循环结构
1.var 循环变量=几;
while(循环条件){
操作;
变量变化;
}
2.do{
操作;
变量条件;
}while(循环条件)
面试题:while和do..while 的区别
while是先判断再执行
do ...while 是先执行再判断
3.for(var 循环变量;循环条件;变量变化){
}
4.退出循环语句:break;
5.死循环:while(true) for(;;)
建议:死循环用while 知道循环次数用for循环
6.for each 和for in 和 for of - 专门为数组遍历准备
2.数组
1.什么是数组:一个集合可以保存多个数据
何时使用:多个相关数据,都要集中都要集中定义在一个集合中
为什么:因为一个好的数据结构,能够极大地提高程序员的开发效率
2.创建:
1.直接量方式:var arr=[值1..,值2...]
2.构造数组方式:var arr=new Array(值1,,值2,...);
坑:new array(num); - 它懂不起,会以为是创建了一个长度为num的数组
3.访问:数组名[下标]
添加/修改:数组名[下标]=新值;
特殊:访问时,下标越界 - 返回undefined
添加时,下标越界 - 变为稀疏数组,导致下标不连续,导致以后遍历一定会得到undefined
4.数组的三大不限制:
1.不限制类型
2.不限制长度
3.不限制下标越界 - 不推荐
5.数组唯一的一个属性:数组名.length - 获取数组的长度
三个固定套路:
1.末尾添加:arr[arr.length]=新值;
2.获取倒数第n个:arr[arr.length-n]
3.缩容:arr.length-=n
6.遍历数组:对数组中每个元素执行相同或相似的操作
for(i=0
arr[i]
}
7.如何释放一个引用类型:看清楚此引用类型有几个变量关联着每个变量释放后才能释放干净
建议:我们代码尽量封装在函数中,函数中的所有变量会自动释放
索引数组:下标都是由数字组成的数组
8.关联数组(hash数组):下标可以自定义的数组
为什么:索引数组的下标无具体意义,不方便查找
如何使用:
1.创建:1.创建一个空数组:var arr=[]
2.为空数组添加自定义下标并且赋值:arr[自定义下标]=新值
2.访问:arr["自定义下标"]
3.强调:hash数组
问题:hash数组不能使用for遍历,只能使用for in 遍历 语法:
for(var i in 数组名){
console.log(i)//自动获得当前数组的下标,不需要我们设置从哪儿开始,从哪儿结束
console.log(arr[i]
}
牛逼处:不仅可以遍历hash数组,也可以遍历索引数组
建议:hash用for in 索引用for
4.js中所有东西都是对象,万物皆对象,除了undefined和null
3.数组中的API:数组中的函数,前辈们定义好的,只有*数组可以使用*
1.arr转为 str
1.语法:var str=arr.join(“自定义连接符”)
作用:1.笔试时,给你一个给你一个数组,将他无缝拼接在一起
var arr=["h","e","e"]
var str=arr.join("")
2.拼接为页面元素:
//以后从数据获取元素
var cities=["-请选择-","北京","南京","西京","东京","重庆"]
//拼接为页面元素后,innerHTML是识别标签的
sel.innerHTML="<option>"+cities.join("</option><option>")+"</option>"
2.拼接数组:添加元素的新方式:
语法:var newArr=arr.concat(值1,...)
特殊:1.此方法不会改变原数组,只会返回一个新数组
2.支持传入数组参数,悄悄将我们的数组打散,不会变为二维数组。
3.截取子数组:取出数组中想要的部分组成一个新数组
语法:var subArr=arr.slice(starti,endi)
t特殊:1.此方法不修改原数组,只会返回一个新数组
2.含头不含尾
3.第二参数也可以不写,截取到末尾
4.第一个参数也可以不写,两个参数都没写,从头截到尾 - 深拷贝(副本)
5.支持负数参数 - -1代表倒数第一个
4.删除,插入,替换
删除:var dels=arr.splice(starti,n)
特殊:此方法也有返回值,返回的就是你删除的组成新的数组
插入:arr.splice(starti,0,新值1,...)
特殊:1.没有删除,也有返回值,返回的是一个空数组
2.原starti以及后续元素会向后移
3.不建议插入,数组会变得不伦不类
替换:var dels=arr.splice(start,n,新值1,...)
特殊:删除的个数和插入的个数不必相同
5.反转数组:
arr.reverse()//没什么大用
day4
Array API:
1.排序:
1.笔试时,不使用数组API将数组进行升降排序 - 冒泡排序 -> 拿着数组中前一个和后一个作比较,前一个大于后一个则二者交换位置
var arr=[32,14,43,453,6,58,56,531,5,57]
for(i=0
for(j=0
var m
if(arr[j]>arr[j+1]){
m=arr[j]
arr[j]=arr[j+1]
arr[j+1]=m
}
}
2.数组API:arr.sort()
默认:悄悄转为字符串,按位PK每个字符的unicode号,默认是按照字符串排序
问题1:希望按照数组升序排列
解决:arr.sort(function(a,b){
a-b
})
原理:1.匿名函数回调,一般是前辈们规定好的,我们只学习怎么使用,一般是自动调用,而且有多少对儿就调用几次
2.a:后一个数字,b:前一个数字
3.返回结果:如果是正数,说明a大
如果是负数,说明b大
如果是0,说明一样大
4.而我们的sort会根据你返回的值得正负来判断是否交换位置
问题2:希望按照降序排列:
解决:arr.sort(function(a,b){
b-a
})
建议:开发中使用API排序,鄙视中可能会遇到冒泡排序
强调:切记前端中所有技术中:只有数组可以排序,如果遇到页面中需要排序,name他的底层一定是数组
2.栈和队列:
栈:其实就是一个数组,只不过只能要求从一端进出,另一端是封闭的
何时:始终希望使用最新的数据时,现实中很少,代码中也很少
如何:
前进:arr.unshift(新元素) - 添加元素的新方式,建议不要添加数组
前出:var first=arr.shift()
后进:arr.push(新元素); - 添加元素的新方式,只能向数组末尾添加一个
后出:var last=arr.pop(); - 删除元素的新方式,只能删除数组最后一个元素
队列:其实就是一个数组,要求一端进,另一端出
何时:按照先来后到的顺序
如何:
前进:arr.unshift(新元素) - 添加元素的新方式,只能向首位添加,建议不要添加数组
后出:var last=arr.pop()
后进:arr.push(新元素)
前出:var first=arr.shift()
二维数组:数组的新元素,又引用着另一个数组
何时使用:在数组中,希望再次细分每个分类
如何使用:创建:
var arr=[
[]
[]
[]
]
访问:arr[行下标][列下标]
特殊:列下标越界:返回undefined
行下标越界:报错 虽然行下标越界确实会得到一个undefined,但是undefined没资格再加[]
遍历二维数组:必然使用两层循环,第一个控制行,第二个控制列
for(var r=0
for(var c=0
console.log(arr[r][c])
}
}
总结:ES3的数组学习完毕
2.数组API:10个(concat,join,slice,splice(删,替换,插入),sort,shift,unshift,push,pop)
3.二维数组
字符串
1.什么是字符串:多个字符组成的【只读】字符【数组】
1.只读:所有字符串的API都不会改变原数组,只会返回一个新数组
2.数组:和数组有相同点:
1.可以遍历
2.可以使用length
3.可以使用下标获取字符
4.数组不修改原数组的API,字符串也可以使用(concat:还不如用+拼接,slice);
当然,数组中修改原数组的API,字符串不能使用
引用/对象类型:11个:
*String,Number,Boolean - >具有包装类型
Array,function,Math,Date,*RegExp(z正则表达,验证用的)
Error:错误
Object:对象
Global:全局对象 - 在前端/客户端/浏览器端 js被window代替了:功能:保存了全局变量和全局函数,只有window可以省略
3.包装类型:专门用于将一个原始类型封装为引用类型的对象(带了属性和方法)
为什么:原始类型原本是不具备属性和方法的,但是前辈们发现我们常操作字符串,因此为三个原始类型提供了包装类型
何时使用:只要试图用原始类型的变量去用.调用方法和属性时,就会悄悄地转为引用类型
何时释放:方法调用完毕,自动释放包装类型,并且返回数据(又会变为原始类型)
为什么undefined和null,没有提供包装类型
day5
1.正则表达式
什么是:定义字符串中【字符出现规则】的一个表达式
何时使用:切割,替换,【验证】
如何使用:语法:/正则表达式/
1.最简单正则:关键字原文 “” -> /no/gi 只要用上正则就可以加上后缀
g:全部 i:忽略大小写
2.备选字符集:/[备选字符集]/
强调:1.一个中括号,只管一个字符
2.正则表达式【默认只要满足条件,不管其他的了】,解决:前加^后加$:/^[]$/
代表要求:用户从头到尾必须完整匹配我们的要求 - 只要是做验证就必须前加^后加$
特殊:如果备选的ASCII码是连续的,中间部分可以用-代替
一位数字:[0-9]
一位字母:[a-z],[A-Z]
一位汉字:[\u4e00-\9fa5]
3.预定字符集:前辈们定义好的,我们直接使用的
目的:简化备选字符集
一位数字:\d
一位数字,字母,下划线 :\w
一位空白字符:\s
建议:优先使用备选字符集,备选字符集满足不了再用自定义字符集
问题:不管备选字符集还是自定义字符集,都只管一位
4.量词:规定一个字符集出现的次数
有明确数量:
{m,n}前边相邻字符集,最少出现m次,最多出现n次
{m,}前边相邻字符集,最少出现m次,最多不限
{n}前边相邻字符集,必须出现n次
无明确数量:
?:前边相邻字符集,可有可无,做多出现一次
*:前边相邻字符集,可有可无,多了不限
+:前边相邻字符集,至少出现一次,多了不限
5.选择和分组:
选择:多个规则中选择一个
规则1|规则2
分组:将多个字符集临时组成一组自规则
(规则1|规则2)
6.指定匹配位置:
^:开头
$:结尾
特殊:如果两者同时出现,表示要从头到尾完全匹配 - 验证时必须加上
7.密码验证: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}$/
2.字符串支持正则表达式的API
1.切割:
var arr=str.split("固定切割符"/regexp,"新内容");
2.替换:
1.基础替换法:var arr=str.splace("固定关键字"/regxp,“新内容”);
2.高级替换法:
var arr=str.splace("固定关键字"/regxp,function(a,b,c){
console.log(a);
console.log(b)
console.log(c);
return a==arr.length?"**":"***";
})
3.格式化:
在使用replace替换时,如果搭配上了正则,并且正则中加入分组,name我们的高级替换法就会多很多形参,有几个分组就会多几个形参
var newStr=id.replace(reg,function(a,b,c,d,e,f,g,h){
3.正则表达API:
1、创建正则对象:
*直接量方式:var reg=/正则表达式/后缀
构造函数方式:var reg=new RegExp("正则表达式","后缀")
为什么有时候要加 前加^后加$,为什么有时候又要加后缀g
1、验证:前加^后加$ - 用户要和我们的规则完全匹配
2、替换:加后缀g
2、API:var bool=reg.test(用户输入的东西)
返回true,说明用户验证成功,否则验证失败
day6
1.Error:错误
1、***浏览器自带四种错误类型:可以快速找到自己的错误
语法错误:SyntaxError - 符号写错了
引用错误:ReferenceError - 没有创建就去使用了
类型错误:TypeError - 不是自己的方法,你却去使用了,最典型的,就是你们经常会undefined.xxx或null.xxx
范围错误:RangeError - 只有一个API会碰到:num.toFixed(d);
2、只要发生错误,就会报错,会导致后续代码不执行(如果APP报错,那会直接闪退),我们程序不希望报错
错误处理:就算发生错误,也不会报错,不希望抛出错误,而是希望给一个错误提示即可,后续代码依然可以继续允许
语法:
try{
只放入你可能出错的代码
}catch(err){
发生错误的时候才会执行
console.log(err);
}
try...catch...的性能非常差,几乎里面的代码效率会被降到最低,所以不推荐使用
*可以用一个技术代替:if...else... 提前预判
*开发经验:一切的用户都是坏人,都要防一手(!isNaN(x)、正则:把用户控死)
3、抛出自定义错误:
throw new Error("自定义提示");
function:函数对象:提前创建好的,以后可以反复使用的代码段
1.创建:3种
声明方式:function xx(){} - 完整提前
直接量方式:var xx=function(){}
构造函数方式:var 函数名 =new function(“形参,...”,函数体;return 返回值);
2.调用:如果有return 记得接住返回值
var 结果=函数名(实参)
3.考点:
1.创建函数的三种方式
2.作用域:变量的使用规则:优先使用自己的,自己的找不到找全局
3.声明提前:变量和声明的函数会提前到当前作用域的顶部,赋值留在原地
4.按值传递
5.重载 overlord:相同的函数名,根据传入的形参不同自动选择不同函数执行
为什么:减轻程序员负担
问题:JS不支持重载
JS不允许多个同名函数同时存在,如果存在会覆盖之前的函数
解决:在【函数中】有一个arguments对象,不需要我们创建,自带
什么是arguments:是一个类数组对象,但是和数组有三个相同点
1.都可以使用下标
2.都可以使用length
3.都可以遍历
作用:可以接住传入函数的实参,哪怕不写形参也行
可以做的事:
1.实现重载:可以通过在函数内部判断arguments的不同,执行不同操作
2.可以不写形参
3.正式开发中,可能会将多个函数整合为一个函数 - 代码优化
6.匿名函数:没有名字的函数
1.匿名函数的字调:此函数只会执行一次,执行完毕会自动释放优点:自动释放 - 代替全局写法,提升网站性能
(function(){
var a=2;
console.log(a);
btn.onclick=function(){
console.log("释放了码");
}
})();
2.匿名函数的回调:将函数作为实参,传递给其它函数使用 - 没有名字的函数就是匿名函数,匿名函数只有自调和回调
1.学习回调函数的目的:知道哪些是回调函数
arr.sort(function(a,b){return a-b;})
str.replace(reg,function(){})
btn.onclick=function(){}
.
.
.
这些东西都是规定好的,只学习如何使用
2.ES6 - 一切的回调函数都可以简化为箭头函数
了解回调函数的原理
7.*****闭包
1.function
作用域:
1.全局:成员,随处可以使用,缺点:容易被污染
2.局部:成员,只能在函数内部使用,不会被污染 缺点:一次性的,用完会被释放
函数的执行原理:
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,AO会自动释放,所以局部变量也就自动释放了
两链一包
作用域链:以函数的EC中的scope chain属性为起点,经过AO,逐级引用,形成的一条链式结构,就称之为作用域链
变量的使用规则,查找变量
闭包:希望保护一个【可以反复使用的局部变量】的一种词法结构,其实是一个函数,只是写法和以前有点区别
何时使用:希望可以保护【可以反复使用的局部变量】
如何使用:4步
1.两个函数相互嵌套
2.外层函数创建出受保护的变量
3.外层函数要return返回内层函数
4.内层函数要操作受保护的变量
强调:
1.判断是不是闭包:有没有两个函数嵌套,外层创建受保护的变量,返回内层,内层操作受保护的变量
2.外层函数调用了几次,就创建了几个闭包,受保护的变量就多了几个副本
3.同一次外层函数的调用,返回的内层函数,都是在操作同一个受保护的变量
缺点:受保护的变量,永远不会被释放,食用过多,会造成内存泄漏
使用场景:防抖节流 - 有三个事件需要做防抖节流:执行速度非常快,减少DOM树的渲染
1.elem.onmousemove - 鼠标移动事件
2.input.oninput - 输入框内容有变化就会触发
3.window.onresize - 当前窗口尺寸发生变化就会触发 - JS的媒体查询
公式:
elem.on事件名=function(){
inner;
}
function fdjl(){
var timer=null;
return function(){
if(timer){clearTimeout(timer);timer=null;}
timer=setTimeout(function(){
},1000)
}
}
var inner=fdjl();