JavaScript基础
一、JavaScript的定义和使用方法
**JavaScript是一个运行在浏览器端的解释型弱类型面向对象的脚本语言**
1.浏览器端:环境 自带JavaScript解释器,打开浏览器自动运行
2.编译型:程序执行前先检查语法是否正确,不正确直接不运行
解释型:程序执行前不需要先检查语法是否正确,直接运行,碰到错误停止
3.强类型:变量保存的数据,严格按数据类型决定
弱类型:数据类型由数据决定
1 --> number 数字
"1" --> string 字符串
4.面向对象
5.特点:一切编辑工具都可以编写js代码/完成一切css完成不了的
js的使用方法:
1.在HTML页面上书写一个script标签,再在里面书写type="text/javascript" (不推荐使用)
2.外部引入
二、检查错误的方式 -- 打桩输出/输出的方式
1.在控制台输出日志 console.log();
2.在页面上输出日志 document.write();
3.在弹出框上输出日志 alert();
扩展:用户输入框 var 保存=prompt("提示文字")
例如 var r=prompt("请输入半径");
三、变量和常量
(一)变量***
语法: var 变量名=值;
特殊:
1.不能以数字开头
2.建议使用驼峰命名法和下划线命名法
3.语义化
4.如果变量名是name,数据类型一定是数字
5.变量名不能是关键字
6.变量可以只创建不赋值
7.如果多个变量连续创建,用逗号隔开
(二)常量
创建后不允许修改
语法: const常量名=值;
四、数据类型的分类
(一)原始/基本/值类型***
1.number - 数字 取值无数(颜色蓝色)
2.string - 字符串 取值无数,取值需要加' '或者" "(颜色黑色)
3.boolen - 布尔 取值 true/false
4.null - 空 取值唯一 null
作用:释放变量释放内存,节约内存空间,提升网页性能(颜色灰色)
5.underfined 报错 取值唯一 (颜色灰色)
(二)引用/对象类型
有11个...
(三)运算符
1.算术运算符***
' + - * / %
特殊
(1)" % " 取余,俗称模
作用:
1.判断奇偶数 任意数%2
2.取出某个数字后n位 1234%10 - 4
1234%100 - 34
(2)带有隐式转换,默认:左右两边转为数字后运算
true - 1 flase - 0
underfined - NaN null - 0
"1000" - 1000 "1000px" - NAN
NaN:Not A Number:不是一个有效数字,但是是数字类型
缺点:参与任何算术运算结果都是NaN
参与任何比较运算结果都是flase
(3)特殊的 + 运算
如果碰上一个字符串,左右两边都会悄悄转为字符串+运算,拼接
2.比较/关系运算符
' < > >= <= != == === !==
结果一定是一个布尔值
带有隐式转换,默认两边转为数字后再比较大小
特殊:
(1)如果参与左右为字符串,则按位pk,每个字符的十六进制 unicode号
数字0-9 < 大写A-Z < 小写a-z < 汉字
常识:
汉字第一个字是一,unicode号是4e00,ascii码是19968
汉字最后一个字是龥,unicode号是9fa5,ascii码是40869
3.赋值运算符
' = += -= *= /= %=
(1)赋值:将右边的保存在左边变量名中
(2)运算后变回变量本身 i=i+1 -->i+=1
4.逻辑运算符
' && || !
(1)&& 与 全满足才为true
(2)|| 或 全不满足才为false
(3) ! 非 取反
结果一定是布尔值 true/false;
5.自增自减运算符
自增:每次固定只能+1
前++,返回的是加了以后的新值
后++,返回的是加了之前的旧值
6.位运算
左移:m<<n 读作m左移了n位,翻译:m*2的n次方
右移:m>>n 底数只能为2
五、分支结构
程序的流程控制语句:3种
(一)顺序结构
默认:从上向下一次执行每一句话
(二)分支结构
通过条件判断,选择部分代码执行
1.if..else
语法:
(1)一个条件,一件事,满足就做,不满足就不做
if(条件){
操作;
}
(2)一个条件,两件事,满足就做第一件,不满足就做第二件
if(条件){
操作;
}else{
默认操作;
}
(3)多个条件,多件事,满足谁就做谁
if(条件){
操作1;
}else if(条件2){
操作2;
}else{
默认操作;
}
注意:
1.if...else的数量不定
2.else可以不写但不推荐
3.分支走了一条路就不走其他路
2.switch...case分支
语法:
Switch(变量/表达式){
case 值1;
操作1;
break;
case 值2;
操作2;
break;
default;
默认操作;
}
特殊:
(1)存在的问题:默认只要一个case满足后就会将后续所有操作全部执行
解决: break;
建议每一个case操作后面都跟上一个break
有的地方也可以不加break
比如:最后一个操作default,可以忽略break
如果中间多个条件,做的操作都一样,可以省略中间
(2)case在做比较的时候 是不带隐式转换的
(3)default可以忽略,但是不推荐
3.if和Switch的区别
switch..case:
优点:执行效率高,速度快,比较用做等值比较
缺点:必须先知道结果
if..else..
优点:比较时做范围判断,不用提前知道结果
缺点:执行效率慢,速度慢
建议:代码开发完后,要做代码优化,尽量少用if..else..
4.三目运算:简化分支
语法:
条件?操作1:默认操作;
条件1?操作1:条件2?操作2:默认操作;
注意:
(1)默认操作不能省略,省略会报错
(2)操作只能有一句话,操作多句话还是推荐使用switch或者if
页面上一切数据js获取后都是字符串类型
(三)循环结构
-
通过条件判断,选择要不要重复执行某块代码
-
循环三要素:循环条件/循环体/循环变量
执行原理: 首先创建循环变量,判断循环条件,如果条件满足 则做一次循环体操作,再次判断是否符合条件 满足则做一次循环操作...直到条件不满足,才会退出循环 特殊: 1.有时候会用到死循环;默认永远不会停下来的循环 不确定循环次数时使用 while(true){死循环} 2.死循环的停止 break 退出整个循环 continue 退出本次循环
1.while循环
语法
var 循环变量=几
while(循环条件){
循环体;
循环变量变化;
}
2.for循环
语法
for(var 循环变量=几;循环条件;循环变量变化){
循环体;
}
特殊
死循环:for(;;){}
3.do..while循环(废物)
语法
var 循环变量=几;
do{
循环体;
循环变量的变化
}while(循环条件)
4.while和for的区别
原理上几乎没有区别
不确定循环次数时使用 while 循环
确定循环次数时使用 for 循环
5.while和do..while的区别
区别只有第一次,如果第一次条件都满足,那么两者没有区别
但是如果第一次条件不满足,那么while一次都不会执行
do..while至少执行一次
(四)强制(显示)数据类型转换:
当隐式转换出来的东西我们不想要的时候,需要先强制转换
1.转字符串
(1)var str=x.taString();
x不能underfined和null,会报错,因为她们不是可识别对象
(2)var str=string(x);
- 万能的,任何人都可以转为字符串
- 但不要手动使用,完全等效于隐式转换,还不如 +""
2.转数字***
(1) parseInt(str/num);***
parse解析 Int整型 专门用于将字符串转为整数
执行原理:
从左向右一次读取转换每个字符,碰到非数字字符就停止转换
如果一开始就不认识则为NaN,不认识小数点
(2)parseFloa(str);
parse解析 Float浮点型 专门用于将字符串转为小数点
执行原理:
几乎和parseInt一样,认识第一个小数点
(3)number(x);
- 万能的,不要手动使用,完全等效于隐式转换
- 还不如-0 *1 /1
3.转布尔
boolean(x);
- 万能的,不要手动使用,还不如 !!x
- 只有6个为false:0,"",underfined,null,false,NaN
六、function的基础
(一)概念
function也加函数也叫方法,[先预定义]好
以后可以[反复使用]和[代码段]
(二)如何使用函数
(1)定义/创建/声明:
function 函数名(){
函数体/代码段;
}
(2)调用函数
1.在js内部写:函数名();
程序员写几次就调用几次
2.在HTML上绑定事件:
-公式
<elem onclick="()"> </elem>
鼠标移入* onmouseover
鼠标移出* onmouseout
(三)什么时候使用函数
- 不希望页面打开后立即执行
- 希望用户来触发,提升用户体验感
- 以后每一个独立的功能(作业)都需要封装成一个函数
(四)带有函数形象的函数
(形式参数)形参:一个不需加var,不需要赋值的变量 语法
function 函数名(形参){
函数体/代码段;
}
带有形参的函数时,必须传入实参,顺序和数量必须一一对应
总结:不带参数的函数,用于执行一些固定操作
带参数的函数:可以根据我们传入的实参不同,做得不同
(六)自定义函数:function***
1.创建
(1)[声明方式]创建函数
语法
function 函数名(形参列表){
操作;
return 返回值/结果;
}
(2)[直接量方式]创建函数 - 不推荐
语法
var 函数名=function(形参列表){
操作;
return 返回值/结果
}
2.调用
var接住返回的结果=函数名(实参列表)
- 其实return本意是退出函数,但如果return后跟着一个数据
- 顺便将数据返回函数作用域的外部,但是return只负责返回,不保存
- 所以调用函数时自己那个变量来接住他
- 如果有一天你在全局希望拿着函数的结果去做其它操作,记得加return
3.作用域***
(1)全局作用域:全局变量+全局函数
(2)函数作用域:局部变量+局部函数[当前函数调用时,内部可用,优先使用局部]
特殊(缺点):
1.不要对函数中未声明的变量直接赋值 - 全局污染
2.局部可以使用全局,但全局不能使用局部
解决方式:return
4.声明提前***(只出现笔试)
-
在程序正式执行前,将var声明的变量(轻)和function(重),集中定义在当前作用域的顶部,但是赋值留在原地
-
声明方式创建的函数会完整的提前
-
直接量方式创建的函数只有变量名部分会提前
为什么平时遇不到?? 遵守以下规则:变量名和函数名尽量不要重复/先创建后使用
5.重载***
重复的函数名,后面会覆盖前面的
目的:减轻程序员压力,记住一个方法就可以执行很多操作
解决:在函数内部自带一个arguments的对象(类似数组对象)
不需要我们去创建,可以接受所有实参
默认length长度为0
固定套路:
1.通过下标去获取传入的某一个实参
arguments[i]-i从0开始
2.通过length去获取到底传入了几个实参
arguments.length
通过判断传入实参的不同,在内部去写判断
从而变相的实现重载
七、数组的基础***
(一)数组的概念
创建一个变量可以保存多个数据,可以节约内存提升网站性能
数组都是线性排列:
除了第一个元素,每个元素都有唯一前驱元素
除了最后一个元素,每个元素都有唯一后继元素
**元素的位置叫下标,从0开始,在最大长度结束**
(二)创建数组
1.直接量方式***
var arr=[]; //空数组
var arr=[数据1,...]
2.构造函数方式
var arr=new Array(); //空数组
var arr=new Array(数据1,...);
(三)获取数组中的元素
数组名[i]
(四)后续添加/替换元素
下标处没有则为添加,有则为替换
(五)数组具有三大不限制
1.不限制元素的类型
2.不限制元素的长度
3.不限制下标越界 - underfined
下标越界的解决方式:
数组中的唯一属性length,语法:数组名.length(长度从1开始)
三个固定套路:
1.向末尾添加元素: arr[arr.length]=新数据
2.获取数组的倒数第n个元素: arr[arr.length-n];
3.缩容:删除倒数n个元素 arr.length=n;
(六)遍历数组
固定公式:
for(var i=0;i<arr.length;i++){
arr[i]; //当前次元素
}
八、DOM:文档对象模型*******
DOM:Document Object Model,用于操作HTML文档
(一)DOM树概念
- HTML看做一个倒挂的树状结构,但树根不是html,是document的对象
- document对象:不需要我们创建,由浏览器的js解释器自动创建,一个页面只有一个树根
- 作用:可以通过树根找到我们想要的任意DOM元素/节点/(属性和方法)对象
- DOM会将页面上的每个元素,文本等视为一个DOM/节点/对象
(二)查找元素
1.通过ID查找元素:
var elem=document.getElementById("id值")
特殊:
1.返回值,找到了返回当前找到DOM元素,没找到返回一个null
2.如果出现多个相同ID,只会找到第一个
3.记住控制台输出的样子,这才叫一个DOM元素/节点/对象,才能操作
4.忘记此方法,留给后端
5.其实不用查找,id直接可用
2.通过标签名查找元素*******
** var elems=document/已经找到的父元素.getElementByTagNamed("标签名") **
特殊:
1.返回值,找到了返回一个类数组DOM集合,没找到得空集合
2.js只能直接操作DOM元素,不能直接操作DOM集合***
(解决:要么拿到某个下标,要么遍历拿到每一个)
3、不一定非要从document开始查找,如果从document去找,会找到所有的元素,可以换成我们已经找到的某个父元素
3、通过 class 查找元素*******
var elems=document/已经找到的父元素素.getElementsByClassName("class名");
特殊:
1、返回值,找到了返回一个类数组DOM集合,没找到得到空集合
2、js只能直接操作DOM元素,不能直接操作DOM集合,解决:要么下标拿到某一个,要么遍历拿到每一个。
3、不一定非要从document开始查找,如果从document去找,会找到所有的元素,可以换成我们已经找到的某个父元素
4、通过关系去获取元素:前提条件:必须先找到一个元素才可以使用关系*******
| 通过关系去获取元素 | ||
|---|---|---|
| 父元素 | elem.parentNode; | 单元素 |
| 子元素 | elem.children; | 集合 |
| 第一个子元素 | elem.firstElementChild | 单元素 |
| 最后一个子元素 | elem.lastElementChild; | 单元素 |
| 前一个兄弟 | elem.previousElementSibling; | 单元素 |
| 后一个兄弟 | elem.nextElementSibling; | 单元素 |
- 为什么要通过关系去找元素呢?
- 不希望影响到别人,只希望影响到自己的关系网
5.直接找元素******
任意css选择器
var elem=document.querySelector("任意CSS选择器")
quary查询 selector选择器:查询css选择器
缺陷:只能找到单个元素
如果匹配到了多个,也只能返回第一个,没找到null
var elems=document.querySelectorAll("任意css选择器")
优点:找到了是集合,没找到是空集合
复杂查找时,非常简单
返回时是一个【静态集合】,NodeList
- 面试题:document.getXXX和document.queryXXX的区别?
- 1.后者更适合复杂查找
- 2.动态集合和静态集合的区别?
-
动态集合:不支持forEach,DOM变化后再次查找,让页面和数据保持一致,效率低。
-
静态集合:支持forEach,DOM变化后不会再次查找,让页面和数据没有保持一致,效率高。
-
(三)操作元素
前提:先找到元素,才能操作元素,3方面
1、内容:
(1)elem.innerHTML***
获取和设置开始标签到结束标签之间的内容,支持识别标签的
获取:elem.innerHTML;
设置:elem.innerHTML="新内容";
(2)elem.innerText***
获取和设置开始标签到结束标签之间的纯文本,不识别标签的
获取:elem.innerText;
设置:elem.innerText="新内容";
elem.innerText-获取和设置开始标签到结束标签直接的纯文本,不识别标签
(3)input.value - 专门获取/设置input里的内容
单标签input专属
获取:input.value;
设置:input.value="新内容";
2、属性:
**(1)获取属性值:**
核心DOM: elem.getAttribute("属性名");
HTML DOM: elem.属性名
**(2)设置属性值:**
核心DOM: elem.setAttribute("属性名","属性值");
HTML DOM: elem.属性名="属性值"
(3)删除属性:
只删除了属性值,属性名还在
(类似href、disabled、readonly等)
**核心DOM** elem.removeAttribute("属性名")
HTML DOM: elem.属性名
(4)判断有没有:
只能判断有没有(推荐:elem.getAttribute("属性名");)
**核心DOM** elem.hasAttribute("属性名")
HTML DOM: elem.属性名!="";
HTML DOM简化版的缺点:
1、class必须写为className
ES6(2015年)class变成了一个关键字
2、不能操作自定义属性
建议:优先HTML DOM,HTML DOM实现不了在用核心DOM补充
3、样式:
使用样式的方式:3种
1、内联样式***
2、内部样式表
3、外部样式表 - 一阶段做开发用的都是外部样式表
二阶段我们就要用js来操作【内联样式】
1.不会牵一发动全身
2.优先级最高
获取样式:elem.style.css属性名;
设置样式:elem.style.css属性名="css属性值";
特殊点:
1、css属性名,有横线的地方,去掉横线,变为小驼峰命名法
border-radius ----- borderRadius
2、小缺陷:获取时,我们只能获取到内联样式
因为我们目前学的就是内联样式的操作
4、绑定事件
elem.on事件名=function(){
操作;
关键字this - 这个 ***
如果单个元素绑定事件,this->这个元素
如果多个元素绑定事件,this->当前触发事件元素
}
- 一切的获取,往往都是为了判断
- 一切的设置,可以说是添加也可以说是修改
5.操作内容
innerHTML/innerText/value
6.创建元素和上树
(1)创建空标签
var elem=document.createElement("标签名")
(2)为其设置必要的属性和事件
elem.属性名="属性值";
elem.on事件名=function(){操作}
(3)挂载上树/渲染页面:
父元素.appendChild(elem);
insetBefore(elem,已有子元素);放已有子元素前
replaceChild(elem,已有子元素;替换已有子元素)
7.删除元素
elem.romove();
扩展
1.创建变量:新增let关键词可代替var
- let 变量名=值;
- 作用:
- 解决了声明提前
- 带来了会计作用域,一个{}就是一个块,此变量只能在{}里使用
- 如果用let当下标去绑事件,会记录当前元素的下标,不需要自定义
2.类数组转普通数组
接住=Array.from(类数组对象)
九、数组的基础(补充)***
(一)创建数组
1.直接量
var arr=[值1,...];
2.构造函数
var arr=new Arrey(值1,...);
3.new Array()num;(有坑)
意为创建了一个长度为num的空数组,里面没有任何东西,只有无数的underfined。
(二)按值传递***
面试题:var a=x;var b=a;修改a,b变不变?或修改b,a变不变?
答:
1.传递的如果是原始类型:(字符串,数字等...)
其实是复制了一个副本给对方
两者互不影响
2.传递的如果 是引用类型:(js中除原始类型,其它都是引用类型)
因为引用类型比原始类型大很多
不能保存在变量本地,只保存了地址值
所以其实是将地址值赋值给了对方
两者相互影响
(三)释放引用类型
- 需要释放每一个变量
- 原理:js底层有一个垃圾回收器,只有垃圾计数器为0的时候才会删除不要的数据
十、hash数组(关联数组)自定义下标***
(一)创建空数组
1.创建空数组:var arr=[];
2.为数组添加自定义下标并且赋值:arr["自定义下标"]=新值
(二)访问元素
arr["自定义下标"];
(三)强调
- hash数组的 length失效了,永远为0!
- 遍历hash数组:不能再使用for循序,必须使用for in循环
- 纯自动化,专门为了遍历hash数组存在的
for(var i in 数组名){
i; //下标
数组名[i]; //当前次元素,=后面赋值的内容
}
- for in循环不仅可以遍历hash数组,也能遍历索引数组
- 建议:索引数组依然是for,hash数组再使用for in
(四)hash数组的原理***
- hash算法:把字符串计算出一个尽量不重复的数组(地址值)
- 字符串的内容相同,则计算出来的数字也一定相同
添加元素:
- 将自定义下标交给hash算法,得到一个数字(地址值),将要保存的数据放在里面保存起来
获取元素
- 将指定的自定义下标交给hash算数,得到一个和当初保存时一样的数字(地址值),通过此地址找到你当初保存的数据,取出来使用
(五)js里面的一切都是对象
- 除了underfined和null,js里面的一切都是对象
- 一切对象的底层都是hash数组
十一、数组的API
(一)arr转str***
var str=arr.join("自定义连接符");
1.笔试题:将数组里面的内容拼接成一句话/单词
(其实就是拼接了一个空字符串)
var arr=["h","e","l","l","o"," ","w","o","r","l","d"];
var str=arr.join("");
console.log(arr.join(""));
2.将数组拼接为DOM页面元素(第一次遇到数据渲染页面)
<body id="bd">
<script type="text/javascript">
//以后我们前端会从后端-数据库拿出所有的数据
//假设我们已经拿到了
var arr=["-请选择-","北京","南京","西京","东京","重庆"];
//将数组拼接为页面标签字符串
//var str="<开始标签>"+arr.join("</结束标签><开始标签>")+"</结束标签>";
var str="<h1>"+arr.join("</h1><h1>")+"</h1>";
bd.innerHTML=str;
</script>
</body>
3.二级联动
<body>
城市选择:
<select></select>
<select></select>
<script type="text/javascript">
var sels=document.getElementsByTagName("select");
//生成一级的数据
var arr1=["-请选择-","北京","南京","西京","东京","重庆"];
//生成二级的数据 - 二维数组:数组中再次引用了数组,再次细分分类
var arr2=[
["-请选择-"],
["-请选择-","北京1","北京2","北京3","北京4","北京5"],
["-请选择-","南京1","南京2","南京3","南京4","南京5"],
["-请选择-","西京1","西京2","西京3","西京4","西京5"],
["-请选择-","东京1","东京2","东京3","东京4","东京5"],
["-请选择-","重庆1","重庆2","重庆3","重庆4","重庆5"]
];
sels[0].innerHTML="<option>"+arr1.join("</option><option>")+"</option>";
sels[0].onchange=function(){
var i=this.selectedIndex;
sels[1].innerHTML="<option>"+arr2[i].join("</option><option>")+"</option>";
}
sels[0].onchange();
</script>
</body>
- select专属事件 onchange
- 只有在选中项发生变化时出发
- select专属属性 selectIndex
- 获取当前选中项下标
(二)数组的拼接 concat***
添加元素的新方式,将传入的实参全部拼接到arr末尾
var newArr=arr.concat(新值1,arr1,...);
- 特殊
- 1.不修改原数组,返回一个新值
- 2.count支持传入数组参数,悄悄的将传入的数组打散为单个元素再拼接
(三)截取子数组 slice***
根据传入的开始下标截取到结束下标
var subArr=arr.slice(starti,endi+1);
-特殊
- 1.不修改原数组,返回一个新数组
- 2.含头不含尾
- 3.endi可以省略不写,意为从starti一直截取到结尾
- 4.starti可以省略不写,如果两个实参都省略,意为从头到尾复制一遍这种拷贝是深拷贝,复制了一个副本给对方
- 5.支持负数参数,-1代表倒数第一个
以上API都不会修改原数组
以下API都会修改原数组
(四)删插替***
1.删除
var dels=arr.splice(starti,n);//n代表被删除的个数
- 特殊
- 虽然直接修改原数组,但也有返回值,返回的是被删除的数据组成的新数组
2.插入
arr.splice(starti,0,新值1,...);//
- 特殊
- 原来starti位置的元素和后续元素自动向后移动
- 尽量不要插入一个数组,会导致我们的数组有一维和二位混合,不利于遍历
3.替换
var dels=arr.splice(starti,n,新值1,...);//
- 特殊
- 删除的个数和插入个数可以不同
(五)翻转数组
不常用
arr reverse ();//
(六)数组排列
1.冒泡排序 不推荐
固定公式
var arr = [31, 21, 54, 4376, 69, 8, 8, 65];
for (var j=1; j<arr.length; j++) {
for (var i=0; i<arr.length-j; i++) {
if (arr[i] > arr[i+1]) {
var m = arr[i];
arr[i] = arr[i+1];
arr[i+1] = m
}
}
}
2.数组排序 arr.sort()
默认:将数组中的元素转为字符串后,再按位pk每个字符的unicode号(Ascii码)
- //如果a-b返回的是一个正数:说明后一个>前一个
- //如果a-b返回的是一个负数,说明后一个<前一个
- //如果a-b返回的是一个0,说明后一个==前一个
- //而sort方法会根据你返回的正数、负数、0,来自动考虑要不要交换位置
升序排列
var arr = [3, 6, 5, 1, 2, 11, 4, 123, 122];//匿名回调函数
arr.sort(function(a,b) {
//console.log(a); 后一个数字
//console.log(b); 前一个数字
return b-a; //a-b为升序,b-a为降序
})
console.log(arr);
- 强调
- 网页上只要有功能带有排序,底层一定为数组
- 网页上只要有随机功能,底层一定用了随机数公式
(七)栈和队列
- 添加元素和删除元素的新元素
- 栈其实就是数组,只不过一端封闭,只能从另一端进出
- 优先使用最新的数据
//开头进:向前添加,会导致其他元素下标变化
arr.unshift(新值,...);
//开头出:删除元素,向前添加
var.first=arr.shift();
//结尾进:向后添加
arr.push(新值1,...);
//结尾出:向后添加
var.last=arr.pop();
//结尾进,开头出的缩写
arr.push(arr.shift());
- 扩展
1.开启
timer=setInterval(function){
操作;
},间隔毫秒数)
2.停止 clear Interval(timer)
3.鼠标移入* onmouseover
4.鼠标移出* onmouseout
(八)二维数组
数组的元素,又引用着另一个数组(在一个数组中,希望再次细分每个分类)
- 创建
var arr2=[
["-请选择-"],
["-请选择-","北京1","北京2","北京3","北京4","北京5"],
["-请选择-","南京1","南京2","南京3","南京4","南京5"],
["-请选择-","西京1","西京2","西京3","西京4","西京5"],
["-请选择-","东京1","东京2","东京3","东京4","东京5"],
["-请选择-","重庆1","重庆2","重庆3","重庆4","重庆5"]
];
-
访问
arr[行下标][列下标];
-特殊
-
列下标越界返回underfined
-
行下标越界返回报错。因为行下标越界得到underfined后,没有资格再加[]操作。
-
遍历二维数组:必然两层循环,外层循环控制行,内层循环控制列
for(var r=0;r<arr.length;r++){
for(var c=0;c<arr.length;c++){
console.log(arr[r][c]);
}
}
(九)ES5提供的API
- 简化for循环
- prev:前一个,val:当前值,i:当前值的下标,arr:当前数组本身
1.判断
(1)every:满足所有才为true,类似&&
var bool=arr.every(function(val,i,arr)){
ruturn 判断条件;
}
(2)some:满足一个就为true,类似||
var bool=arr.some(function(val,i,arr)){
ruturn 判断条件;
}
2.遍历
(1)forEach:直接修改原数组
arr.forEach(function(val,i,arr)){
操作;
}
(2)map:不修改原数组返回一个新数组
var newArr=arr.map(function(val,i,arr)){
ruturn 操作;
}
3.过滤和汇总
(1)过滤:筛选filter,原数组不变
var subArr=arr.filter(function(val,i,arr)){
return 判断条件;
}
(2)汇总:reduce
var subArr=arr.reduce(function(prev,val,i,arr)){
ruturn prev tval;
},基础值)
(十)ES6箭头函数
- 简化一切匿名回调函数
- 固定公式
- 去掉function,()和{}之间添加=>
- 如果形参只有一个,那么()可省略
- 如果函数体只有一句话,那么{}也可以省略
- 如果函数体只有一句话并且是return,那么ruturn和{}都可以省略
(十一)eval函数
eval()函数:可以结束一个字符串str作为参数,并把这个参数作为脚本代码来执行,如果在计算器中不使用eval()则为字符串,不能进行运算,结果为underfined---》只能用于脱数组的衣服
十二、String*****
(一)String的概念*****
- 字符串:多个字符组成的只读字符数组(只读:不会修改原字符串,都会返回一个新字符串)
- 和数组的相同点
- 1.字符串中的个数:str.length
- 2.获取字符串中的某个字符:str[i];
- 3.遍历字符串
- 4.所有数组不修改原数组的API,字符串也可以使用(concat、slice)
- 和数组的不同点
- 所有数组直接修改原数组的API,字符串都不可以使用
- 比如排序只有数组可以使用
(二)引用/对象类型***
- String Number Boolen -->包装类型
- Array Function Date Math RegExp(正则
- Error 错误
- Object(面向对象开发方式)
- Global(全局对象)- 只有在浏览器中被window对象代替了,自然保存着全局变量和全局函数,只不过windows可以省略不写。node.js中全局对象就叫global
包装类型***
- 专门用于将原始类型的值,封装成一个引用类型的对象
- 因为原始类型的值,原本就是没有任何属性和方法,意味着原始类型本身就是不支持去做任何操作的,前辈们为了方便程序员操作将这三个提供了包装类型(提供了属性和方法)
- 使用:只要你试图使用原始类型的变量调用属性或方法的时候,自动包装
- 释放:方法调用完毕后,自动释放包装类型,又变成了原始类型
(三)SrtingAPI*****
1.转义字符
- 作用:
- 1.将字符串中和程序冲突的字符转为原文
- 2.包含特殊功能的符号
- --换行:\n
- --制表符:\t -->大空格,跟按tab效果一样
- 3.输出unicode编码的字符
- \u4e00 - ASCII:19968
- \U9FA5 - ASCII:40869
2.大小写转换
- 将字符串中每一个字符【先统一】转为大写或者小写再比较
- 小写:var upper=str. toUpperCase();
- 大写:var upper=str. toLowerCase();
3.获取字符串中指定位置的字符
str.charAt(i) ==>不如str(i) (变量中下标为i的值)
4.获取字符串中指定位置的字符的ASCII码
- 原文转ascii码 var scsii=str.charCodeAt(i);
- ascii码转原文 var 原文=String.fromCharCode(ascii);
5.检索字符串
检查索引,检查下标,获取关键字的下标
var i=str/arr.indexOf("关键字")
- 从starti位置开始,查找右侧第一个关键字的第一个字符的位置
- starti可以省略,默认从0位置开始查找
- 返回值
- 找到了返回第一个关键字第一个字符的下标位置
- 没找到,返回-1
- 判断有没有
- 强调
- 数组也能只有此方法,数组这个方法是后期才添加上的,老IE的数组没有此方法
-笔试题
var str="no zuo "
var str="no zuo no die no can no bibi no";
012345678901234567890123456789
//鄙视题:找到所有的关键字的下标
var index=-1; while((index=str.indexOf("no",index+1))!=-1){
console.log("找到了,下标为:"+index);
}
6.拼接字符串
var newStr=str.concat("新字符串",...)
还不如+运算
7.截取字符串***
var subStr=str/arr.slice(starti,endi+1);
//用法和数组的用法完全一致
var subStr=str.substring(starti,endi+1);
//用法几乎和slice一致,但是不支持负数参数
var subStr=str.substr(starti,n);
//n代表的是截取的个数,不必考虑含头不含尾
8.替换字符串
var newStr=str.replace("固定关键词"/正则表达式,"新内容");
9.切割/分割/分隔字符串
作用:将字符串转为数组
var arr=str.spilt("自定义切割符")
注意:
- 1、切割后,切割符就不存在了
- 2、如果你的切割符些的是" ",切散每一个字符
10.去掉空白字符串
str.trim/trimStart/trimEnd()
11.扩展(js如何创建元素,生成随机数)
js如何创建元素 二维结构
-
1.创建空标签:
var elem=document.createElement("标签名"); -
2.为其设置必要的属性和事件
elem.属性名="属性值"; elem.on 事件名=function(){操作} -
3.挂载上树/渲染页面
-
父元素.appendChild(elem);
生成随机数
arr(Math.random()*(max-min+1)+min)
十三、Math对象
(一)概念
- Math对象:专门提供数学计算机的API
- 强调:可以直接使用
- 属性:PI,其他为科学计数法,几乎用不到
(二)Math的API
1.取整
(1)上取整:超过一点点,就取下一个整数
var num=Math.ceil(num);
//小数位数不能超过15位,否则此方法只能取整,不能上取整
(2)下取整:无论超过多少,都会省略小数部分
var num=Math.floor(num);
(3)四舍五入取整:
var num=Math.round(num);//只看小数位数的第一位
以上三个都局限很大
- 取整的方式:以上三个+parseInt(str去掉单位)+num.toFixed(d)
- num.toFixed(d)
- 优点:
- 1.可以四舍五入,并且保留指定小数位数
- 2.解决浏览器的四舍五入的误差,2-1.6=3.99999...
- 缺点
- 结果是一个字符串,建议搭配parseFloat()使用
- 笔试题:不允许使用toFixed的情况下,自己封装一个函数
- 由用户传入数字和保留位数,实现四舍五入操作
<script type="text/javascript">
function toFixed(num,d){
num*=(10**d);
num=Math.round(num);
num/=(10**d);
return num;
}
var result=toFixed(Math.PI,2);
console.log(result);
</script>
2.乘方和开方***
- 乘方:Math.pow(底数,幂); -> 更简化:底数**幂
- 开方:Math.sqrt(num); - 仅仅只能开平方
3.最大值和最小值***
var max/min=Math.max/min(a,b,c,d,e,f,g,...);
//自动在你传入的数字中比较出最大值或最小值
-
问题:本身不支持数组参数
-
解决:固定用法:
Math.max/min.apply(Math,arr); //apply具有打散数组的功能
4.绝对值
Math.abs(-1);//1
5.随机数 Math.random***
- Math.random(); 在0-1之间去一个随机的小数
- 搭配上parseInt,只能取到0,但是不可能取到1,意味着取不到最大值
- 公式:parseInt(Math.random()*(max-min+1)+min)
- 强调:
- 只要以后网页中某一块有随机的功能,他的底层一定用到了随机数
十四、Date对象:日期对象,提供了操作日期和时间的API。
(一)创建:4种
-
1、创建一个当前日期:
var now=new Date(); -
2、创建一个自定义时间:
var birth=new Date("yyyy/MM/dd hh:mm:ss"); -
3、创建一个自定义时间:
var birth=new Date(yyyy,MM,dd,hh,mm,ss); //修改月份,从0~11,0代表1月
4、复制一个日期:
-
为什么:日期的所有API都是直接修改原日期的,无法获得修改之前的日期
-
所以,在执行API之前先进行复制,然后再操作复制后的日期
var end=new Date(start); -
使用:
-
1、两个日期对象之间,可以相减(大-小),得到一个毫秒差,换算出自己想要的任何一部分 - 日期的本质其实就是保存了一个毫秒数 - 做倒计时的关键
-
创建日期的最后一种方式,绝对没人用:
var date=new Date(毫秒数); //计算机元年:1970年1月1日 8点整
(二)API:
- 分量:时间的单位
- 年月日星期:FullYear Month Date Day
- 时分秒毫秒:Hours Minutes Seconds Milliseconds
- 每一个分量都有一对儿getXXX/setXXX的方法
- 其中getXXX负责获取一个分量的值
- 其中setXXX负责设置一个分量的值
- 特殊:
1、取值范围:
(1)FullYear - 当前年份的数字
(2)Month - 0~11
(3)Date - 1~31
(4)Day - 0~6:0代表是星期天
(5)Hours - 0~23
(6)Minutes、Seconds:0~59
日期你如果设置超出范围,会自动进制
2、Day,没有set方法
3、如果希望对某个分量进行加减操作:
date.setXXX(date.getXXX()+/-n)
4、格式化日期为本地字符串:
date.toLocaleString();
//垃圾:具有兼容性问题
//我们一般会选择自己创建一个格式化方法来格式日
//用了此方法会失去一些东西:日期的自动进制、日期的API
//但是你也会获得一些东西:字符串的API
(三)定时器:
1、周期性定时器:每过一段时间就会执行一次,先等后做**
开启:timer=setInterval(callback,间隔毫秒数);
停止:clearInterval(timer);
2、一次性定时器:等待一段时间,只会做一次就结束了
开启:timer=setTimeout(callback,间隔毫秒数);
停止:clearTimeout(timer);
简写:setInterval(()=>getTime(),500)
- 同步技术:代码必须一行一行的执行,前面没做完,后面就等着
- 定时器是我们第一次见到的异步技术:无论我这一块代码多么的耗时,也不会卡住后续代码
十五、BOM:Browser Object Model - 浏览器对象模型
- 专门用于操作浏览器的,但是它使用的不多,远不如ES和DOM,浏览器很多操作都是自带的,而且BOM没有标准,
- 各个浏览器都有自己的定义,但是大部分浏览器的都是一致规范的,除了老IE(8-)
(一)window对象:扮演着两个角色:
- 1、全局对象:保存着全局变量和全局函数
- 2、指代当前窗口本身:
属性:
- 1、获取浏览器的完整大小:outerWidth/outerHeight
- 2、获取浏览器的文档显示区域的大小:innerWidth/innerHeight - 获取每台电脑的浏览器的文档显示区的大小**
- 3、获取屏幕的完整大小:跟window没关系:screen.width/height; - 我们目前学习的都是浏览器应用(网页),并不会去做桌面应用
方法:
打开链接的新方式:
(1)当前窗口打开,可以后退:
HTML:<a href="url">内容</a>
JS:open("url","_self");
-
(2)当前窗口打开,禁止后退:
-
使用场景:比如电商网站,结账后不允许后退
history:当前【窗口的历史记录】前进后退
location:当前【窗口正在打开的url】:
location.replace("新url");
//替换当前页面,不会产生历史记录
(3)新窗口打开,可以打开多个
HTML:<a href="url" target="_blank">内容</a>
JS:open("url","_blank");
-
(4)新窗口打开,只能打开一个
-
使用场景:比如电商网站,只允许用户打开一个结账页面
HTML:<a href="url" target="自定义一个name">内容</a>
JS:open("url","自定义一个name");
-
其实窗口的底层都是有一个名字的,如果打开了一个已经开着的名字的窗口的,他会把他关闭掉,再次打开
-
学完这块,我们知道了两个点:
-
1、以后的跳转,任何标签都可以
-
2、提升用户的体验感
-
a标签的其他用途:
-
1、跳转
-
2、锚点
-
3、下载按钮:
<a href="xx.exe/rar/zip/7z">下载</a>
- 4、打开图片和txt文档:
<a href="xx.png/jpg/jpeg/gif/txt">
打开图片和txt</a>
- 5、直接书写js-不需要绑定点击事件
<a href="javascript:js代码;">打开图片和txt</a>
打开新窗口/新链接:
newW=open("url","target","width=?,height=?,left=?,top=?");
特殊:
-
1、如果没有加第三个参数,那么窗口会和浏览器融为一体
-
2、如果你加了第三个参数,那么窗口会脱离浏览器独立存在
-
3、关闭窗口:window/newW.close();
-
4、改变新窗口的大小:newW.resizeTo(新宽,新高);
-
5、改变新窗口的位置:newW.moveTo(新X,新Y);
-
6、window提供了三个框:***
警告框:alert("警告文字"); 输入框:var user=prompt("提示文字"); 确认框:var bool=confirm("提示文字"); -
7、定时器也是window的*****
-
8、事件:
-
(1)window.onload事件 - load - 加载:等待其他所有的资源加载完毕后才会执行的代码,放在里面的代码其实要最后才会执行
-
(2)window.onresize事件 - 窗口如果大小发生了变化,就会触发,搭配上判断innerWidth可以理解为是js版本的css媒体查询*
-
(3)window.onscroll事件 - 滚动事件,一旦滚动就会触发***
获取滚动条当前的位置: window.scrollY 获取元素距离页面顶部有多远: elem.offsetTop/offsetLeft -
9、本地/客户端存储技术:***
-
cookie:淘汰了,存储的大小只有2kb,而且操作极其麻烦,尤其要到处切割,只能最多保存30天
-
webStorage:H5带来了一个新特性,存储的大小有8mb,永久保存,而且非常简单
-
分类2种:
-
1、sessionStorage - 会话级,只要浏览器一旦关闭,数据就会死亡了
-
2、localStorage - 本地即,只要你不清空,就会永久存在
-
两者的用法是一模一样的,不用创建,直接可用
-
操作:
-
1、添加:xxxStorage.属性名="属性值";
-
2、读取:xxxStorage.属性名;
-
3、删除:xxxStorage.removeItem("属性名");
-
4、清空:xxxStorage.clear();
(二)history对象
-
保存当前窗口的正在打开的url(现在的url) *
-
程序员常识 *
1.协议:*** https(加密)/http(未加密)/ftp(传输文件)/ws(直播) location.protocal; 2.主机号/IP地址/域名: 域名需要花钱购买,主机号/IP地址免费 主机号:127.0.0.1 只能自己访问自己 location.hostname; 3.端口号 https默认端口为443,http默认端口为80 默认端口可以省略不写 location.port 4.路由/文件的相对路径:*** location.pathname; 5.请求消息/查询字符串:*** location.search; -
跳转
- location="新url"- 替换当前窗口,可以后退
-
跳转后,禁止后退
- location.replace("新url")-替换当前窗口,禁止后退
十六、递归
(一)递归和纯循环
- 递归:简单来说就是再函数之中再一次调用了函数自己,迟早有一天会停下来;
- 何时:专门用于【遍历层级不明确的情况】 - DOM树和数据(children只能找到儿子层,找不到孙子层) - 如何使用:2步
function 函数名(root){
1、第一层要做什么直接做
2、判断有没有下一层,如果有下一层则再次调用此方法
只不过传入的实参是自己的下一层
}函数名(实际的根)
注意:
- 算法:深度优先!优先遍历当前节点的子节点,子节点遍历完毕才会跳到兄弟节点
- 缺陷:不要过多使用,性能相对较差,同时开启大量的函数调用,浪费内存,只有【层级不明确】时使用
区别:递归 vs 纯循环
- 递归:
- 优点:简单易用
- 缺点:性能低
- 纯循环:
- 优点:几乎不占用性能
- 缺点:难的一批
(二)绑定事件:3种方式:
1、在HTML上书写事件属性
<elem on事件名="函数名(实参)"></elem>
缺点:
1、不符合内容与样式与行为的分离原则
2、无法动态绑定,一次只能绑定一个元素
3、不支持绑定多个函数对象
2、在js中使用事件处理函数属性***
elem.on事件名=function(){操作}
优点:
1、符合内容与样式与行为的分离原则
2、动态绑定,一次能绑定多个元素
缺点:
1、不支持绑定多个函数对象
3、在js中使用事件API:如果不用考虑老IE,他也不错***
主流:elem.addEventListener("事件名",callback);
老IE:elem.attachEvent("on事件名",callback);
兼容:
if(elem.addEventListener){
elem.addEventListener("事件名",callback);
}else{
elem.attachEvent("on事件名",callback);
}
优点:
1、符合内容与样式与行为的分离原则
2、动态绑定
3、支持绑定多个函数对象
缺点:有兼容性问题
(三)扩展:select&option:
select&option只有他们可以简化创建元素&上树:
select.add(new Option("innerHTML","value"));
十七、BOM事件*********
(一)事件周期
- 从事件发生,到所有事件处理函数执行完毕的全过程
- 1.捕获阶段:由外向内,记录要发生的事件
- 2.目标优先触发:当前点击的事迹发生事件的元素
- 3.冒泡触发:由内向外
(二)获取时间对象event
- 主流:会自动作为事件处理函数的第一个形参传入
- 老IE:老IE全局都有这个变量
(三)事件对象event的功能
- 1.获取鼠标的坐标
| 获取鼠标的坐标 | |
|---|---|
| 获取鼠标相对于屏幕的坐标 | e.screenX/Y |
| 获取鼠标相对窗口/客户端/文档显示区域的坐标 | e.clientX/Y |
| 获取鼠标相对于网页的坐标 | e.pageX/Y |
- 2.阻止事件冒泡(笔试面试中
| 阻止事件冒泡(笔试面试中 | |
|---|---|
| 主流 | e.stopPropagation(); |
| 老IE | e.cancelBubble=true; |
| 兼容 | e.cancelBubble=true; |
- 3.利用冒泡冒泡*********
- 开发中常用,提升网页性能,事件可换箭头
- 优化:如果多个元素定义了相同或相似的事件操作,最好只给父元素定义一次
- 每一次绑定一个事件函数,其实都是创建了一个事件对象,会影响网站性能
| 目标元素 target | |
|---|---|
| 主流 | e.target; |
| 老IE | e.srcElement; |
| 兼容 | e.srcElement; |
- 4.阻止浏览器的默认行为
| 阻止浏览器的默认行为 | |
|---|---|
| 主流 | e.preventDafault; |
| 老IE | e.returnValue; |
| 兼容 | e.returnValue; |
新事件:右键事件/键盘事件
| 右键事件/键盘事件 | |
|---|---|
| 右键事件 | window.oncontextmenu; |
| 键盘事件 | |
| 按住和按下,任何键盘按钮都可以触发 | window.onkeydown; |
| 按住和按下,只有字母,数字,回车,空格可以触发 | window.onkeypress |
| 松开,任何键盘按键都可触发 | window.onkeyup |
- 5.获取键盘的键码
e.keyCode:
老IE不支持HTML5和CSC3和ES5+
扩展:
- 图片的加载速度比js执行速度慢,所有js执行完,图片还未加载完
- 解决: img.onload - 图片加载完毕后才会执行的代码
- 图片隐藏了,就该删除掉
(四)事件委托
1、如何判断目标元素是什么标签:
xx.nodeName; - 得到大写标签名
2、事件处理函数可以写为箭头函数
this就会失效,所以必须使用目标元素target
3、this的指向:******
1、单个元素绑定事件,this->这个元素
2、多个元素绑定事件,this->当前元素
3、箭头函数,this->外部对象
4、函数中,this->当前正在调用函数的这个人
5、定时器中,this->window
6、构造函数之中this->当前正在创建的对象
(五)事件的取消绑定
1、如果你使用elem.onclick=()=>{},那么elem.onclick=null
2、如果你使用elem.addEventListener("事件名",回调函数); 那么:
elem.removeEventListener("事件名",回调函数);
事件名和回调函数,必须和添加时的一模一样
(六)强制改变this的指向*****
call/apply:临时的替换了函数的this - 借用 语法:
函数名.call(借用的对象,实参,...);
//单独传入每个实参
函数名.apply(借用的对象,arr);
//只能传入一个实参要求是一个数组,apply其实会悄悄的打散数组
强调:call/apply:相当于立刻调用函数,立即执行的
bind:永久替换了函数中的this - 买
- 1、创建了一个和原函数功能完全相同的新函数
- 2、将新函数的this永久绑定为了指定对象,别人都借不走
- 3、将新函数的部分参数永久固定
语法:
var 新函数=函数名.bind(永久对象,永久实参,...);
//不是立刻执行,需要自己调用
强调:bind绑定的新函数没办法被call/apply再次借走
-推荐:借,白嫖! 三个固定套路:
1、Math.max/min.apply(Math,arr) - 也能支持数组参数:
2、Object.prototype.toString.call/apply(x)==="[object Array]";
//鄙视题:判断xx是不也是一个数组
3、类数组转为普通数组:
(1)接住=Array.prototype.slice.call/apply(类数组对象)
(2)接住=Array.from(类数组对象)
十八、ES6:
- 学过了:let、const关键字、箭头函数
(一)模板字符串
可以直接识别变量,不再需要+运算去拼接了,而且实现了一个简答的js环境,甚至支持再里面书写API
`我的名字叫${name}`
(二)解构赋值*****
-
解析结构再进行赋值 - 赋值的新方式,并且得到了增强
-
如果赋值符号,左右两边的结构一样的,就会悄悄的解开/脱掉结构再一一的进行赋值
-
语法:
1、类似数组的解构赋值 let [a,b,c]=[1,2,3]; console.log(a); console.log(b); console.log(c); 2、类似对象的解构赋值 let {a,b=默认值,c}={c:3,a:1,b:2}; console.log(a); console.log(b); console.log(c); //形参可以设置默认值,如果自己传入了,就用自己的 3、调用函数时,传递实参的顺序无所谓了 function zwjs({name,age,hobby="女"}){ return `我的名字叫${name},今年${age}岁,喜欢${hobby}`; } console.log(zwjs({hobby:"学习",age:18,name:"袍哥"})); 4、函数的返回的结果,可以有多个 function f1(){ var a=1; var b=2; return [a,b]; } var [a,b]=f1(); console.log(a,b); 只要以后见到: 方法名({里面放着键值对就是使用了ES6的解构赋值})
(三)Set和Map新的数据类型:
1、Set:类似于数组的一种数据格式 - 【去重数组,然后再转回数组】***
var s=new Set(arr);
...s - 三个点扩展运算符,可以脱掉数组的外套
一句话完成:[...new Set(arr)] - 不用记忆任何API
2、Map:类似于对象的一种数据格式
var m=new Map();
添加:m.set("键","值");
获取:m.get("键");
清空:m.clear();
删除:m.delete("键");
(四)新的循环:垃圾
for(var v of arr){
v;
}
缺陷:
- 1、没有提供过下标,意味着不能修改原数组
- 2、只能遍历索引数组,不能遍历hash数组,意味着也不能遍历对象
十九、正则表达式:定义字符串中字符出现规则的表达式*****
- 何时使用:切割 替换 【验证】!
- 如何使用:
- 语法/正则表达式/
(一)最简单的正则就是关键字原文 "no" -> /no/后缀
- 后缀:g:找全部 i:忽略大小写
(二)备选字符集:/^[备选字符集]$/
强调:
-
1、一个中括号,只管一位字符
-
2、问题:正则表达式默认只要满足就不管后续了,而我们做验证的人,希望的是用户从头到尾按照我们的要求来,希望从头到尾完全匹配
-
解决:
前加^,后加$ 两者同时使用,代表要求从头到尾完全匹配 /^[备选字符集]$/ - 只要做验证必加!
特殊如果备选字符集中的ascii码是连续的,那么可用-省略掉中间部分
比如:
一位数字:[0-9];
一位字母:[A-Za-z];
一位数字、字母、下划线:[0-9A-Za-z_]
一位汉字:[\u4e00-\u9fa5]
除了xxx之外的:[^0-9] - 很少使用,范围太广了
(三)预定义字符集:简化了备选字符集
一位数字:\d ===>[0-9]
一位数字、字母、下划线:\w ===> [0-9A-Za-z_]
一位空白字符:\s
一位除了换行外的任意字符:. - 很少使用,范围太广了
- 建议:优先使用预定义字符集,预定义满足不了我们再用备选字符集补充
- 问题:不管是备选字符集,还是预定义字符集,一个都只管一位
(四)量词:规定一个字符集出现的次数:
1、有明确数量:
字符集{n,m}:前边相邻的字符集,至少n个,最多m个
字符集{n,}:前边相邻的字符集,至少n个,多了不限
字符集{n}:前边相邻的字符集,必须n个
2、无明确数量:
字符集?:前边相邻的字符集,可有可无,最多1个
字符集*:前边相邻的字符集,可有可无,多了不限
字符集+:前边相邻的字符集,至少一个,多了不限
(五)选择和分组:
选择:在多个规则中选一个
规则1|规则2
分组:将多个字符集临时组成一组子规则
(规则1|规则2)
(六)指定匹配位置
^:开头
$:结尾
特殊:两者同时使用,前加^,后加$
表示从头到尾要求完全匹配 - 只要你做【验证】
(七)密码强度验证:
题目:2-4位,可以输入数字、字母,但是必须出现一位大写和一位数字的组合
/^[0-9A-Za-z]{2,4}$/
预判公式:
(?![0-9]+$)
//不能全由数字组成,可能有大写、小写、汉字、日文、特殊符号...
(?![a-z]+$)
//不能全由小写组成,可能有数字、大写、汉字、日文、特殊符号...
(?![0-9a-z]+$)
//不能全由数字组成、也不能全由小写组成、也不能全由数字和小写的组合组成
比如:
/(?![0-9a-z]+$)(?![A-Za-z]+$)[0-9A-Za-z]{2,4}/;
//2-4位,可以输入数字、字母,但是必须出现一位大写和一位数字的组合
/(?![0-9a-z]+$)(?![A-Za-z]+$)(?![A-Z0-9]+$)[0-9A-Za-z]{2,4}/;
//必须三者都有
/(?![0-9A-Za-z]+$)[0-9A-Za-z_]{2,4}/;
//至少要有下划线
(八)支持正则表达式的字符串API*****
1、切割:
var arr=str.split("固定切割符"/RegExp);
2、替换:很有可能出现在笔试之中 *****
(1)基本替换法:
str=str.replace(/正则表达式/后缀,"新内容");
//replace支持支持正则,并且搭配上后缀g就可以找到全部
//缺陷:替换的新内容是一个固定的
2、高级替换法:
str=str.replace(/正则表达式/后缀,function(a,b,c){
console.log(a);//正则匹配到的关键字
console.log(b);//正则匹配到的关键字的下标
console.log(c);//原字符串
return 判断a关键字的长度,而返回不同的星星数量
});
3、格式化:身份证
var id="500103198602215933";
var reg=/(\d{6})(\d{4})(\d{2})(\d{2})(\d{4})/;
id.replace(reg,function(a,b,c,d,e,f,g,h){
//再replace的时候,正则出现了分组,我们会得到更多的形参
//再形参a的后面就会出现n个形参,就看你有多少个分组
//第1个分组获得的内容会保存在第2个形参之中
//第2个分组获得的内容会保存在第3个形参之中
//...
//倒数第二个一定是下标
//倒数第一个一定是原文本身
})
格式化:手机号
var phone="13452390312";
var reg=/(\d{4})\d{4}(\d{3})/;
phone=phone.replace(reg,(a,b,c)=>{
return b+"****"+c;
})
console.log(phone);
总结:
- 1、前加^后加$ - 验证
- 2、替换,你希望替换所有 - 必须加g
3、正则对象:
创建:
1、直接量:var reg=/正则表达式/后缀;
2、构造函数:var reg=new RegExp("正则表达式","后缀");
4.API:
验证:var bool=reg.test(用户输入的);
二十、动画库
- animate.css文件是一个动画库:放着很多很多的动画。
- 如何使用:
1、打开百度:搜索animate.css 得到网址
http://www.animate.net.cn/
https://animate.style/
2、下载 - 你们不用做这个操作
3、引入此文件
4、挑选你喜欢的动画,把class放到那个元素上
5、并且要记得设置上animation-duration:3s; 执行时长
6、还需要根据不同的动画,设置不同的初始效果,才会更好看
二十一、Object:对象********
*****Object:对象 - Array/String/RegExp/Date... 对象具有属性和方法,都是预定义好的,现在我们可以学习自定义对象 - js是基于原型的面向对象语言
- 面向对象 - 三大特点:封装、继承、多态
(一)***开发方式:
-
面向过程:
-
过程 - 开始->结束,其实我们一致的开发方式都是面向过程:先干什么再干什么最后干什么
-
面向对象:
-
对象(属性和方法),js有一句话万物皆对象,假设一个人是一个对象的话:
- 属性:身高、体重、姓名、性别、爱好、智商、情商..
- 方法:吃饭、睡觉、跑步、拉粑粑、打字、上课...
-
何时使用面向对象
-
以后任何操作都要封装在一个对象之中 - 但是新手并不太推荐,难度较大
-
为什么要面向对象:
-
现实生活中所有的数据都必须包含在一个事物之中才有意义
(二)封装/创建/定义:封装自定义对象:3种*****
1、*直接量方式:一次只能创建一个对象
var obj={
"属性名":属性值,
...,
"方法名":function(){操作},
//可以简化为箭头函数
...
}
强调:
- 1、其实属性名和方法名的""可以不加 - 暂时建议你加上,以后我们要学习一个数据格式JSON,他必须在键上加上""
- 2、访问对象的属性和方法:
- obj.属性名;===obj["属性名"];
- obj.方法名(); === obj"方法名";
- 建议使用.去访问对象的属性和方法,更简单
- js中一切都是对象,除了undefined和null,一切对象的底层都是hash数组
- 3、访问到不存在的属性,返回undefined
- 4、可以随时随地的添加新属性和新方法
- obj.属性名=新值;
- obj.方法名=function(){};
- 5、如果我希望遍历出对象所有的东西,必须使用for in,obj[i]才能拿到,不要使用.会出问题
- 6、如果你希望在对象的方法里,使用对象自己的属性,写为this.属性名
2、预定义构造函数方式:一次只能创建一个对象
var obj=new Object();//空对象
//需要自己后续慢慢添加属性和方法
obj.属性名=新值;
obj.方法名=function(){};
3、自定义构造函数方式:2步
(1)创建自定义构造函数
function 类名(name,age,hobby){
this.name=name;
this.age=age;
this.hobby=hobby;
}
//千万不要在里面创建方法,
每个对象都会创建出一个相同的方法,浪费内存
- 学习继承后可以解决
(2)调用构造函数创建对象
var obj=new 类名(实参,...);
面向对象
- 优点:
- 1、逼格高,所有的属性和方法都保存在一个对象之中 - 更符合现实更有意义
- 2、每个功能特地分开写 - 便于以后维护
- 3、铁锁链舟 - 一个方法触发多个方法联动
- 缺点:
- 对新手不友好,尤其是this的指向问题
(三)继承:父对象的成员(属性和方法),子对象可以直接使用*****
- 代码重用!提高代码的复用性,节约了内存空间!提升了网站的性能!
- 何时继承:
- 只要多个子对象公用的属性和【方法】,都要集中定义在父对象之中
1、如何找到原型对象(父对象):***
保存了一类子对象共有属性和共有方法
1、对象名.__proto__; //必须先有一个对象
2、构造函数名.prototype;
//构造函数名几乎人人都有
除了Math和Window,new 构造函数名();
//Array、String、Date、RegExp...
2、面试题:两链一包:作用域链和【原型链】和闭包*
-
1、作用域链:
- 以函数的EC的scope chain属性为起点,经过AO,逐级引用,形成的一条链式结构,我们就称之为叫做作用域链。
- 作用:查找变量,带来了变量的使用规则:优先使用自己的,自己没有找全局,全局没有就报错(面向对象)
-
2、原型链:
- 每个对象都有一个属性叫做.
__proto__,可以一层一层的找到每个对象的原型对象,最顶层的就是Object的原型,形成的一条链式结构,我们就称之为叫做原型链 - 作用:查找属性和方法,哪怕自己没有也会顺着原型链向上找,怪不得人人都能用toString(),因为他在最顶层(面向过程)
- 每个对象都有一个属性叫做.
-
3、闭包:
- 希望保护一个可以【反复使用的局部变量】的一种词法结构,其实还是一个函数,只是写法比较特殊
- 作用:专门用于防抖节流
3、设置共有属性和共有方法
1、原型对象.属性名=属性值;
2、原型对象.方法名=function(){}
4、继承判断是自有还是共有:*****
(1)判断自有:
obj.hasOwnProperty("属性名");
//如果结果为true,说明是自有属性
//如果结果为false,有两种可能,说明可能是共有,也可能是没有
(2)判断共有:
if(obj.hasOwnProperty("属性名")==false&&"属性名" in obj){
//in关键字,会自动查找整条原型链上的属性
//找到了结果为true,找不到结果为false
共有
}else{
没有
}
**完整公式:**
if(obj.hasOwnProperty("属性名")){
自有
}else{
if("属性名" in obj){
共有
}else{
没有
}
}
5、修改和删除:自有和共有
自有:
修改:obj.属性名=新属性值;
删除:delete obj.属性名;
共有:
修改:原型对象.属性名=新属性值;
//千万不要觉得,自己能拿到,就能直接修改
//这样并没有修改原型的东西,而是在本地添加了一个同名属性
删除:delete 原型对象.属性名;
//如果你对着本地直接删除,那么此操作直接无效
6、*如何为老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;
}
}
var arr1=[1,2,3,4,5];
var arr2=[2,4,6,8,10];
7、如何判断x是不是一个数组:*
4种方法:
-
千万别用typeof(),只能检查原始类型,不能检查引用类型,如果检查引用类型得到的结果都是一个object。
1、判断x是否继承自Array.prototype: Array.prototype.isPrototypeOf(x); //结果为true,说明是数组 //结果为false,说明不是数组 2、判断x是不是由Array这个构造函数创建的 x instanceof Array; //结果为true,说明是数组 //结果为false,说明不是数组 3、Array.isArray(x); //ES5新增的方法,只有数组可以这么使用 //结果为true,说明是数组 //结果为false,说明不是数组 4、**输出【对象的字符串】形式** 在Object的原型上保存着最原始的toString方法 原始的toString输出形式:[object 构造函数名]
8、多态:
子对象觉得父对象的成员不好用,就在本地定义了同名函数,覆盖了父对象的成员,不严格定义:同一个方法,不同的人使用,效果不同,有多种形态
固定套路:
Object.prototype.toString.call(x)==="[object Array]"
9、实现自定义继承:
1、两个对象之间设置继承
子对象.__proto__=父对象
2、多个对象之间设置继承
构造函数名.prototype=父对象;
时机:应该在开始创建对象之前就设置好继承关系
(四)class关键字:简化面向对象(封装、继承、多态)
class 类名 extends 老类{
constructor(name,age,hobby,...){
//放在constructor里面的都是自有属性
super(name,age);
this.hobby=hobby;
}//放在constructor外面的都是共有方法
//还会继承到老类所有的API,也可以添加新的
}
(五)Function:闭包*****
作用域:2种
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自动释放,局部变量也就释放了
闭包: 希望保护一个可以【反复使用的局部变量】的一种词法结构,其实还是一个函数,只是写法比较特殊 何时使用: 希望保护一个可以【反复使用的局部变量】的时候 如何使用:
1、两个函数进行嵌套
2、外层函数创建出受保护的变量
3、外层函数return出内层函数
4、内层函数再操作受保护的变量
function outer(){}
outer() 强调:
- 1、判断是不是闭包:有没有两个函数嵌套,返回了内层函数,内层函数再操作受保护的变量
- 2、外层函数调用了几次,就创建了几个闭包,受保护的变量就有了几个副本
- 3、同一次外层函数调用,返回的内层函数,都是在操作同一个受保护的变量
缺点: 受保护的变量,永远都不会被释放,使用过多,会导致内存泄漏 - 不可多用 问题:应该在哪里去使用呢?
- 三个事件需要防抖节流 - 共同点:触发的速度飞快
- 1、elem.onmousemove - 鼠标移动事件
- 2、input.oninput - 每次输入/改变都会触发
- 3、onresize - 每次窗口改变大小都会触发
防抖节流的公式:
function fdjl(){
var timer=null;
return function(){
if(timer!==null{clearTimeout(timer);timer=null;}
timer=setTimeout(()=>{
操作
},500)
}
}
var inner=fdjl();
elem.on事件名=function(){
inner();
}
(六)保护对象:保护对象的属性和方法
1、四大特性:
{
value: 1001,
//实际保存值的地方
writable: true,
//开关:控制着是否可以被修改 - 默认值:都为true
enumerable: true,
//开关:控制着是否可以被for in循环遍历到
//- 默认值:都为true
configurable: true
//开关:控制着是否可以被删除
//- 默认值:都为true,总开关:一旦设置为false,其他特性不可以在修改,而且它本身也是一旦设置为false,不可逆
}
修改四大特性:
(1)单一写法
Object.defineProperty(对象名,"属性名",{
修改四大特性
})
调用一次方法只能保护一个属性的四大特性
(2)复合写法
Object.defineProperties(对象名,{
"属性名":{修改四大特性},
...
})
至少方法只调用了一次
2、三个级别:
1、防扩展:防止添加
Object.preventExtensions(obj);
2、密封:防止添加和删除
Object.seal(obj);
3、冻结:防止添加和删除和修改
Object.freeze(obj);
3、动态数据***
Object.defineProperty(obj,"name",{
get:()=>{
console.log("获取数据会进行拦截");
},
set:v=>{
console.log("设置数据会进行拦截");
v;//拦截到的新数据
d1.innerHTML=v;
}
})
vue中的所有数据都是动态数据,意味着他的底层就是做了拦截操作
(七)对象的深浅拷贝:*
1、浅拷贝:
var obj1={"name":"obj1"};
var obj2=obj1;
2、深拷贝:
var obj1={"name":"obj1"};
var obj2={...obj1}
3、深拷贝(以后如何脱掉后端传来的数据)
后端穿衣服:var jsonText=JSON.stringify(obj1);
前端脱衣服:var jsonObj=JSON.parse(jsonText);
此方法也能实现深拷贝
(八)Error对象:报错分析*
以后工作/学习的目的:
- 1、快速找到错误
- 2、记得要放用户
1、***浏览器自带4种错误类型:可以快速找到自己的错误
语法错误:SyntaxError - 一定是你的符号写错了
引用错误:ReferenceError - 没有创建就去使用了
类型错误:TypeError - 不是你的方法,你却去使用了
范围错误:RangeError - 只有一个API会碰到:num.toFixed(d);//d取值范围:0~100之间
2、只要发生错误,就会报错导致后续代码终止(闪退),我们不希望
错误处理: 就算发生错误,我们也不希望报错,而是给出一个错误提示,让后续代码可以继续执行
语法:
try{
只放入你可能出错的代码
}catch(err){
发生错误后才会执行的代码
alert(err);
//err就是我们的错误提示:只不过是英文的
alert("中文的错误提示,来提示用户");
}
- try...catch...的性能非常差,几乎是所有代码里最差的,放在try中的代码效率会被降到最低
- *可以用一个技术代替他:分支结构
- *开发经验:记住一切的客户端输入/用户输入都是坏人 - 但是你不必担心,只要你做好该做的防护就不会出错(!isNaN、正则)
3、抛出自定义错误,只要是错误,后续代码都不会执行
throw new Error("自定义错误消息");
4、ES5:严格模式
开启:"use strict"; - 写在任何一个作用域的顶部都可以
作用:
1、禁止了全局污染,使用变量之前必须先创建变量
2、将静默失败升级为了错误
5、柯里化函数
把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术
function add(a){
return function(b){
return function(c){
console.log(a+b+c);
}
}
}
add(3)(5)(7)
二十二、百度/高德地图:
(一)定位技术有哪些?
- 1、GPS - 美国(卫星定位):
- 需要缴纳版权费用|安全性低
- 2、北斗 - 中国自主:
- 最初并不是民用,而是军用,使用的是惯性定位(定位并不精准)
- 后期发展为了民用,添加了卫星定位了(更精确了) 物联网、车联网...
- 3、基站定位
- 信号的范围发射,可以检测到你现在的信号属于哪个范围。
- 4、IP定位
(二)开发者如何使用:
- 1、打开百度:搜索百度地图开放平台
- 2、注册、登录百度账号
- 3、拉到最下面、点击立即注册成为开发者
- 4、进入控制台
- 5、应用管理->我的应用->创建应用->实名认证->获得密钥(AK)
- 6、鼠标移动到导航条->放到开发文档上->web开发->JavaScript API->示例DEMO
- 7、挑选出你喜欢的地图,然后复制全部代码(HTML/CSS/JS),到你需要的位置
- 8、查询经纬度:api.map.baidu.com/lbsapi/getp…
- 9、百度地图你看上的每一个都可以混搭在一起,但是一定要注意版本:普通版(老) 和 webGL(新),是不可以混搭的
二十三、匿名函数:没有名字的函数
(一)自调:只能执行一次
好处:函数中的没用的变量是会自动释放的,他可以用于代替全局代码写法,两者很相似:都只会执行一次,但是自调会释放 语法
(function(){
console.log(1);
})();
(二)回调:匿名函数不是自调,就是回调
elem.on事件名=function(){}
arr.sort(function(){})
var obj={
"方法名":function(){}
}
一切的回调函数,都可以简化为箭头函数
二十四、设计模式:
不仅仅局限于前端,它是一种编程思想,越来越复杂,对于我们前端人员要求也越来越高了。可以了解一下21种设计模式
(一)单例模式:
-
也称之为单体模式,保证一个类仅有一个实例对象,并且提供一个访问它的全局访问点,为三阶段的vue,new Vue();
-
举例:一个班级只有一个班主任,只有一个太阳,一个国家只有一个主席,"唯一" "便于访问(全局访问的)",行为对象变成做单例
-
如何实现:
-
利用ES6的let不允许重复声明的特性,刚好就符合了单例的特点
let obj={ "name":"袍哥1", "getName":()=>this.name, }
-
-
缺点
- 1、污染命名空间(容易变量名冲突)
- 2、维护时不容易管控(搞不好就直接覆盖了)
推荐写法:
var h52301=(function(){
let state=null;
return function(name,age){
this.name=name;
this.age=age;
if(state){
return state;
}
return state=this;
}
})();
h52301.prototype.sayHello=function(){
console.log(this.name);
}
var llc=new h52301("兰林传",18);
var yxw=new h52301("因性温",19);
console.log(llc);
console.log(yxw);
console.log(yxw==llc);
llc.sayHello();
yxw.sayHello();
何时使用:我们的页面只有一个弹出框
(二)发布订阅模式 :
为三阶段vue的bus总线用到的底层原理就是我们的发布订阅模式
let obj={};
//创建订阅者
function on(id,fn){
if(!obj[id]){
//判断有没有此id(有没有这个人),没有就创建一个空数组
obj[id]=[];
}
obj[id].push(fn);
}
on("老袍",(msg)=>{console.log("小兰来了",msg)});
on("老袍",(msg)=>{console.log("小尹来了",msg)});
on("老袍",(msg)=>{console.log("小张来了",msg)});
on("老袍",(msg)=>{console.log("小李来了",msg)});
on("老袍",(msg)=>{console.log("小赵来了",msg)});
console.log(obj);//{"老袍":[fn,fn,fn,fn,fn]}
//发布者的操作
function emit(id,msg){
obj[id].forEach(fn=>fn(msg));
//obj["老袍"].forEach
}
btn.onclick=()=>{
emit("老袍","一支穿云箭");
}
(三)事件轮询:
js其实是单线程引用,代码必然是从上向下,一步一步的执行,如果某一块代码非常耗时,可能会导致整个页面卡住,尤其如果你把js放在head之中,会看到页面是一个白板
1、宏任务:
不会再卡住我们的单线程应用,可以让后续代码先走,我们慢慢跟着来,但是问题在于,多个宏任务同时存在,到底谁先执行谁后执行,分不清
- (1)定时器:setInterval和setTimeout
- (2)Ajax
2、微任务:
ES6提供的Promise对象 - 可以控制异步代码,依然是异步代码,但是可以控制执行的顺序了
function ajax1(resolve){
setTimeout(()=>{
console.log(1);
resolve();
},Math.random()*5000);
}
function ajax2(){
return new Promise(resolve=>{
setTimeout(()=>{
console.log(2);
resolve();
},Math.random()*5000);
})
}
function ajax3(){
return new Promise(resolve=>{
setTimeout(()=>{
console.log(3);
resolve();
},Math.random()*5000);
})
}
new Promise(ajax1).then(ajax2).then(ajax3);
//promise的回调函数提供了一个形参函数,可以用于放行
console.log("后续代码");
二十五、Node_js基础
(一)基本内容:
1、服务器端概念:
- 简单来说就是一台电脑
- 生活中:微机
- 商业中/国家中:小型机(造价几十万好的上百万)、中型机、大型机、超级计算机
拥有服务器的方式:
-
(1)买一对中小型公司不友好
-
(2)买一台配置好一点的微机 - 对于别的行业的公司也不太划算
-
(3)租云服务器 - 腾讯云、阿里云、新浪云、百度云... 配置自选:配置越好,价格越高,按年收费
-
对于开发人员来说
- 硬件服务器 - 人人都有一台电脑
- 软件服务器 - 中间件(软件可以将你的电脑变成一台服务器,人人都可以来访问你,就是我们要学习的Node.js
软件架构:服务器很重要
(1)C/S - Client客户端/Server服务器端
举例:
QQ、微信、大型网络游戏
优点:
1、用户体验感较好
2、运行稳定
3、对带宽的要求低
缺点:
1、占硬盘空间
2、更新过于麻烦 - 服务器端和客户端都要更新
(2)B/S - Browser浏览器端/Server服务器端
举例:
网页版QQ、微信、游戏
优点:
1、几乎不占硬盘
2、更新简单 - 只需要更新服务器端
3、电脑在垃圾都可以玩得起
缺点:
1、用户体验感较差(越来越好,尤其是现在出了个云平台,根本不用考虑你的电脑好不好,配置如何)
2、对带宽的要求高(还好现在的网速越来越快的)
2、Node.js概述:
-
不是JS,但是语法和JavaScript非常相似,他的竞争对手:Java、C++、C#、Python...
-
做的功能绝对不是特效!做的事和服务器端其他语言是一致(和数据库进行交互,成为了一个前端到数据库的中间桥梁)
-
目的:
- 1、使用代码搭建一个服务器&文件系统(服务器文件可以放在任何位置,但是不在你的电脑里,你可以根据网址来访问到我的东西)
- 2、Node.js如何沟通前端和数据库
- 3、全栈:图书管理系统(HTML+CSS+JS+Node+Mongo)
(二)Node.js安装:node-v18.15.0-x64.msi
检查是否安装成功:打开cmd输入:node -v - 查看版本号,如果有版本号代表你已经安装成功!
(三)Node.js运行模式
1、交互模式 - 临时测试
打开cmd输入:node回车,就可以开始敲你的"js"代码
2、脚本/文件模式 - 正式开发中
1、先创建xx.js,里面书写自己的代码
2、打开cmd输入:node 文件的绝对路径
3、安装插件
vscode - code runner
对着文件出右键,第一个选项就是code runner,或者 右上角有一个开始按钮
(四)Node.js知识:
1、js和node的区别
- 相同点:
- 都可以使用一切的ECMAScript的东西包括一切的API都可以使用,在服务器端不存在任何浏览器,所以不必担心兼容问题
- 不同点:
- 1、JavaScript:DOM+BOM - 做特效
- 2、Node.js:虽然没有DOM+BOM,但是他却又10万以上+的模块等待我们学习
2、模块(module):
每一个xx.js文件,都可以称之为是一个模块
(1)公开/暴露自己的成员
exports:Node.js自带的一个预定义变量,可以直接使用,是一个对象,放在此对象里面的东西,就是允许公开的东西
-
语法:
1、exports.属性名=属性值; 2、module.exports={ 属性名:属性值, ... } 错误导出法: exports={ name:"袍哥", age:18, hobby:"学习" }
(2)导入/引入其他模块
require:Node.js自带的一个预定义变量,可以直接使用,是一个函数,函数中需要书写出引入模块的路径
- 语法: var x=require("./文件名")
鄙视题:exports和module.exports有什么区别?
1、语法,写法,用法不同
2、都是用于公开暴露自己的成员的
但是exports={},写法是错误的
其实Node.js底层有一句话:exports=module.exports
其实真正做公开功能的是module.exports
如果你使用了 exports={};//你创建了一个新的空对象,把module.exports,所以不在具有公开的功能
3、模块的分类:
(1)官方模块
1、Global模块:不需要引入的,可以直接使用
1、五个预定义变量,可以直接使用
(1)__filename - 获取当前文件完整的绝对路径
(2)*__dirname - 获取当前文件绝对路径,不包含文件的名字,何时:vscode某的同学可能不支持node.js上书写相对路径,只能写绝对路径 - 等我们学习了文件系统
(3)*exports - 空对象,可以用于公开暴露自己的成员
(4)*require - 函数,可以用于导入其他模块
(5)***module - 指代当前模块本身,甚至包含着以上4个操作
2、定时器(周期性、一次性、瞬间定时器):定时器不是当初的js,只不过用法和当初一摸一样
3、console也不是当初的console,只不过用法和当初一摸一样
2、querystring模块:解析查询字符串,使其变成一个对象,可以获取到前端传到后端的消息
需要引入:var qs = require('querystring');
作用:解析url查询字符串部分的功能
var obj=qs.parse("查询字符串");
想要获得前端传来的每一个部分:obj.键名;
垃圾:如果前端传来的是一个完整的url网址,他就解析不了了!
3、url模块***
需要引入:var url = require('url');
作用:提供了解析url各个部分的功能
var objUrl=url.parse("网址",true);
//支持第二参数,是一个布尔值,默认为false,一旦设置为true,自动使用querystring模块的parse方法去解析查询字符串部分
- 真正的重点:
- 1、查询字符串:objUrl.query.键名; - 前端form表单提交传到后端的东西
- 2、路由/文件相对路径/请求地址:objUrl.pathname - 判断路由的不同,去读取不同的HTML发送给我们的用户看
4、Buffer模块:
缓冲区,可以将数据变成一个16进制的数字,后面的一些API可能会导致我们被动都到Buffer,但是你也别怕,因为Node.js中大部分的API,是支持Buffer
5、fs模块*****
需要引入:
var fs = require('fs');
*异步读取文件:
fs.readFile("文件路径",(err,buf)=>{
buf->读取到的内容
})
异步写入文件:
fs.writeFile("文件路径","新内容"/buf,()=>{
console.log("写入完毕后,要做什么,必须放在这里面");
})//会替换掉原来的东西
异步追加文件:
fs.appendFile("文件路径","新内容"/buf,()=>{
console.log("写入完毕后,要做什么,必须放在这里面");
})//会替换掉原来的东西
强调:只有异步才能更完美的发挥Node.js的特点(快)
6、http模块 - 超级重点:搭建服务器
//引入了http(搭建服务器)、url(区分开路由和请求消息)、fs(读取文件响应给用户看)
var http=require("http");
var url=require("url");
var fs=require("fs");
//创建服务器应用
var app=http.createServer();
//为其绑定监听端口
app.listen(80);
//为其绑定请求事件:http:请求 - 响应模式,必须要有一个请求,才有一个响应
app.on("request",(req,res)=>{
//req:request(请求)对象,他有一个属性叫做req.url,看了一获取到前端传到后端的路由和请求消息,但是路由和请求消息是融为一体的,不方便我们获取某个部分,所以我们引入了url,进行解析,分开两部分
var objUrl=url.parse(req.url,true);
//保存路由
var router=objUrl.pathname;
if(router=="/" || router=="/index.html"){
//判断路由的不同,读取不同的页面给用户看
//res:response(响应)对象,他有一个方法:res.end(响应的内容) - 可以响应给前端想要的东西
fs.readFile("./public/html/index.html",(err,buf)=>{
res.end(buf);//res.end只能用一次
})
}
})
扩展: 字符串有一个API:math var rs=str.match(reg);和indexOf几乎一致,但是支持正则,我们不关心为多少,只关心为不为null
强调: 一切的src和href都是一个请求都是一个路由,这个请求就需要后端来解析,根据不同的请求响应不同的内容
(2)第三方模块
多到数不清出,提供了很多官方模块没有的东西,有一个网址npm可以去下载 - 明天我们在学习
(3)自定义模块
Node.js最大的特点:
- 快、非常快 - 以前最快的是php,js的速度是php的十六倍
- 因为官方提供的东西少,甚至连数据库的操作API都没有提供的
- 使用了chrome浏览器的v8引擎
4、模块(每个.js文件)的分类
- (1)官方模块:不需要下载,再安装Node.js环境的时候就已经自带了,但是有的模块需要引入:require("模块名");
- (2)第三方模块
- (3)自定义模块:自己书写的xx.js:require("./模块名");
自定义模块:
-
1、文件模块:
- 创建xx.js去公开需要公开的内容,主模块要引入,必须写为require("./模块名");
-
2、目录模块:3种用法
- 1、比如创建m1的文件夹,在其中创建index.js的文件,去公开需要公开的内容,主模块要引入,必须写为require("./m1");
- 2、比如创建m2的文件夹,在其中创建xx.js的文件,,去公开需要公开的内容,主模块要引入,必须写为require("./m2");必须再创建一个package.json的配置文件,写入:{"main":"xx.js"}
- 3、创建一个文件夹必须名为:node_modules,再在其中创建出m3文件夹,在其中创建index.js的文件,去公开需要公开的内容,主模块要引入,必须写为require("m3");
-
3、如何下载第三方模块:
-
npm工具:Node Package Manager:Node.js的模块/包管理器,专门用于管理第三方模块的,作用:下载、更新、删除、维护包之间的依赖关系
-
打开网址:npm官网www.npmjs.com/
-
搜索你需要用到的模块:尽量用带有完全符合标签的那个包,或者是 第一个包:
1、打开cmd:检查npm是否安装成功:npm -v 2、在你的项目之中,再打开cmd 3、下载:npm i 包名 4、更新:npm up 包名 5、删除:npm un 包名
-
二十六、mongo就是基于json的数据库
(一)安装&启动:
- 1、解压我提供的mongodb-win32-x86_64-2008plus-ssl-3.6.11.zip文件
- 2、打开bin文件夹,里面有:mongo.exe(客户端) 和 mongod.exe(服务器端)
- 3、如何启动:
- 在bin文件夹中打开cmd:输入:.\mongod.exe --dbpath=你想要保存的绝对文件夹路径; - 服务器开启成功,而且那个文件夹就保存着你以后要存储的所有的数据
- 不要关闭mongo服务器的cmd
- 再打开一个cmd:输入:.\mongo.exe - 在上一个命令行可以查看我们是否链接成功 - 客户端开启成功
(二)mongo的语法:都是在客户端cmd输入
1、数据库的操作
1、查询所有数据库:show dbs
2、创建/切换数据库:没有就创建,有了就切换:use 数据库名称
3、查看当前选中的数据库:db
4、创建数据表:db.createCollection("表名") - 无限,一定要先创建数据表后,我们才能查看到自己创建的数据库
5、删除数据库:db.dropDatabase(); - 一旦删除不能恢复,不推荐,因为要坐牢
2、数据表的操作
1、创建数据表:db.createCollection("表名",{size:5242880,capped:true,max:5000}) - 最大存储空间为5mb,最多存储500个,意味着这个数据表做了限制,不推荐
2、查看目前所有的数据表:db.getCollectionNames();
3、删除数据表:db.表名.drop();
3、*****数据的操作
1、增:db.表名.save({键值对,...}) - 一次只能插入一条数据
db.表名.save([{},{},{},....]) - 一次插入多条数据
举例:db.user.save([{name:"付楠",age:18,pwd:"666666",email:"fn@qq.com",vip:"0"},{name:"袍哥",age:19,pwd:"999999",email:"pg@qq.com",vip:"1"}])
2、删:db.表名.remove({}) - 不推荐,删除数据库中所有的数据
db.表名.remove({name:"任小波"}) - 会删除数据库中name:"任小波"的所有数据
3、改:db.表名.update({条件},{$set:{新内容}});
举例:db.表名.update({name:"任小波"},{$set:{pwd:"123123"}});
4、*查:db.表名.find(); - 找所有
db.表名.find({pwd:"666666"}); - 找到所有的密码为666666的数据
db.表名.find({},{name:1,pwd:1}) - 找到所有的数据,但是只返回name和pwd
db.表名.find().sort({age:1}) - 按照age升序排列,-1为降序排列
db.表名.find({age:{$gte:18}}) - 拿到所有age大于等于18的数据
db.表名.find({name:/正则/}) - 甚至可以用正则(模糊查询)
db.表名.find().skip(5).limit(5) - 跳过前5条,再拿5条,理解为5-10条数据(第几个分页条显示第几条数据-第几条数据)
db.表名.find().count() - 获取到此表有多少条数据(做出分页条)
(三)安装mongoDBCompass软件:
图形化界面,直观、好看、方便 - 仅仅只用于给我们方便查看
(四)Node.js操作mongoDB:
1、安装第三方模块:mongoose
2、使用步骤:
1、引入:const mongoose = require('mongoose');
2、连接数据库:mongoose.connect("mongodb://127.0.0.1/数据库名称");
3、创建出一个新的数据表的同时,设置数据类型的控制,防止用户乱输
const UserSchema=mongoose.Schema({
age: Number,
pwd: String,
email: String,
vip: String,
name: String,
})
// 模型名 类型限制
var User=mongoose.model("User",UserSchema,"数据表名");
4、增:
var x=new User({
//仅仅只是创建出了一个x对象,并没有放入到数据库之中
age: "20",
pwd: "123123",
email: "dy@qq.com",
vip: "0",
name: "dy",
})
x.save((err)=>{
console.log("新增成功后要干什么");
})
5、删:
User.remove/deleteOne/deleteMany({条件},(err)=>{// - 作者不推荐remove在mongoose之中使用
console.log("删除成功后要干什么");
})
6、改:
User.update/updateOne/updateMany({条件},{新内容},(err)=>{// - 作者不推荐update在mongoose之中使用
console.log("修改成功后要干什么");
})
7、查:
User.find({条件},(err,result)=>{
result就是你的查找到的结果
})
强调:mongoose不要下载,一会儿用我传给你们的
目前:前端能传到后端的技术,只有一个:form表单,action属性可以随便自定义一个路由名称,后端解析此路由就可以通过objUrl.query.键名得到想要的部分
二十七、Ajax:Asynchronous JavaScript And XML*****
(一)同步交互和异步交互的概念:
-
1.同步交互:
- 用户向服务器端发起请求,直到服务器端进行响应的全过程,用户是不可以做其他事情的(等)
- 典型:表单提交、网址请求 - 都属于同步交互
-
2.异步交互:
- 用户向服务器端发起请求,直到服务器端进行响应的全过程,用户是可以做其他事情的(不等)
- 典型:ajax请求
(二)Ajax的定义
- 直译:异步的JavaScript和XML - 前端技术
- 不严格的定义:页面不完全刷新,只会导致页面局部发生改变的技术
- 见过的异步技术/代码:
- 1、定时器 - 做特效
- 2、mongoose操作数据库的增删改查 - 操作数据库
- 3、ajax - 目的:在不刷新页面的情况下和服务器端进行交互 - 可以将服务器端的数据放到前端(比较验证、数据渲染)
- 见过的异步技术/代码:
(三)使用步骤:
1、创建ajax核心对象:
var xhr=new XMLHttpRequest();
2、建立和服务器端的连接
xhr.open("GET/POST","路由");
3、向服务器端发送请求消息
xhr.send();//但是此方法很特殊:
1、如果你是GET请求,send方法会失效,但是还不能省略,必须写为:
xhr.open("GET","路由?key=value&key=value&...");
xhr.send(null);
2、如果你是POST请求,send方法可用,必须写为:- 暂时不能用
xhr.open("POST","路由");
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
xhr.send("key=value&key=value&...");
get:获取 - ajax一般都是使用get,去找服务器端那东西的 - 举例:跟安全性不挂钩的,搜索框
post:发送 - 举例:跟安全性挂钩,登录、注册
4、绑定状态监听事件
xhr.onreadystatechange=()=>{
if(xhr.readyState==4&&xhr.status==200){
xhr.responseText - 服务器端相应的文本,ajax就难在你拿到东西了要干什么
}
}
readyState的请求状态
0 尚未初始化
1 正在发送请求
2 请求完成
3 请求成功,正在接受数据
4 数据接受成功
status的请求状态
200 表示请求成功
202 请求被接受但处理未完成
400 错误的请求
404 资源未找到
500 内部服务器错误,如asp代码错误
二十八、数据格式:
(一)XML:
1、面试题:HTML、XHTML、DHTML、XML分别是什么?
- HTML - 网页:预定义了很多标签,我们学习后,就可以使用他们写出网页
- XHTML - 更严格的网页:HTML5 -> XHTML -> HTML4.01,比如:
-
<input />、<input disabled="disabled"> - DHTML - 动态效果网页:在离线端,我们的网页也具有动态的特效:其实不是新技术也不是新概念,而是现有技术的一个整合统称:HTML+CSS+JS(dom)
- XML - 配置文件|数据格式:没有提供过任何预定义标签!全靠自定义
2、使用XML
1、创建xx.xml文件
2、必须写上声明标签:<?xml version="1.0" encoding="utf-8"?> - 必须放在第一行第一列
version - 版本号:目前有的版本只有1.0和1.1,但是1.1升级并不理想,没有人使用,所以1.0可以说是唯一版本,而且你学了以后都不用在学了,以后都不会更新了,因为已经淘汰了,有更棒的人(JSON)
encoding - 编码格式
3、必须写上一个根标签,而且只能写一个根标签,而且必须是双标签
4、里面你随意,你想放什么就放什么
5、恭喜你,学完了
开发中,正常来说后端会想办法将数据库的数据整理为一个xml格式的文件
- 前端:依然使用ajax去获取xml
- 1、路由 写为 "xx.xml"
- 2、xhr.responseText 换成 xhr.responseXML - 可以使用【核心DOM】去操作你需要的东西 - 淘汰的原因,现在来获取数据都要使用核心DOM,太麻烦了
(二)JSON:JavaScript Object Notation:JS对象表示法,本身就是JS的一部分
作用:数据格式 类似于 XML
好处:比XML 更简洁、更快、更容易解析
1、哪些属于JSON字符串:
(1)'[1,2,3,4,5]';
(2)'{"key":value,...}';
(3)'[{},{},{},{}]';
()'{"names":[1,2,3,4],"ages":[1,2,3,4]}'
2、后端把数据库的数据取出来整理为一个JSON字符串:
var jsonTxt=JSON.stringify(jsonObj);
3、前端依然使用ajax去获取响应数据,真正重要的:
xhr.responseText;
将JSON字符串解析为一个JSON对象:那么:2种方法 - 脱衣服
1、eval("("+xhr.responseText+")");
2、*JSON.parse(xhr.responseText);
1、jQueryUI:基于jQuery(基于JavaScript的一个框架,是三大框架出现之前,最火的一个,但是现在已经被淘汰了)的开源网页用户界面代码库 - 提供了HTML、CSS、JS的一个插件库 三大框架:Vue(中国人的框架)、React、Angular(在国内几乎没有市场) 组件库:组件,组成网站一部分的部分,代码重用,一般不具备JS功能:比如导航条、图文显示... 插件库:跟组件差不多,只不过带有JS功能 - 选项卡、轮播...
如何使用插件库:
1、下载jQueryUI - 不需要你们做
2、必须在页面上进行引入: - 顺序不能错,一定要先引入jquery.js再引入jquery-ui.js
<link rel="stylesheet" type="text/css" href="jquery-ui-1.13.2.custom/jquery-ui.css"/>
<script src="jquery-ui-1.13.2.custom/external/jquery/jquery.js" type="text/javascript" charset="utf-8"></script>
<script src="jquery-ui-1.13.2.custom/jquery-ui.js" type="text/javascript" charset="utf-8"></script>
3、挑选出你需要的/喜欢的插件,直接梭到你的项目中
4、根据设计图,来修改样式 - 修改不成功,只有一个可能:权重不够
5、使用ajax去获取数据库中的数据,来进行页面渲染
6、千万别忘了调用jQuery提供的xx方法来实现功能
个人比较推荐的JQUI的插件:
1、选项卡/标签页
2、菜单
3、手风琴/折叠面板
4、模糊查询/自动完成
5、JQ动画/特效
6、交互部分自己试试
二十九、前端框架
使用jQuery简化了核心DOM 必须先引入:
<script src="jquery-ui-1.13.2.custom/external/jquery/jquery.js" type="text/javascript" charset="utf-8"></script>
jQuery中$:
作用:
1、查找元素:$("JQ选择器"); - 包含一切css选择器的,不需要记忆:推荐网址:https://www.w3school.com.cn/jquery/jquery_ref_selectors.asp - 底层就是document.querySelectorAll
2、创建元素:$("<标签></标签>"); - document.createElement
3、可以将DOM转为JQ:$(DOM对象);
4、代替了window.onload - $(callback);面试题:两者的区别?
1、window.onload - 等待所有资源(html、css、其他js、图片、视频、音频。。。)加载完毕才会执行,效率降到了最低,而且一个页面只能写一次
2、$(callback) - 只是等待DOM加载完毕就会执行,性能比window.onload要高,而且一个页面能写多次
底层用到了一个人:重载:arguments - 可以通过判断用户传入的实参的不同执行不同的操作
(一)查找元素:
1、除了直接查找:$("JQ选择器");
2、通过关系查找:至少要先找到一个人才可以使用关系:
父:parent();
子:children();
前一个兄弟:prev();
后一个兄弟:next();
其他兄弟:siblings();
JQ自带隐式迭代,不需要遍历,可以对集合直接做操作
(二)操作元素:
1、内容:
获取:$("xx").html/text/val();
获取:$("xx").html/text/val("新内容");
2、属性:
获取:$("xx").attr("属性名");
设置:$("xx").attr("属性名","属性值");
3、样式:
1、可以操作class:
1、添加class:$("xx").addClass("新class") - JS中没有此操作,只能替换
2、删除class:$("xx").removeClass()
如果不传参,删除所有的class名
如果传入,删除对应的class名
3、切换class:$("xx").toggleClass("新class")
2、直接操作css
获取:$("xx").css("css属性名");
设置:$("xx").css("css属性名","css属性值");
一句话设置多个样式:
$("xx").css({
css属性名:"css属性值",
...
});
(三)JQ的遍历:
$("一堆人").each((i,val)=>{
})
(四)JQ上树&删除:
上树:父亲.append(儿子)
删除:$("xx").remove();
(五)JQ动画:
1、显示 - $("xx").show();
2、隐藏 - $("xx").hide();
3、切换 - $("xx").toggle();
如果不传参数,是瞬间显示,瞬间隐藏
可以传入实参:$("xx").api("动画名称",时长);
-
JQ不可以用以前DOM的语法,DOM也不可以用JQ的语法,但是两者其实可以互换
- JQ->DOM:$("xx")[下标];
- DOM->JQ:$(DOM)
-
jQuery的组成部分:
- 1、jquery.js
- 2、jQueryUI.js
- 3、jQuery-Mobile.js - 但是现在三阶段有uniapp
- 4、QUnit - 测试用来测试JavaScript代码的一个工具
三十、后端框架
Node.js的第三方框架:express,需要使用npm去下载它,express中有两个核心概念
0、下载:在你的项目路径下打开cmd:npm i express
1、引入后发现express是一个函数,创建服务器应用,还要设置监听端口!
var express=require("express");
var app=express();
app.listen(端口号);
2、路由:客户端发来的请求中的一部分,也称呼叫做相对路径,通过判断路由的不同响应不同的内容。
1、app.get("路由",(req,res)=>{//req和res不是以前的req和res,用法会与原生Node有所不同
1、req->依然是请求对象,保存着前端传来的请求消息:req.query.键名;
2、res->依然是响应对象,可以为前端发数据,也可以为前端发页面:
1、发数据:res.send("想要发的东西");
2、发文件:res.sendFile("文件的路径");
})
2、特殊:post请求要稍微麻烦一点点,尤其在于获取前端传到后端的请求消息,因为post是隐式提交,所以需要某些东西才能看得见他
app.post("路由",(req,res)=>{//req和res不是以前的req和res,用法会与原生Node有所不同
1、req->依然是请求对象,保存着前端传来的请求消息:3步
1、需要引入一个第三方模块(中间件的语法):var bp=require("body-parser")
2、使用中间件的语法:app.use(bp.urlencoded({extended:false}))
3、req.body.键名;
2、res->依然是响应对象,可以为前端发数据,也可以为前端发页面:
1、发数据:res.send("想要发的东西");
2、发文件:res.sendFile("文件的路径");
})
现在不管是form表单还是ajax,都可以自行选择使用get还是post了
如果是全栈开发,一个人随便搞,但是如果是前后端分离开发,那么要沟通,路由是什么
3、中间件:express本身就是一个功能极简的框架,完全路由和中间件两部分构成
中间件其实就是一个函数,但是它也可以访问req和res两个对象,处于路由之前 - 可以理解为是现实生活中的一个保安、保镖、秘书
中间件的功能包括:
可以执行任何代码
可以修改请求和响应对象
可以终止请求
可以放行你到下一个中间件/路由 - 中间件可以写多个
语法:
app.use((req,res,resolve)=>{
一切你想要执行的代码,中间件代码
resolve();//放行的函数
})
固定套路:
1、*获取post的请求消息,见上面 - app.use(bp.urlencoded({extended:false}))
2、*内置中间件加载一切静态资源:app.use(express.static("静态资源的文件夹名"));
三十一、gulp
自动化构建工具(打包工具):项目经理/小组长使用的 - 学习目的:体验流程
作用:
*1、复制文件
*2、压缩(css/js/图片...)
*3、降级ES6为ES5,降级语法 - 因为ES5之前语法其实都没有变化,ES5只是提供了一些新的API,目的:支持兼容老IE
4、将scss/less编译为css - 不需要学习,现在的编辑器都自带此功能
5、重命名 - 不推荐,html引入href、src的地方名字都要进行修改
- *为什么打包:
- 上线过后,不可能使用源代码(1、太大了 2、别的成员/外界也能看的懂)
- 肯定使用的是处理过后的代码,目的:1、为了提升网站效率(文件更小) 2、安全性(加密)
- *gulp固定操作安装:
1、cmd必须先全局安装gulp(不安的话,cmd提示:gulp不是内部命令) - 必做(运行gulp必要方式),一次性安装永久可用
npm i --global gulp
2、cmd再你的项目中局部安装 - 可以不做,直接复制代老湿的node_modules到你的项目之中
npm i gulp
3、cmd在你的项目初始化gulp - 必做
npm init
注意:名字可以自己写,但是不能有大写&中文,然后一路回车到底
4、配置完成,开始编写属于你自己的gulpfile.js文件!!!必须是这个名字
使用gulp:
1、先引入var gulp=require("gulp");
API:
1、布置任务:
gulp.task("任务名",()=>{
//任务要做什么操作
})
执行任务:
cmd里面输入gulp 任务名; - gulp基于node,但是属于是一个独立的软件
如果想不写任务名,默认执行default任务名的操作
2、*复制
gulp.src("入口文件路径"); -- 选中某个、某些源文件
gulp.pipe(); -- 管道 -- 输送/插件操作
gulp.dest("出口路径"); -- 输送到哪里去?
三十二、SVN工具(1-):集中式版本管理控制工具
- 作用:项目管理
- 集中式:服务器只有一台电脑,所有人可以把自己完成的工作,传送到服务器上,任何人(客户端)都可以访问
- 缺点:如果服务器坏了就完了
- 优点:没有放在云端,安全性一定是极高的,如果泄露了一定是内鬼,如果项目真的是需要很安全的,你的电脑应该也会装上监控软件
如何使用:
1、项目经理:
1、安装svn服务器端:VisualSVN-Server-4.3.2-x64.msi
2、为此项目组的每个开发者创建出账号密码
3、创建项目仓库
4、把仓库地址和你的账号私发给你
5、承受压力、核算项目周期、核算项目成本、监督项目进度、陪伴加班...
2、开发人员
1、安装svn客户端:TortoiseSVN-1.14.1.29085-x64-svn-1.14.1.msi - 记得重启一下电脑(不重启可能看不到小图标)
2、对着任意位置右键:svn checkout - 检出/拉取仓库,填上仓库地址
3、在文件夹(仓库)里面做开发
4、每天下班前提交到服务器:在项目文件夹里面,写代码的位置,右键svn commit,填入日志,在提交
5、每天上班前更新一下:右键svn update
GIT工具(9+):三阶段学习 - 分布式版本管理控制工具
三十三、websocket - HTML5提供的了一个新特性
(一)HTML5新特性10个:
一、语义化标签
二、新增Input表单的类型、和属性
三、audio、video音频和视频
四、Canvas绘图
五、SVG绘图 - 因为程序员大部分都不会画画,就算学会了,画出来也很丑,而现在有框架echart.js,可以帮助你实现画图功能(数据可视化 - 折线图、柱状图、饼状图...)
六、地理定位
七、拖拽API
八、WebStorage - sessionStorage和localStorage
九、WebWorker - 没用
十、WebSocket
(二)websocket的概念
http协议 属于请求-响应模型,只有客户端发起请求,服务器端才能响应消息,没有请求就没有响应,
一个请求,只能得到一个响应,有些场景中,此模型就不太行了:比如:实施走势图、在线聊天室等等...
解决:
1、ajax+定时器 - 请求过于复杂了,服务器的压力太大,而且不够频繁(心跳请求、长轮询)
2、websocket协议:简称ws协议:属于广播-收听模型,客户端连接到服务器端就不会再断开了,永久连接的,
双方可以随意的向对方发送消息,且是不对等的发送,WS协议专门用于完成实施走势图、在线聊天室等等...
(三)如何使用ws:
1、基于Node.js的第三方模块包,下载引入: var ws=require("ws");
2、分为三方面:
1、依然使用node.js搭建http服务器和文件系统 - 可以用express简化
2、搭建ws服务器
//搭建ws服务器并且设置了监听端口号
var server=new ws.Server({port:8008});
//绑定了连接事件,是不自己断开的,可向客户端发送消息,或者,接收消息
server.on("connection",socket=>{
console.log("11111---有人来连接上了");
//后端->前端
socket.send("消息")
//前端->后端
socket.on("message",data=>{
data->前端说的话,只不过是一个buffer类型
})
})
3、搭建ws客户端
//连接到ws服务器端
var socket=new WebSocket("ws:127.0.0.1:8008");
//前端想要接收消息
socket.onmessage=e=>{
e.data;
}
//前端说话:
socket.send("消息");
三十四、各大版本更新
(一)ES5:
1、保护对象:
(1)6大特性
Object.defineProperties(obj,{
"属性名":{
value:,
writable:true/false,
enumerable:true/false,
configurable:true,false
get:()=>{
拦截操作
},
set:()=>{
拦截操作
}
}
})
2、3个级别
防扩展:Object.preventExtensions(obj);
密封:Object.seal(obj);
冻结:Object.freeze(obj);
(2)数组新增的六个API:
判断:arr.every/some((v,i,arr)=>判断条件)
遍历:arr.forEach((v,i,arr)=>操作) var newArr=arr.map((v,i,arr)=>操作)
过滤和汇总
var subArr=arr.filter((v,i,arr)=>判断条件)
var sum=arr.reduce((prev,v,i,arr)=>prev+v);
(3)call、apply-借用
语法:
Array.prototype.slice.call(借用的人,实参1,....)
Array.prototype.slice.apply(借用的人,arr)
bind-买
语法:
var 新的slice=Array.prototype.slice.bind(指定的人,永久实参1)
(4)严格模式:"use strict"
(二)ES6:超级大版本:
1、模板字符串:${name}
2、let 变量名=值;
3、箭头函数
4、for(var v of arr){ v - 值 }
5、解构赋值 new Vue({}) - 很多框架底层都用到了解构赋值
6、Set和Map [...new Set(arr)] - 数组去重变回数组
7、class关键字 - 简化面向对象的三大特点:封装、继承、多态
class plane extends flyer{//extends有两个作用:1、继承自有属性全部都不用再写,只需要写一次super(),2、自动继承到共有方法
constructor(name,speed,rl){//放在constructor里面的都是自有属性
super(name,speed);
this.rl=rl;
}
fly(){//flyer提供的fly方法不好用,我自己封装了一个,覆盖他的 - 多态
return `${this.name}正在以时速${this.speed}飞行,可以容纳${this.rl}人`;
}
}
8、Promise - 让异步有顺序的执行,但是还是异步
new Promise(ajax1).then(ajax2).then(ajax3);
一定要放行,且前一个return Promise才可以连.then操作
9、模块化开发 - 目的:1、分工合作 2、新的引入方式
语法
1、分支模块要公开自己的成员
export var obj={
...
}
2、主模块要引入:
import {obj} from "./文件路径"
3、HTML在引入主模块的时候要注意设置类型:
<script src="主模块路径" type="module"></script>
(三)ES7:
1、ArrayAPI:includes
在ES7之前,如果我们想要判断一个数组中是否包含某个元素,需要通过 indexOf 获取结果,并且判断是否为-1
在ES7之后,我们可以通过includes来判断数组中是否包含一个指定元素,得到结果直接就是一个布尔值
var arr=[1,2,3,4,5];
//原来
console.log(arr.indexOf(6)!=-1);
//现在
console.log(arr.includes(3))
console.log(arr.includes(6))
2、指数运算符:
在ES7之前,如果我们想要计算数字的乘方,必须通过 Math.pow(底数,幂);
在ES7之后,增加了 ** 运算符 ,可以对数字进行乘方操作
Math.pow(2,3) -> 8
2**3 -> 8
(四)ES8:
1、Object.values
作用:可以将一个对象转为数组
之前我们可以通过 Object.keys 获取一个对象所有的key
可以针对对象操作:
var obj={
name:"袍哥",
age:18,
hobby:"学习"
}
console.log(Object.keys(obj));//["name","age","hobby"];
// 在ES8中提供了 Object.values 获取一个对象所有的value
console.log(Object.values(obj));//["袍哥",18,"学习"];
2、Object.entries
作用:将对象、数组、字符串 变为 二维数组
通过 Object.entries 可以获取到一个数组,数组中会存放可枚举属性的键值对数组
console.log(Object.entries(obj));//[["name","袍哥"],["age",18],["hobby","学习"]]
也可以针对数组、字符串进行操作,数组和字符串会将下标作为key
*3、StringPadding
某些字符传我们需要对其进行前后的填充,来实现某种格式化操作,ES8之中就给字符串添加padStart和padEnd方法,分别填充前面和后面
//日期格式化,为个位数,前面添加了一个0
var h="8";
var m="3";
var s="50";
console.log(`${h.padStart(2,"0")}:${m.padStart(2,"0")}:${s.padStart(2,"0")}`)
4、尾部逗号的添加,不会报错了
5、async 和 await *****
async作为一个关键字放到函数前面,用于表示函数是一个异步函数,异步函数也就意味着该函数不会阻塞后续代码
async function f1(){
return "我是f1函数";
}
f1().then(rs=>{
console.log(rs);
console.log("得到结果要干什么就在这里操作")
});
console.log("后续代码");
意味着任何函数都可以变为异步
await是等待的意思,那么他等待的是什么呢,他后面又该跟着什么呢?其实它后面可以放任何表达式,不过我们更多的是放一个返回Promise对象的表达式
注意:await 关键字只能放在async函数里面
async function f1(){
return 1;
}
async function f2(){
return 2;
}
async function f3(){
return await f1() + await f2();
}
f3().then(rs=>{
console.log(rs);
});
console.log("后续代码");
(五)ES9:
*扩展运算符:...
,ES9过后不光数组,对象也可以使用了
//脱掉数组的衣服
var arr=[32,1,54,76,98,7,23,54,24,764];
console.log(Math.max.apply(Math,arr));
console.log(Math.max(...arr));
//脱掉对象的衣服
var obj1={a:1,b:2,c:3}
var obj2={...obj1,d:4}
console.log(obj2);
//c穿上了对象的衣服
function f1({a,...c}){
console.log(a);
console.log(c);
}
f1({a:1,b:2,c:3})
(六)ES10:
1、flat方法会按照一个可指定的深度遍历递归你的数组,并将所有的元素与遍历到的子数组中的元素合并为一个新数组
var arr=[1,[2,[3,[4,[5,6,7,8,9]]]]]
console.log(arr.flat(4));//[1,2,3,4,5,6,7,8,9]
2、flatMap:两个方法二合一flat和map,先执行map在执行flat,但是flat只能脱1层
var arr=["hello world","你好 中国","hello h52301"];
var newArr=arr.flatMap(v=>v.split(" "));
console.log(newArr);//["hello","world","你好","中国","hello","h52301"];
3、trimStart/trimEnd
(七)ES11:
全局对象全新写法:
- 在浏览器中可以通过window访问全局对象
- 在Node.js中可以通过global来访问对象
- 在ES11中对全局对象添加了一个新的名字,统一了规范:globalThis
for...in循环标准化
在ES11之前,虽然很多浏览器支持for...in来遍历对象,但是并没有被ECMA标准化
(八)ES12:
逻辑赋值运算符
function f1(a){
a||="默认值";
console.log(a);
}
f1();//a=默认值
var obj={
name:"袍哥"
}
obj&&=obj.name;
console.log(obj);//袍哥
(九)ES13:
字符串、数组API:at();
可以通过at方法获取字符串、数组的元素
var arr=[1,2,3,4,5,6];
console.log(arr.at(0));
console.log(arr.at(2));
console.log(arr.at(-1));
console.log(arr[arr.length-1])
var str="hello world";
console.log(str[str.length-3])
console.log(str.at(-3))