JavaScript第10天
回顾
- 操作元素的样式
-
设置
元素.style.样式名 = 样式值 -
获取
- 行内样式的获取
元素.style.样式名 - 非行内样式的获取
window.getComputedStyle(元素)[样式]
- 行内样式的获取
- 操作元素的属性
-
原生属性
- 获取
元素.属性名 - 设置
元素.属性名 = 属性值
- 获取
-
自定义属性
- 获取
元素.getAttribute("属性名") - 设置
元素.setAttribute("属性名","属性值") - 删除
元素.removeAttribute("属性名","属性值")
- 获取
-
H5自定义属性
- 获取
元素.dataset.属性名 - 设置
元素.dataset.属性名 = 属性值 - 删除
delete 元素.dataset.属性名注意: 以后不推荐使用驼峰命名,原因会将多个单词首先字母变小写,然后使用-隔开
- 获取
- 操作元素的类名
-
className
- 获取
元素.className - 设置
元素.className = 类名 - 追加
元素.className += ' 类名'
- 获取
-
classList
- 添加
元素.classList.add() - 删除
元素.classList.remove() - 切换
元素.classList.toggle()
- 添加
- 同步异步 JS的事件轮询,JS里面的异步代码(ajax,定时器,DOM回调)
- 排他思想 先把公共的事情给处理,然后再单独处理自己的事情
知识点
- 省市级联动
案例
<!--
省市级联动
-->
<select id="province">
<option value="请选择">请选择</option>
</select>
<select id="city">
<option value="请选择">请选择</option>
</select>
<script>
//1. 模拟数据
var proList = ["贵州","湖南","湖北"]
var citList = [
["贵阳","遵义","毕节","六盘水"],
["长沙","株洲","常德","怀化"],
["武汉","襄阳","恩施"]
]
/*
思路:
1. 先获取province和city
2. 遍历省份,获取所有的省份
3. 将省份渲染到第一个下拉框
*/
// 1. 先获取province和city
var pro = document.querySelector("#province")
var cit = document.querySelector("#city")
// 2. 遍历省份,获取所有的省份
proList.forEach(function(item,index){
// console.log(item,index);
var str = `<option value=${index}>${item}</option>`
// 3. 将省份渲染到第一个下拉框
pro.innerHTML += str;
})
// 3. 给省份绑定change事件
pro.onchange = function(){
//在渲染之前需要先清空城市下拉框列表
cit.innerHTML = "<option>请选择</option>"
//this.value
citList[this.value].forEach(function(item,index){
var str = `<option value=${index}>${item}</option>`
cit.innerHTML += str;
})
}
</script>
获取元素的尺寸
- 获取元素的尺寸
-
offset
- 语法:
元素.offsetWidth和元素.offsetHeight - 特点: 获取的是元素的内容+内边距+边框, 注意:如果元素被隐藏了,那么就获取不到
- 语法:
-
client
- 语法:
元素.clientWidth和元素.clientHeight - 特点: 获取的是元素的内容+内边距,注意:如果元素被隐藏了,那么就获取不到
- 语法:
比如
*{
margin: 0;
padding:0;
}
div{
width: 100px;
height: 100px;
background-color: springgreen;
padding: 20px;
border: 10px solid red;
margin: 30px;
display: none;
}
<div></div>
//获取盒子的尺寸
//如果盒子被隐藏了,那么就获取不到
// offset => 元素.offsetHeight和offsetWidth => 获取的是元素的内容+内边距+边框
var box = document.querySelector("div")
console.log(box.offsetWidth,box.offsetHeight);
//client => 元素.clientHeight和元素.clientWidth => 获取的是元素的内容+内边距
console.log(box.clientHeight,box.clientWidth);
- 获取元素的偏移量
-
offset
- 语法:
元素.offsetTop和元素.offsetLeft - 特点: 其实就是求坐标,如果该元素的父级有定位,那么坐标的参考点就是父元素,如果父级没有定位,那么参考点就是浏览器的左上角
- 语法:
-
client
- 语法:
元素.clientTop和元素.clientLeft - 特定: 其实就是获取该元素的上边框和左边框
- 语法:
比如
*{
margin: 0;
padding: 0;
}
div{
width: 200px;
height: 200px;
background-color: springgreen;
margin: 150px;
position: absolute;
top: 30px;
left: 30px;
}
p{
width: 100px;
height: 100px;
background-color: pink;
border: 20px solid red;
}
<div>
<p></p>
</div>
//语法: 元素.offsetTop和元素.offsetLeft,其实看该元素的父级,如果父级有定位,那么参考点就是父级,如果父级没有定位,那么参考点就是浏览器的左上角
var p = document.querySelector("p")
var div = document.querySelector("div")
//父级没有定位,那么坐标的参考点就是浏览器的左上角,如果父元素有定位,那么参考点就是父元素
console.log(p.offsetTop,p.offsetLeft);
//其实就是获取的是该盒子的上边框和左边框
console.log(p.clientTop,p.clientLeft);
- 获取可视窗口大小
- BOM级别
window.innerWidth和window.innerHeight=> 获取的当前浏览器的可视窗口大小,包括滚动条 - DOM级别
document.documentElement.clientHeight=> 获取的当前浏览器的可视窗口大小,不包括滚动条document.documentElement.clientWidth=> 获取的当前浏览器的可视窗口大小,不包括滚动条
比如
*{
margin: 0;
padding: 0;
}
body{
height: 4000px;
width: 4000px;
}
/*
获取的是可视窗口的大小
document.documentElement.clientHeight
document.documentElement.clientWidth
*/
//BOM级别
console.log(window.innerHeight,window.innerWidth);
//DOM级别
console.log(document.documentElement.clientHeight);
console.log(document.documentElement.clientWidth);
JavaScript第11天
回顾
- 获取元素的尺寸
- offset =>
元素.offsetWidth和元素.offsetHeight获取元素的内容+内边距+边框 - client =>
元素.clientWidth和元素.clientHeight获取元素的内容+内边距
- 获取元素的偏移量
- offset =>
元素.offsetTop和元素.offsetLeft如果元素的父级有定位,那么的坐标的参照物是父级,如果父级没有定位,那么坐标的参照物的是浏览器的左上角 - client =>
元素.clientTop和元素.clientLeft其实就是求的元素的上边框和左边边框的距离
- 获取元素的可视窗口
- BOM =>
window.innerWidth和window.innerHeight(注意:宽高包含滚动的距离) - DOM =>
document.documentElement.clientWidth和document.documentElement.clientHeight(注意:不包括滚动条的距离)
知识点
DOM节点
- 获取DOM节点
-
获取非常规节点
- HTML =>
document.documentElement - BODY =>
document.body - HEAD =>
document.head
- HTML =>
比如
<!--
DOM树
1. 获取DOM元素
获取非常规节点 =>
HTML => document.documentElement
BODY => document.body
HEAD => document.head
-->
<script>
//获取HTML
console.log(document.documentElement);
//获取head
console.log(document.head);
//获取body
console.log(document.body);
</script>
-
获取常规节点
- ID 直接写
- document.querySelector
- document.querySelectorAll
- document.getElementById
- document.getElementsByClassName
- document.getElementsByTagName
DOM节点直接的关系
| 节点 | 文本节点 | 注释节点 | 元素节点 | 属性节点 |
|---|---|---|---|---|
| nodeType | 3 | 8 | 1 | 2 |
| nodeName | #text | #comment | 标签名大写 | 属性名 |
| nodeValue | 节点文本值 | 节点文本值 | null | 属性值 |
- DOM节点一般由四点组成
比如
<!-- 这是一个div -->
<div id="i1" class="c1">我是div</div>
注释节点 => 指的就是对HTML注释
元素节点 => 指的就是HTML的标签
属性节点 => 指的就是标签身上的属性
文本节点 => 指就是标签的文本描述
- 节点之间的关系
-
兄弟关系
- 哥哥节点 =>
元素.previousSibling - 哥哥元素节点 =>
元素. previousElementSibling - 弟弟节点 =>
元素.nextSibling - 弟弟元素节点 =>
元素.nextElementSibling
- 哥哥节点 =>
-
父子关系
- 获取元素的父节点 =>
元素.parentNode - 获取元素的父元素节点 =>
元素.parentElement - 获取第一个儿子节点 =>
元素.firstChild - 获取第一个儿子元素节点 =>
元素.firstElementChild - 获取最后一个儿子节点 =>
元素.lastChild - 获取最后一个儿子元素节点 =>
元素.lastElementChild - 获取所有的子节点 =>
元素.childNodes - 获取所有的子元素节点 =>
元素.children
- 获取元素的父节点 =>
-
属性
- 获取元素的属性 =>
元素.attributes
- 获取元素的属性 =>
比如
<!--
文本节点 注释节点 元素节点 属性节点
nodeName #text #comment 标签名大写 属性名
nodeType 3 8 1 2
nodeValue 文本值 文本值 null 属性值
-->
<ul id="u1" class="c1">
<!-- 这是第一个div标签 -->
<li>1</li>
<li>2</li>
<!-- 这是一个li3的标签 -->
<li>3</li>
<li>4</li>
</ul>
<script>
/*
父子关系
兄弟关系
*/
var ul = document.querySelector("ul")
var li2 = document.querySelector("li:nth-child(2)")
//兄弟关系
//获取li2的哥哥节点
console.log(li2.previousSibling);//是一个空格,nodeName是 #text => 就是一个文本节点
//获取li2的哥哥元素节点
console.log(li2.previousElementSibling); //第一个li标签
//获取li2的弟弟节点
console.log(li2.nextSibling);
//获取li2的弟弟元素节点
console.log(li2.nextElementSibling);
//父子关系
//获取ul的第一个儿子节点
console.log(ul.firstChild);
//获取ul的第一个元素节点
console.log(ul.firstElementChild);
//获取ul的最后一个儿子节点
console.log(ul.lastChild);
//获取ul的最后一个儿子元素
console.log(ul.lastElementChild);
//获取所有的儿子节点
console.log(ul.childNodes);
//获取所有的儿子元素节点
console.log(ul.children);
//获取属性节点
console.log(ul.attributes);
</script>
创建节点
- 创建文本节点 =>
document.createTextNode - 创建元素节点 =>
document.createElement
比如
/*
创建文本节点
document.createTextNode
创建元素节点
document.createElement
*/
//创建文本节点
var text = document.createTextNode("👲🏼")
console.log(text);
//创建元素节点
var li = document.createElement("li")
//给文本节点添加内容
li.innerHTML = "👲🏼"
console.log(li);
添加节点
- 追加节点 => 父节点.appendChild(子节点)
- 插入节点 => 父节点.insertBefore(插队的,已存在)
比如
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
<script>
//获取ul
var ul = document.querySelector("ul")
//创建节点
var li = document.createElement("li")
li.innerHTML = "我是新成员"
//追加节点 => 将子节点追加到父节点的末尾
ul.appendChild(li)
//插入节点 => 插队
var newLi = document.createElement("li")
newLi.innerHTML = "我是插队的"
//获取第二个元素节点
var li2 = document.querySelector("li:nth-child(2)")
//插入节点 爹.insertBefore("插队的","已经存在的儿子")
ul.insertBefore(newLi,li2)
</script>
删除节点
- 删除节点 => 删除儿子 => 父节点.removeChild(子节点)
- 删除节点 => 删除自己 => 节点.remove();
比如
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
<script>
//删除节点
var ul= document.querySelector("ul")
// 获取第二个儿子
var li2 = document.querySelector("ul>li:nth-child(2)")
//删除第二个儿子
ul.removeChild(li2)
//删除ul
ul.remove();
//删除body
document.body.remove();
//删除head
document.head.remove();
//删除html
document.documentElement.remove();
</script>
替换节点
替换节点 => replaceChild
比如
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
<script>
//获取ul和li2
var ul = document.querySelector("ul")
var li2 = document.querySelector("ul>li:nth-child(2)")
//创建一个节点
var newLi = document.createElement("li")
newLi.innerHTML = "新来的"
//替换节点 => 父节点.replaceChild("换上节点","换下节点")
ul.replaceChild(newLi,li2)
</script>
克隆节点
克隆节点 => cloneNode(bool类型)
比如
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
<script>
//获取ul
var ul = document.querySelector("ul")
//将ul克隆一份,cloneNode(bool),如果bool为true,表示克隆子节点,如果bool为false,表示不克隆子节点,默认为false
console.log(ul.cloneNode());//不克隆子节点
console.log(ul.cloneNode(false));//不克隆子节点
console.log(ul.cloneNode(true));//克隆子节点
</script>
DOM与字符串的效率问题
比如
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<script>
var ul = document.querySelector("ul")
//在没有添加之前的时间的毫秒值
var t1 = +new Date();
//连续追加10000个
for (var i = 0; i < 10000; i++) {
//使用DOM的方式给ul添加10000个儿子
var li = document.createElement("li")
li.innerHTML = "儿子"
ul.appendChild(li)
}
// for(var i = 0 ; i < 1000 ; i++){
// var li = "<li>儿子</li>"
// ul.innerHTML += li;
// }
//添加完毕之后的毫秒值
var t2 = +new Date();
console.log(t2 - t1);
</script>
事件
事件就是我们程序员和浏览器已经约定好的一个行为,当我们触发某一个事件的时候,浏览器会出现一个特定行为
- 事件三要素
- 事件源 => 触发事件的源头
- 事件类型 => 触发事件行为的类型
- 事件处理函数 => 触发事件后所执行的函数
- 鼠标事件
比如
//click 点击事件
box.onclick = function(){console.log("点击事件");}
//dblclick 双击事件
box.ondblclick = function(){console.log("双击事件");}
//contextmenu 鼠标右边事件
box.oncontextmenu = function(){console.log("鼠标右键事件");}
//mousedown鼠标按下事件
box.onmousedown = function(){console.log("鼠标按下事件");}
//mouseup鼠标抬起事件
box.onmouseup = function(){console.log("鼠标抬起事件");}
//mousemove鼠标移动事件
box.onmousemove = function(){console.log("鼠标移动事件");}
//mouseout鼠标离开事件
box.onmouseout = function(){console.log("鼠标离开事件");}
//mouseover鼠标移入事件
box.onmouseover = function(){console.log("鼠标移入事件");}
//mouseleave鼠标离开事件
box.onmouseleave = function(){console.log("鼠标离开事件");}
//mouseenter鼠标移入事件
box.onmouseenter = function(){console.log("鼠标移入事件");}
- 键盘事件
比如
/*
两个按下事件的区别
识别功能(keydown认识功能键,onkeypress不认识功能键)
*/
//键盘按下事件
document.onkeydown = function(){console.log("键盘按下~keydown");}
//键盘按下事件
document.onkeypress = function(){console.log("键盘按下~keypress");}
//键盘抬起事件
document.onkeyup = function(){console.log("键盘抬起~keyup");}
- 表单事件
比如
//重置事件
form.onreset = function(){console.log("重置表单触发的事件");}
//提交事件
form.onsubmit = function(){console.log("提交表单触发的事件");}
//获取焦点事件
inp.onfocus = function(){console.log("获取焦点触发的事件");}
//失去焦点触发的事件
inp.onblur = function(){console.log("失去焦点触发的事件");}
//输入事件
inp.oninput = function(){console.log("输入事件");}
//改变事件
/* input事件就是当input里面的文本框一旦发生改变的时候,触发
change事件 1. 失去焦点,2,文本改变
*/
inp.onchange = function(){console.log("change改变事件");}
- 触摸事件
比如
//开始触摸
box.ontouchstart = function(){console.log("触摸开始");}
//触摸移动
box.ontouchmove = function(){console.log("触摸移动");}
//触摸结束
box.ontouchend = function(){console.log("触摸结束");}
JavaScript第12天
回顾
- 获取DOM的方式
-
常规获取DOM
- ID可以直接写
- document.getElementById
- document.getElementsByClassName
- document.getElementsByTagName
- document.querySelector
- document.querySelectorAll
-
非常规获取DOM
- html => document.documentElement
- body => document.body
- head => document.head
- 节点之间的关系
-
兄弟关系
- previousSibling
- proviousElementSibling
- nextSibling
- nextElementSibling
-
父子关系
- childNodes
- chilren
- firstChild
- firstElementChild
- lastChild
- lastELementChild
- parentNode
- parentElement
-
属性
- attributes
-
创建节点
- document.createElement
- document.createTextNode
-
追加节点
- 父.appendChild(子)
- 父.insertBefore(新,原)
-
删除
- 父.removeChild(子)
- 父.remove()
-
替换
- 父.replaceChild(新,原)
-
克隆
- 节点.cloneNode(bool)
- 节点的分类
| 节点 | 元素节点 | 属性节点 | 文本节点 | 注释节点 |
|---|---|---|---|---|
| nodeType | 1 | 2 | 3 | 8 |
| nodeName | 标签名大写 | 属性名 | #text | #comment |
| nodeValue | null | 属性值 | 文本节点值 | 注释的文本值 |
- 事件
-
鼠标事件
- click
- dblclick
- contextmenu
- mousedown
- mouseup
- mousemove
- mouseleave 支持事件的捕获
- mouseenter
- mouseout 支持事件的冒泡
- mouseover
-
键盘事件
- keydown 可以识别功能(shift,alt,ctrl)
- keypress
- keyup
-
表单事件
- reset
- submit
- blur
- focus
- change
- input
-
触摸事件
- touchstart
- touchmove
- touchend
知识点
事件
- 其他事件
比如
//选中事件 selectstart
document.onselectstart = function(){
alert("我不要让你选中,我要你冲会员才可以选中")
return;
}
//标签的切换事件
document.onvisibilitychange = function(){
//document.visibilityState == 'hidden' 隐藏当前页面
if(document.visibilityState == 'hidden'){
console.log("当前这个页面看不见了");
}
//document.visibilityState == 'visible' 显示当前页面
if(document.visibilityState == 'visible'){
console.log("又回到这个页面了");
}
}
- 事件的绑定 DOM0绑定事件 => 元素.on事件类型 = fn DOM2绑定事件 => 元素.addEventListener("事件类型",fn)
比如
/*
绑定事件的方式 DOM0
元素.on事件类型 = xxx
只能绑定一个事件
*/
//给div这个盒子绑定一个事件
var box = document.querySelector("div")
//绑定事件
box.onclick = function(){
console.log("绑定完毕之后触发这个事件");
}
//他下面的点击事件将上面的点击事件给覆盖了
box.onclick = function(){
console.log("我又绑定另外一个事件");
}
/*
绑定事件的另外一种方式 DOM2
元素.addEventListener("事件类型",事件函数)
相同的事件类型可以绑定一个函数
*/
var btn = document.querySelector("button")
btn.addEventListener("click",function(){
console.log("DOM2绑定第一个事件");
})
btn.addEventListener("click",function(){
console.log("DOM2绑定第二个事件");
})
- 事件的解绑 DOM0 => 元素.on事件类型 = null DOM2 => 元素.removeEventListener("事件类型",解绑的函数)
比如
<button id="btn1">绑定函数</button>
<button id="btn2">解绑</button>
<script>
//语法
// DOM0 => 元素.on事件类型 = null<br>
// DOM2 => 元素.removeEventListener("事件类型",解绑的函数)
btn1.onclick = function(){
console.log("你好");
}
btn2.onclick = function(){
//给btn1这个按钮解绑
btn1.onclick = null;
}
btn1.addEventListener("click",fn) //DOM2的方式绑定fn函数
btn1.addEventListener("click",fn1) //DOM2的方式绑定fn1的函数
btn2.addEventListener("click",function(){
//给btn1解绑
btn1.removeEventListener("click",fn)
})
function fn(){
console.log("我好");
}
function fn1(){
console.log("大家好");
}
- 事件的综合练习
比如
<form action="##">
<label>账号: <input type="text" placeholder="请输入账号" id="username"></label><span id="usernamespan"></span><br>
<label>密码: <input type="password" placeholder="请输入密码"></label><br>
<input type="submit" value="登录">
</form>
<script>
/*
1. 先处理颜色
当账号获取焦点的时候,改变文本框的背景颜色,当失去焦点的时候,清除背景颜色
在输入内容的时候,如果内容的范围在6~16位之间,那么为合法的内容,否则不合法
*/
var username = document.getElementById("username")
//当获取焦点的时候有一个背景颜色
username.onfocus = function(){
this.style.backgroundColor = "springgreen"
}
//当失去焦点的时候,没有背景颜色了
username.onblur = function(){
this.style.backgroundColor = ""
}
//输入范围在6~16位之间,那么为合法的内容
username.oninput = function(){
//获取文本框里面的内容,如果文本框的内容的长度不合法,在文本框的后面给一个文本提示
if(this.value.trim().length >= 6 && this.value.trim().length <= 16){
//合法
usernamespan.innerHTML = "当前账号可用"
usernamespan.style.color = "green"
}else{
//不合法
usernamespan.innerHTML = "当前账号不可用"
usernamespan.style.color = "red"
}
}
</script>
事件对象
- 认识事件对象 事件对象就是我们在触发某一个事件的时候,浏览器主动的将该次事件一些所需要的内容给存储来,叫做event可以简写成e 比如: e.pageX,e.pageY e.offsetX,e.offsetY e.clientX,e.clientY ... ... 兼容性的写法 : e = e || window.event 事件是在函数的第一个参数
比如
<button>按钮</button>
<script>
var btn = document.querySelector("button")
//事件对象在函数的里面的第一个参数,是浏览器主动的记录本次事件一些相关内容
//简写成e
btn.onclick = function(e){
//兼容性的写法
e = e || window.event;
//e.pageX,e.offsetX,e.clientX;
console.log(e);
}
</script>
- 事件对象的属性
- pageX,pageY => 坐标,参照物是页面
- offsetX,offsetY => 坐标 => 参照物是盒子
- clientX,clientY => 坐标 => 参照物是浏览器的左上角
- 回顾
-
offset
- offsetTop,offsetLeft => 看定位,如果父级有定位,那么他的参照物父级,如果父级没有定位,那么他的参照物的浏览器的左上角
- offsetWidth,offsetHeight => 求盒子自身的宽度和高度(内容+内边距+边框)
- offsetX,offsetY
-
client
- clientTop,clientLeft => 求盒子的上边框,求盒子的左边框
- clientWidth,clientHeight => 求盒子自身宽度和高度(内容+内边距)
- clientX,clieentY
-
pageX,pageY
- 练习一
比如
//鼠标在页面随机移动,将坐标输出在网页的p标签身上
<p></p>
<script>
var p = document.querySelector("p")
//让鼠标和页面上进行移动
document.onmousemove = function(e){
//兼容性写法
e = e || window.event
//获取鼠标在页面当中移动的坐标
var X = e.pageX;
var Y = e.pageY;
var X = e.offsetX;
var Y = e.offsetY;
var X = e.clientX;
var Y = e.clientY;
p.innerHTML = `X轴${X}~~Y轴${Y}`
}
</script>
- 练习二
比如
* {
margin: 0;
padding: 0;
}
div {
width: 100px;
height: 100px;
background-color: springgreen;
/* 如果你想要让这个盒子移动起来,那么需要给盒子加几定位 */
position: relative;
top: 0;
left: 0;
}
<div></div>
<script>
/*
需要
当鼠标在移动的时候,盒子需要跟随鼠标的进行移动
思路
1. 先获取鼠标的坐标 => pageX,pageY
2. 将盒子的top值和left值与pageX和pageY设置成一样的
*/
var box = document.querySelector("div")
document.onmousemove = function (e) {
e = e || window.event
//获取盒子的坐标
var X = e.pageX;
var Y = e.pageY;
//将鼠标的坐标的X轴赋值给盒子的left,将鼠标的Y轴赋值给盒子的top
box.style.top = Y - box.offsetHeight / 2 + "px"
box.style.left = X - box.offsetWidth / 2 + "px"
}
</script>
- 练习二
贵阳社保局
*{
margin: 0;
padding: 0;
}
div{
width: 100px;
height: 100px;
background-color: springgreen;
position: relative;
top: 0;
left: 0;
}
<div></div>
<script>
var box = document.querySelector("div")
function fn(){
//5表示一次移动5px
var step = 5;
//表示移动的路程
var sum = 0;
//先让盒子往右边进行移动,一次移动5px
setInterval(function(){
//进入到定时器里面,移动5px
sum += step;
/*
思路:
如果盒子超过了移动的范围,那么盒子应该往回走
合法的范围: document.documentElement.clientWidth - box.offsetWidth
if(sum > document.documentElement.clientWidth - box.offsetWidth){
sum = document.documentElement.clientWidth - box.offsetWidth
//并且还要往回走
step = -5;
}
*/
if(sum > document.documentElement.clientWidth - box.offsetWidth){
sum = document.documentElement.clientWidth - box.offsetWidth
//往回走
step = -5;
}
//如果盒子的移动的距离小于0了,那么step=5;并且sum = 0;
if(sum < 0){
sum = 0;
//并且盒子 step = 5;
step = 5;
}
box.style.left = sum + 'px'
},1)
}
fn();
</script>
阻止表单提交事件
比如
<!--
阻止表单默认提交事件
1. 在表单当中写一个 onsubmit="return false"
2. 在提交事件当中写一个 return false;
3. 使用事件对象 e.preventDefault();
-->
<!-- <form action="http://1000phone.com" onsubmit="return false"> -->
<form action="http://1000phone.com">
<label>账号: <input type="text" placeholder="账号"></label><br>
<label>密码: <input type="text" placeholder="密码"></label><br>
<input type="submit" value="登录">
</form>
<script>
var form = document.querySelector("form")
form.onsubmit = function(e){
// e.preventDefault();
// return false;
}
</script>
事件的触发机制
- 事件的触发机制 当某一个元素触发一个事件之后,他会将这个事件传递和相关的元素 如果是从爷爷传递给儿子 => 事件的捕获 如果是儿子传递给爷爷 => 事件的冒泡
- 事件捕获
- 事件源
- 事件的冒泡
比如
/*
使用DOM2的方式模拟事件的传递机制
*/
//事件的捕获
window.addEventListener("click", function () { console.log("window"); }, true)
document.addEventListener("click", function () { console.log("document"); }, true)
document.documentElement.addEventListener("click", function () { console.log("html"); }, true)
document.body.addEventListener("click", function () { console.log("body"); }, true)
document.querySelector("ul").addEventListener("click", function () { console.log("ul"); }, true)
document.querySelector("li").addEventListener("click", function () { console.log("li"); }, true)
//事件的冒泡
window.addEventListener("click", function () { console.log("window"); }, false)
document.addEventListener("click", function () { console.log("document"); }, false)
document.documentElement.addEventListener("click", function () { console.log("html"); }, false)
document.body.addEventListener("click", function () { console.log("body"); }, false)
document.querySelector("ul").addEventListener("click", function () { console.log("ul"); }, false)
document.querySelector("li").addEventListener("click", function () { console.log("li"); }, false)
- 阻止事件的冒泡 阻止事件的冒泡就是当儿子触发某一个事件的时候,不想外部进行传递 语法: 直接使用事件对象 => e.stopPropagation();
比如
<div class="outer">
<div class="content">
<div class="inner"></div>
</div>
</div>
<script>
var out = document.querySelector(".outer")
var con = document.querySelector(".content")
var inn = document.querySelector(".inner")
out.addEventListener("click",function(e){
console.log("我是爷爷");
},false)
con.addEventListener("click",function(e){
//阻止事件的冒泡
e.stopPropagation();
console.log("我是爹爹");
},false)
inn.addEventListener("click",function(e){
e.stopPropagation();
console.log("我是儿子");
},false)
</script>
事件的委托(事件的委派)
事件委派的原理: 就是事件的冒泡
- e.target => 事件的目标对象
比如
<button>给ul的末尾添加li,内容随便</button>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
<script>
/*
使用事件的委派
不需要给每一个li都绑定一个点击事件,只需要给ul这个爹绑定一个点击事件即可,利用事件冒泡进行将事件外传
事件对象.target => 目标 => 触发事件的目标对象
*/
var ul = document.querySelector("ul")
var btn = document.querySelector("button")
btn.onclick = function(){
var li = document.createElement("li")
li.innerHTML = "随便"
ul.appendChild(li);
}
ul.onclick = function(e){
//排他思想
var lis = this.children;
console.log(lis);
//触发事件的目标对象
for(var i = 0 ; i < lis.length ; i++){
lis[i].style.backgroundColor = ""
}
e.target.style.backgroundColor = "red"
}
</script>
JavaScript第13天
回顾
- 其他事件类型
-
selectstart
-
visibilitychange
- visible => 进入当前页面的状态
- hidden => 离开当前页面
- 事件的绑定和解绑
-
DOM0 => 只能同一个事件类型绑定一个函数
- 绑定 => 元素.on事件类型 = function(){}
- 解绑 => 元素.on事件类型 = null;
-
DOM2 => 可以给同一个事件绑定多个函数
- 绑定 => 元素.addEventListener("事件类型",事件函数)
- 解绑 => 元素.removeEventListener("事件类型",事件函数)
- 事件对象 e
- 兼容性的写法 => e = e || window.event
- pageX,pageY
- offsetX,offsetY
- clientX,clientY
- 元素.offsetTop,元素.offsetLeft
- 元素.clientTop,元素.clientLeft
- 元素.offsetWidth,元素.offsetHeight
- 元素.clientWidth,元素.clientHeight
- e.target => 目标对象
- 事件传递机制
- 捕获
- 事件源
- 冒泡
- 事件的委派
- 给后续添加的子元素友好
- 减少在标签上绑定事件,减少内存的占用
- 阻止表单提交
- 在form表档上面直接写 onsubmit = "return false"
- 在form表单的提交事件 写 return false;
- 使用事件对象 e.preventDefault()
- 阻止事件的冒泡
- e.stopPropagation();
知识点
键盘事件的其他属性
-
keydown和keypress的区别
- keydown是可以认识功能键,但是keypress是不认识功能键
- keydown是不识别大小写的,但是keypress是key识别大小写的
-
e.keyCode => 键盘码
比如
<input type="text">
<script>
var inp = document.querySelector("input")
//可以识别的功能键,不区别大小写
inp.onkeydown = function(){
console.log("keydown触发");
}
//不是被功能键,可以识别大小写
inp.onkeypress = function(e){
console.log("keypress被触发",e.keyCode);
}
//keyCode => 当我们在按键盘的键的时候,计算机有时候为了识别你按的是哪一个键,所以可以利用keyCode来识别你按的键
//通过你按的键盘中键对应有一个键码 => 记住一个键码 => 回车键的键码是13
inp.onkeydown = function(e){
console.log(e.keyCode);
}
</script>
-
练习
<form action="http://1000phone.com">
账号: <input type="text"><br>
密码: <input type="password"><br>
<input type="submit">
</form>
<script>
var inp = document.querySelector("input:nth-child(2)")
inp.oninput = function(e){
if(e.keyCode == 13){
alert("登录操作")
}
}
</script>
-
组合按键
- shiftKey => shift键
- ctrlKey => ctrl键
- altKey => alt键
- metaKey => window键
比如
//比如,按回车键+shift实现输出打印
console.log(e.shiftKey);
if(e.keyCode == 13 && e.shiftKey){
console.log("您按的是回车键+shift键");
}
/* 按a键+alt键组合使用 */
console.log(e.keyCode);
if(e.keyCode == 65 && e.altKey){
console.log("a键与alt键的组合使用");
}
/* ctrlKey + b键 */
console.log(e.keyCode);
if(e.keyCode== 66 && e.ctrlKey){
console.log("b键+ctrl键");
}
this的指向
- 谁调用这个函数,那么this就指向谁
- 在全局作用域当中,this指向window
- 强制改变this的执行
- call => 改变this的指向,调用函数
- apply => 改变this的指向,调用函数
- bind => 改变this的指向,不调用函数
语法规则
call的使用
语法:函数名.call(参数一,参数二....)
参数一 => this的指向
参数二往后 => 参数
作用:
改变this的指向
调用这个函数
apply的使用
语法:函数名.apply(参数一,[参数二....])
参数一 => this的指向
参数二往后 => 参数
作用:
改变this的指向
调用这个函数
bind的使用
语法:函数名.bind(参数一,参数二...)
参数一 => this的指向
参数二往后 => 参数
作用:
改变this的指向
不调用这个函数
无参使用
var obj = {name:"张三",age:18,gender:'男'}
function fn(){
console.log(this);
}
// fn(); //普通的函数调用 => this=>window
fn.call(obj) //强制改变this的指向,this指向的是obj这个对象
fn.apply(obj) //强制改变this的指向,this执行就是obj这个对象
fn.bind(obj)() //强制改变this的指向
有参使用
var obj = {name:'张三'}
function fn(a,b,c){
console.log(this);
console.log(a,b,c);
}
fn(1,2,3);//普通的
fn.call(obj,1,2,3) //this指向obj,参数是1,2,3
fn.apply(obj,['张三','李四','王五'])
fn.bind(obj,1,2,3)() //this的指向obj
fn.call(1,'小名',obj,['你好'])//this => Number(1) 参数=>'小名',obj,['你好']
包装类
比如
//是一个引用数据类型
// var obj = {name:"张三",age:18}
// console.log(obj.name1);
//基本数据类型
// 基本数据类型本质点出来的,但是基本数据类型在使用的过程当中,会将基本数据转成一个引用(复杂)数据类型
// 我们管这种叫做包装类
var a = "abc";
var b = 10;
var c = true;
console.log(c.valueOf());
console.log(b.toString());
console.log(a.length);
//基本数据类型,Number,String,Boolean,Null,Undefined
//其中Null和Undefined是无法进行转换成包装类
思考题
//a.b => 做了什么?
/*
先看a
看a的数据类型
基本数据类型
a 是不是null,undefined这些 => 直接报错,不是就会将a转换成包装类
复杂数据类型
a 是可以直接点出来的
再看b
如果b属于a的属性,那么就直接输出b对应的属性值
如果b不属于a的属性,那么输出的就是undefined
*/
reduce
比如
var arr = [1,2,3,4,5,6]
/*
参数一
参数A prev => 是数组的第一个值或者是上一次的统计结果
参数B item => 遍历数组里面的每一个元素
参数二
统计的初始值
*/
var res = arr.reduce(function(prev,item){
console.log(prev,item);
return prev + item;
},10)
console.log(res)
Storage
-
Storage是浏览器存储数据的一种解决方案
-
Storage存储的大小一般为5M左右
-
Storage存储的是形式是
KEY/VLALUE的形式 -
Storage只能是前端处理
-
注意: Storage不要存储对象,如果要存储对象,那么将对象转换JSON数据格式进行存储
-
Storage分为两种
- localStorage(持久化存储) => 使用localStorage进行存储的除了人为的删除,否则会永远存在在浏览器里面
- sessionStorage(会话存储) => 使用sessionStorage进行存储,当我们把浏览器给关闭之后,那么存储的内容消失
-
语法
-
localStorage
- 存储 =>
localStorage.setItem("key","value") - 获取 =>
localStorage.getItem("key") - 删除 =>
localStorage.removeItem("key")
- 存储 =>
-
sessionStorage
- 存储 =>
sessionStorage.setItem("key","value") - 获取 =>
sessionStorage.getItem("key") - 删除 =>
sessionStorage.removeItem("key")
- 存储 =>
-
-
在浏览器当中找到Storage存储位置 打开浏览器 => F12 或者 右键检查 => Application => Storage => localStorage或者SessionStorage
案例
//localStorage => 持久化存储
//存储
localStorage.setItem("name","张三")
//获取
var res = localStorage.getItem("name")
console.log(res);
//删除
localStorage.removeItem("name")
//sessionStorage => 会话存储
//存储
sessionStorage.setItem("name","李四")
//获取
var res = sessionStorage.getItem("name")
console.log(res);
//删除
sessionStorage.removeItem("name")
//Storge里面不要存储对象,存储对象就取不出来了
var obj = {name:"zhangsan",age:18,gender:"男"}
//如果要存储对象,那么需要将数组转换成JSON格式
localStorage.setItem("obj",JSON.stringify(obj))
var result = localStorage.getItem("obj")
console.log(result);
JavaScript第14天
回顾
- 键盘事件的其他属性
-
获取键盘事件的键码 =>
e.keyCode回车键的键码是13 -
组合键
e.shiftKeye.altKeye.metaKeye.ctrlKey
- this的指向
-
全局作用域当中 => window
-
this指向的函数的调用着
-
强制改变this的执行
- call
- apply
- bind
- 基本数据类型与复杂数据类型的区别
- 基本数据类型存储的就是值
- 复杂数据类型存储的就是地址
- 包装类 基本数据类型在使用的过程当中,会将基本数据类型转换成复杂数据类型 => 比如: var a = 10;a.toString();
- reduce的使用
比如
var arr = [1,2,3,3,4,5,6]
/*
参数一 函数
参数一 初始值或者上一次统计的结果
参数二 数组里面的每一项元素
参数二 统计的初始值
*/
var res = arr.reduce(function(prev,item){
return prev + item;
},10)
- storage
-
持久话存储
- 存储 =>
localStorage.setItem("key","value") - 获取 =>
localStorage.getItem("key") - 删除 =>
localStorage.removeItem("key")
- 存储 =>
-
会话存储
- 存储 =>
sessionStorage.setItem("key",value) - 获取 =>
sessionStorage.getItem("key") - 删除 =>
sessionStorage.removeItem("key")
- 存储 =>
-
不要存储对象
-
存储大小为5M
-
持久化存储的是会一直的存储浏览器里面,除非人为的删除,会话存储当浏览器关闭的时候,会话存储的内容会消失
知识点
1. ES6定义变量
- ES6定义变量 我们之前使用的var在定义变量的时候,有问题存在,所以ES6使用let和const来定义变量
-
ES6定义变量使用的是let或者const定义变量,let或者const定义变量与var的区别?
- let或者const定义的变量变量名不能重复使用
- let或者const定义的变量具有块级作用域的特点
- let或者const定义的变量没有预解析,var定义的边有预解析
- let和const与var的区别
比如
/*
ES6定义变量
*/
// - let或者const定义的变量变量名不能重复使用
let a = 10;
let a = 20;
// - let或者const定义的变量没有预解析,var定义的边有预解析
console.log(a);
var a = 10;
console.log(a) //没有变量的提升
let a = 10;
// - let或者const定义的变量具有块级作用域的特点
/*
var声明的变量类似于一层楼,楼里面都是一块公共的空间,但是
let声明的变量相当于将这一层楼进行的装修,将每一个房间给独立开来
各个空间之间互不影响
*/
/*
i = 0 => 空间
lis[0].onclick = function(){
console.log(i);
}
i = 1 => 空间
lis[1].onclick = function(){
console.log(i);
}
i = 2 => 空间
lis[2].onclick = function(){
console.log(i);
}
i = 3 => 空间
lis[3].onclick = function(){
console.log(i);
}
*/
let lis = document.querySelectorAll("ul>li")
for(let i = 0 ; i < lis.length ; i++){
lis[i].onclick = function(){
console.log(i);
}
}
-
const和let的区别
- const是常量,常量就是不可该变的量,而let声明的变量是可以改变的
- const在定义变量的时候,必须要赋值,如果不赋值就会报错,但是let可以在定义变量的时候,不赋值
比如
// let 定义的变量可以改变,const定义的变量是不可以改变的量
let a = 10;
const b = 10;
a = 11;
b = 11;
console.log(a,b);
//let定义的变量可以不需要定义初始值,const定义的变量必须要赋值
const a1;
let a2;
2. 箭头函数
- 语法
比如
//普通函数
function fn(a, b) {
return a + b;
}
fn(1, 2)
//匿名函数
var fn = function (a, b) {
return a + b;
}
//箭头函数 -> 将关键字function省略不写,变成一个箭头 =>,将箭头写在参数小括号的后面
var fn = (a, b) => {
return a + b
}
//语法特点1 => 当参数只有一个的情况下,可以省略小括号不写,其他情况必须写
// var fn = (a) => { return a + a }
var fn = a => { return a + a }
//语法特点2 => 当大括号里面只有一句代码的时候,并且有返回值return存在,那么可以将return和大括号省略不写,其他情况不行
// var fn = a => { return a + a }
var fn = a => a + a
- 特点
- 箭头函数没有自己this,箭头函数的this沿着作用域链往外找
- 箭头函数没有arguments
比如
<button>点我</button>
<script>
function fn(){
console.log(arguments);
}
fn(1,2,3,4,5)
//箭头函数没有arguments
var fn = () => {
console.log(arguments);
}
fn(1,2,3,4,5);
//箭头函数没有自己的this,箭头函数的this沿着作用域链的形式往找找
var btn = document.querySelector("button")
btn.onclick = () => {
console.log(this);
}
</script>
3. 定时器的this和定时器的箭头函数写法
- 全局作用域 => window
- 谁调用这个函数 => 调用着
- 箭头函数没有自己的this,this沿着作用域链往外找
- 定时器当中this => window
- 强制改变this的指向
- call
- apply
- bind
比如
//定时器当中this是指向window => 归纳成谁调用=> this指向谁
setInterval(function(){
console.log(this);
},1000)
//定时器的箭头函数写法
setInterval(()=>{
console.log("我是箭头函数定时器写法");
},100)
setTimeout(()=>{
console.log(this);
},100)
4. 模板字符串
- 写变量
- 换行
比如
var str = `
${变量}
`
5. ES6对象中属性和方法的简写
比如
//ES6的对象简写
const obj1 = {
name:"张三",
age:18,
gender:"男",
//方法
eat:function(){
console.log("张三吃");
}
}
//ES6的属性和方法的简写
const name = "张三"
const age = 18;
const gender = "男"
const obj2 = {
//简写属性
name,
age,
gender,
//ES6的方法简写,将:function省略不写
eat(){
console.log("李四吃");
}
}
var res = obj2.eat();
console.log(res);
6. 参数默认值
比如
/*
参数默认值就是形参
有时候实参在传参数的过程中,没有对应上每一个形参,此时形参是undefined
可以使用参数默认来解决没有传参的问题
注意的问题
如果我们传参了,那么参数的默认值失效
一般情况将参数默认值在后面可以了
*/
function fn(a = '11', b, c = '10') {//c = '10' => 表示第三个参数的默认值
console.log(a, b, c);
}
fn(2, 3)
7. 解构赋值
当我们需要取数组或者是对象里面的某一些数组的时候,通过点语法或者数组的语法去取数组
- 数组的解构
比如
// let arr = ["🍉","🍎","🍐",'🍌','🍇']
// let a1 = arr[0]
// let a2 = arr[1]
// let a3 = arr[2]
// let a4 = arr[3]
// let a5 = arr[4]
// console.log(a1,a2,a3,a4,a5);
//数组的解构来取值
//一维数组的解构
// const arr = ["🍉","🍎","🍐",'🍌','🍇']
const [a,b,c,d,e] = arr;
console.log(a,b,c,d,e);
//多维数组 => 在数组里面继续写数组
const arr = [1,[2,[3,[4,[5,[6,[7,8,9]]]]]]]
//多维数组的解构
const [a,[b,[c,[d,[e,[f,[g,h,i]]]]]]] = arr;
console.log(a,b,c,d,e,f,g,h,i);
- 对象的解构
比如
const obj = {
username: "张三",
age: 18,
gender: "男"
}
// console.log(obj.name,obj.age,obj.gender);
//普通对象的解构
const {name,age,gender} = obj;
console.log(name,age,gender);
//别名,小名
const {username:nickname,age,gender} = obj;
console.log(nickname,age,gender);//对象的解构使用了别名,如果再使用真名,那么就会报错
//深度层次的对象解构
const student = {
username: "张三",
age: 18,
gender: '男',
hobby: ["🏀", "⚽", "🏓", "🏸"],
address: {
info1: "贵阳",
info2: "怀化"
}
}
//对象的深度解构
const {username,age,gender,hobby: [h1, h2, h3, h4],address: {info1:address1,info2}} = student;
console.log(username,age,gender,h1,h2,h3,h4,address1,info2);
8. 展开运算符(扩展运算符,三点运算符)
- 扩展运算符的基本使用
比如
//我说数组也是一个对象,数组的下标其实就是对象的KEY,数组的元素其实就是对象的VALUE
const arr = [1,2,3,4,5]
//将数组的名前面添加...
console.log(...arr); //就是将数组给展开了 => 1 2 3 4 5 6
const obj = {name:"张三",age:18,gender:"男"}
//可以展开,可以合并
// console.log({...obj,phone:13701120123});//用一个对象将展开的内容合并起来
console.log({...arr,...obj});//{0:1,1:2,2:3,3:4,4:5,name:"张三",age:18,gender:"男"}
//函数的参数用法
function fn(a,c,...b){//相当于将后面所有参数都交给的b
console.log(a,b,c);
}
fn(1,2,3,4,5,6,7,8,9)
- 扩展运算符与浅拷贝
比如
var obj = {
name:"张三",
age:18,
address:{
info1:'贵阳',
info2:"长沙"
},
hobby:["🏀","⚽","🏸"]
}
// var newObj = obj; //这个拷贝,就是将obj存储的地址复制一份给newObj
//浅拷贝 => 只拷贝一层数据
var newObj = {}
// for(var key in obj){
// //将老对象里面的key值和value值复制一份,给newObj
// newObj[key] = obj[key]
// }
var newObj = {...obj}
//将老对象里面的name值修改成李四
obj.name = "李四"
obj.address.info1 = "深圳"
obj.age = 88;
obj.hobby[1] = "湖南"
console.log(newObj,obj);
9. 新容器语法
- map
比如
//创建一个map容器
var map = new Map()
//map容器的添加
map.set(1,"张三");
map.set(2,"李四")
map.set(3,"王五")
map.set(4,"赵六")
map.set(5,"田七")
//有则修改,无则添加
map.set(1,"王五") //key是唯一的,出现重复的key会覆盖原先的和key一直的value值
//KEY和VALUE 都是任意类型的
map.set({},[])
//删除
map.delete(5) //根据KEY删除这一条
console.log(map);
console.log(map.get(1));
//注意,map身上有迭代器,是可以进行for of遍历的
for(var value of map){
console.log(value[0],value[1]);
}
//还可以使用forEach
map.forEach((item)=>{
console.log(item);
})
//清空map里面所有的内容
map.clear();
console.log(map);
- set
比如
var obj = {}
/*
ES6提出了一个新容器的语法 => Set
Set里面没有重复的元素
*/
//创建一个set
var set = new Set();
set.add(1)
set.add("ni hao")
set.add(obj)
set.add([])
//删除
// set.delete("ni hao")
// set.delete(obj)
//查
console.log(set.has(1)); //返回true,表示有,false表示没有
console.log(set);
//使用forof进行遍历
for(var value of set){
console.log(value);
}
//forEach遍历
set.forEach((item)=>{
console.log(item);
})
//清空
console.log(set.clear());
去重
var arr = [1,2,3,1,2,3,1,2,3]
//set里面的元素是唯一的
// var res = new Set(arr)
// console.log([...res]);
// var res = new Set(arr)
console.log([...new Set(arr)]);
10. Symbol
比如
// symbol是一个ES6提出来的基本数据类型 => 使用Symbol所修饰的内容提供唯一的标识
const a1 = Symbol(1)
const a2 = Symbol(1)
console.log(a1 == a2);
11. 模块化开发
- 安装live server插件 => 可以将代码以服务器的方式启动
- 导入模块化的JS文件 =>
<script src="JS路径" type="module"></script> - 语法:
-
方式一
- 导出 =>
export default {想要导出的内容}
//暴露出去 导出 export default { name1, name2, name3, fn, arr }- 导入 =>
import 变量名 from '路径.js'
//导入 import head from './header.js' console.log(head); - 导出 =>
-
方式二
- 导出 =>
export const 变量名 = 变量存储内容
export const name = "张三"; export const fn = function(){console.log("111111111111111");} export const obj = {};-
导入 =>
import {变量名} from '路径.js'- as
import {name,fn,obj} from './footer.js' fn() console.log(name,obj);JavaScript第15天
- 导出 =>
回顾
- ES6定义变量
-
使用 const 和 let 来作为声明变量的关键字
-
const 和 let 与 var 的区别
- var有预解析,const 和 let 没有预解析
- const 和 let 具有块级作用域的特点
- const 和 let 声明的变量,变量名不能重复
-
let 与 const 的区别
- let 声明的是变量,const声明的是常量(常量就是不可以改变的量)
- let 声明的变量可以不用赋值,但是const 声明的变量必须要赋值
- 箭头函数
-
将function省略,变成一个箭头 => ,写在小括号的后面
-
语法的特点:
- 如果参数只有一个,那么可以省略小括号不写
- 如果函数体中只有一句,并且有一个return,那么可以省略return和{}不写
-
功能的特点:
- 箭头函数没有自己this,箭头函数的this沿着作用域链往找外
- 箭头函数没有arguments
- 箭头函数与定时器的使用
比如
setInterval(()=>{
})
- this的执行
-
全局作用域 => window
-
定时器 => wind- ow
-
谁调用这个函数 => 调用者
-
箭头函数没有自己的this,沿着作用域链往外找
-
强制改变this的指向
- call
- apply
- bind
- 模板字符串
- 换行
- 写变量
- 对象的简写
- 当key和value一样的时候,可以只写一个
- 在对象里面的方法可以解析,省略
:function不写
- 参数默认值
比如
function fn(a=10,b=20,c){
}
fn(11,12,13)
- 解构赋值
- 数组的解构赋值 const arr = [1,2,3,4] const [a,b,c,d] = arr;
- 对象的解构 const obj = {name:"张三"} const {name:username} = obj;
- 扩展运算符 var obj = {a:1,b:2} console.log({...obj,...arr}) var arr = [1,2,4] console.log([...obj,...arr])
- Set和Map
- Symbol
- ES6模块化开发
-
安装
live server插件 -
在页面当中导入其他模块 =>
<script src="路径" type="module"></script> -
语法一:
- 暴露 =>
export default {} - 导入 =>
import 变量名 from '路径.js'
- 暴露 =>
-
语法二:
- 暴露 =>
export const a = 10; - 导入 =>
import {a} from '路径.js'
- 暴露 =>
localStorage.clear()=> 清空所有的localStorage
知识点
认识真这个表达式
- 正则表达式就是专门给字符串进行类型的检测的,检测字符串是否符合我预期
- 有时候,HTML的标签检测,并不能满足的我的对于一个字符串的要求,那么此时,我们可以来写一个正则表达式来书写满足我们自己的规则
- 正则表达式属于复杂数据类型
创建正则表达式两种形式
- 字面量创建正则表达式 ->
var reg = /正则表达式/ - 使用内置构造函数创建正则表达式 ->
var reg = new RegExp(正则表达式)
正则表达式的方法_test
语法: 正则.test(字符串) => 如果字符串满足的正则的要求,那么就返回true,如果没有满足正则的要求,那么就会返回一个false
比如
/*
正则表达式的方法
语法: 正则.test(字符串)
返回: boolean
*/
// 使用字面量创建一个正则表达式
const reg1 = /123/ //就是判断某一个字符串是否包含123
console.log(reg1.test('abc123def456')); //true => 包含了123
console.log(reg1.test('abc213def546')); //false => 没有包含123
//使用内置构造函数创建正则表达式
const reg2 = new RegExp("123") ////就是判断某一个字符串是否包含123
console.log(reg2.test('abc123def456')); //true => 包含了123
console.log(reg2.test('abc213def546')); //false => 没有包含123
正则表达式的元字符
- 普通的元字符
\d=> 表示 一位 数字\D=> 表示 一位 非数字\w=> 表示 一位 数字字母下划线\W=> 表示 一位 非数字字母下划线\s=> 表示 一位 空白字符\S=> 表示 一位 非空白字符.=> 表示 一位 非换行- `` => 转义字符串 => 将有意义的符号转换成没有意义的文本,将没有意义的文本转换成有意义的符号
比如
// - `\d` => 表示 一位 数字
var reg = /\d/ // 表示包含一位数组
console.log(reg.test('a1b2c3')); //true
console.log(reg.test('abcdef')); //false
console.log(reg.test('abc123')); //true
console.log(reg.test('123456')); //true
// - `\D` => 表示 一位 非数字
var reg = /\D/ //表示包含一位非数组
console.log(reg.test('a1b2c3'));//true
console.log(reg.test('abcdef'));//true
console.log(reg.test('abc123'));//true
console.log(reg.test('123456'));//false
// - `\w` => 表示 一位 数字字母下划线
var reg = /\w/ //表示包含一位数字或者字母或者下划线
console.log(reg.test('a1b&_'));//true
console.log(reg.test('abc12'));//true
console.log(reg.test('abc!'));//true
console.log(reg.test('&^%$#'));//false
// - `\W` => 表示 一位 非数字字母下划线
var reg = /\W/ //表示包含一位非数字字母下划线
console.log(reg.test('a1b&_'));//true
console.log(reg.test('abc12'));//false
console.log(reg.test('abc!'));//true
console.log(reg.test('&^%$#'));//true
// - `\s` => 表示 一位 空白字符(包含空格,换行也算)
var reg = /\s/ //表示包含一个空格字符
console.log(reg.test('1 2')); //true
console.log(reg.test('123')); //false
console.log(reg.test(' '));//true
console.log(reg.test('\n'));//false,true
console.log(reg.test('\t'));//false,true
console.log(reg.test('abcef123'));//false,true
// - `\S` => 表示 一位 非空白字符
var reg = /\S/ //表示包含一个非空格字符
console.log(reg.test('1 2'));//true
console.log(reg.test('123'));//true
console.log(reg.test(' '));//false
console.log(reg.test('\n'));//false
console.log(reg.test('\t'));//false
console.log(reg.test('abcef123'));//true
// - `.` => 表示 一位 非换行
var reg = /./ //表示包含一位非换行
console.log(reg.test("abc\n123"));//true
console.log(reg.test("\n"));//false
console.log(reg.test("123"));//true
// - `` => 转义字符串 => 将有意义的符号转换成没有意义的文本,将没有意义的文本转换成有意义的符号
//检测一个是否存在的d
// var reg = /\d/ //将普通的文本d转换成意义的数组 \d 表示就是检测数组
//检测1.4
var reg = /./ //将有意义的符号转换成没有意义的文本
console.log(reg.test('1.5'));
console.log(reg.test("1#5"));
- 边界元字符
^=> 正则以某某开头$=> 正则以某某结尾
比如
// 边界元字符
// ^ => 以某某开头
var reg = /^\d/ //表示以数字开头
console.log(reg.test('123'));//true
console.log(reg.test("4"));//true
console.log(reg.test("A4"));//true
// $ => 以某某结尾
var reg = /\d$/ //表示以数字结尾
console.log(reg.test('123'));//true
console.log(reg.test("4"));//true
console.log(reg.test("A4"));//true
console.log(reg.test("4A"));//false
var reg = /^\d$/ //以数字开头,以数字结尾,只有一位数字
console.log(reg.test('123'));//true
console.log(reg.test("4"));//true
console.log(reg.test("A4"));//false
console.log(reg.test("4A"));//false
- 限定元字符
*=> 表示0个或者多个+=> 表示1个或者多个?=> 表示0个或者1个{n}=> 表示只有n个{n,}=> 表示至少n个{n,m}=> 表示n到m个
比如
// - `*` => 表示0个或者多少个
var reg = /^\w*$/ //以数字或者字母或者下划线开头和结尾,可以有0个或者多个数字字母下划线组成
console.log(reg.test(""));//true
console.log(reg.test("_abc1"));//true
console.log(reg.test("_a$c1"));//false
console.log(reg.test("ab 12"));//false
console.log(reg.test(" "));//false, 如果是0个,如果是多个,那么必须由数字字母下划线组成
// - `+` => 表示1或者多个
// var reg = /^\w+$/ //以数字或者字母或者下划线开头和结尾,可以有1个或者多个数字字母下划线组成
console.log(reg.test(""));//false
console.log(reg.test("_abc1"));//true
console.log(reg.test("_a$c1"));//false
console.log(reg.test("ab 12"));//false
console.log(reg.test(" "));//false
// - `?` => 表示0或者1个
// var reg = /^\w?$/ //以数字或者字母或者下划线开头和结尾,可以有0个或者1个数字字母下划线组成
console.log(reg.test(""));//true
console.log(reg.test("_abc1"));//false
console.log(reg.test("_a$c1"));//false
console.log(reg.test("ab 12"));//false
console.log(reg.test(" "));//false
// - `{n}` => 表示只有n个
// var reg = /^\w{2}$/ //以数字或者字母或者下划线开头和结尾,必须是2位数字字母下划线
console.log(reg.test(""));//false
console.log(reg.test("c1"));//true
console.log(reg.test("$c"));//false
console.log(reg.test(" 2"));//false
console.log(reg.test(" "));//false
// - `{n,}` => 表示至少n个
// var reg = /^\w{2,}$/ //以数字或者字母或者下划线开头和结尾,至少是2位数字字母下划线
console.log(reg.test(""));//false
console.log(reg.test("c12"));//true
console.log(reg.test("$c"));//false
console.log(reg.test(" 2"));//false
console.log(reg.test(" "));//false
// - `{n,m}` => 表示n到m个
var reg = /^\w{2,4}$/ //以数字或者字母或者下划线开头和结尾,内容的范围在2~4个之间,包含2个和4个
console.log(reg.test(""));//false
console.log(reg.test("c12"));//true
console.log(reg.test("$c"));//false
console.log(reg.test(" 2"));//false
console.log(reg.test("abcd"));//true
console.log(reg.test("abd"));//true
- 特殊元字符
()=> 一个整体|=> 或者[]=> 一个[^]=> 非-=> 连接符,至
比如
// - `()` => 一个整体,代表一个
// - `|` => 或者
var reg = /^(a|b)+$/ //以a或者b开头和结尾,由a或者b组成,至少存在一个
console.log(reg.test("a"));//true
console.log(reg.test("b"));//true
console.log(reg.test("ab"));//true
console.log(reg.test("abc"));//false
// - `[]` => 一个
var reg = /^[0123456789]{2}3$/ //以数字开头,以3结尾,长度3位
console.log(reg.test("012"));//false
console.log(reg.test("013"));//true
console.log(reg.test("014"));//false
console.log(reg.test("110"));//false
console.log(reg.test("111"));//false
console.log(reg.test("1131"));//false
// - `-` => 连接符,至
var reg = /^[a-z]{2}[0-9]{3}$/ //以字母开头,以数字结尾,2个字母和三个数字组成,顺序不能乱
console.log(reg.test("ab123"));//true
console.log(reg.test("abc12"));//false
console.log(reg.test("abc123"));//false
console.log(reg.test("a 323"));//false
// - `[^]` => 非
var reg = /^[^a-z]{2}[0-9]{3}$/ //不能以小写字母开头,长度为2位,以数字结尾,长度3位
console.log(reg.test("ab123"));//false
console.log(reg.test("abc12"));//false
console.log(reg.test("abc123"));//false
console.log(reg.test("& 323"));//true
console.log(reg.test("&2323"));//true
console.log(reg.test("&A323"));//true
console.log(reg.test("&a323"));//false
- 重复元字符 \1 => 重复第1个小括号里面的内容 \2 => 重复第2个小括号里面的内容 \3 => 重复第3个小括号里面的内容
比如
/*
重复元字符
\1 => 重复第1个小括号里面的内容<br>
\2 => 重复第2个小括号里面的内容<br>
\3 => 重复第3个小括号里面的内容<br>
*/
var reg = /^(aa|bb)(xx|yy)\1$/ //以aa或者是bb开头,如果是aa开头,那么就是aa结尾,如果bb开头,那么就bb结尾,中间可以是xx或者是yy
console.log(reg.test("aabbxx"));//false
console.log(reg.test("aabbyy"));//false
console.log(reg.test("aaxxbb"));//false
console.log(reg.test("aayybb"));//false
console.log(reg.test("bbyyaa"));//false
console.log(reg.test("aayyaa"));//true
console.log(reg.test("bbxxbb"));//true
var reg = /^(aa|bb)(xx|yy)\2$/
console.log(reg.test("aabbxx"));//false
console.log(reg.test("aabbyy"));//false
console.log(reg.test("aaxxxx"));//true
console.log(reg.test("aayyyy"));//true
- 标识符
- i => 忽略大小写
比如
//标识符 => i 忽略大小写
//字面量 => var reg = /正则/标识符
//内置构造 => var reg = new RegExp("正则","标识符")
var reg = /^[a-z]{2}$/i
console.log(reg.test("ab"));//true
console.log(reg.test("a1"));//false
console.log(reg.test("Ab"));//true
console.log(reg.test("aB"));//true
console.log(reg.test("11"));//false
正则表达式的方法二
- exec => 从字符串里面捕获符合正则表达式的内容
- 语法: 正则.exec(字符串)
比如
//这是一个字符串
const str = "abc123def456"
// 012345678901
const reg = /\d{3}/
const res = reg.exec(str)
console.log(res);
标识符二
- g => 全局匹配,从字符串的头到尾部,全部进行匹配
- 语法:
var reg = /正则/g
比如
var str = "我爱JavaScript"
// 0 1 2345678901
var reg = /a/g
var res1 = reg.exec(str)
var res2 = reg.exec(str)
var res3 = reg.exec(str)
var res4 = reg.exec(str)
var res5 = reg.exec(str)
console.log(res1);
console.log(res2);
console.log(res3);
console.log(res4);
console.log(res5);
正则表达式的两种模式
-
贪婪模式 => 贪婪 => 能拿多少就拿多少
*+?{n}{n,}{n,m}
-
非贪婪模式 => 非贪婪 => 能拿多少就拿多少
*?+???{n}?{n,}?{n,m}?
比如
const str = "<p class='c1'>我是第一个p标签</p><p class='c1'>我是第一个p标签</p><p class='c1'>我是第一个p标签</p>"
const reg = /<p.*>.*</p>/ //贪婪模式 => 尽量多的拿
const reg = /<p.*?>.*?</p>/ //非贪婪模式 => 尽量少的拿
console.log(reg.exec(str));
字符串和正则的方法
- repalce
- 语法: =>
str.replace(正则,"换上字符")
比如
var str = "我爱JavaScript"
//将str字符串里面的第一个a替换成*
// console.log(str.replace("a",'*'));
// console.log(str.replaceAll("a","*"));
/* replace 和 正则的使用
语法: 字符串.replace(正则,'换上字符串')
*/
var reg = /a/ //只能替换第一个*
var reg = /a/g //使用全局匹配的方式可以批量替换
console.log(str.replace(reg,'*'));
- search
比如
var str = "我爱JavaScript"
//search => 查找的意思
//语法: 字符串.search(字符串片段) 返回的就是字符串片段的下标,找不到就返回-1
// console.log(str.search('a11'));
//正则的语法 => 字符串.search(正则) 返回的就是正则表达式满足要求的的下标,不满足就返回-1
var reg = /a/
console.log(str.search(reg));
- match
- 如果没有写g,那么作用和exec一样
- 如果写了g,那么将匹配到的结果组合成一个数组
比如
var str = "我爱JavaScript"
//字符串的语法
//语法: str.match("字符串片段")
// console.log(str.match('a'));
//正则和字符串match使用
console.log(str.match(/a/)); //这个作用和exec一样
console.log(str.match(/a/g)) //将匹配到的结果组成成一个数组
JavaScript第16天
回顾
- 创建正则表达式
- 字面量 ->
const reg = /正则/ - 内置构造函数 ->
const reg = new RegExp(正则)
- 普通元字符
\d=> 一个 数字\D=> 一个 非数字\w=> 一个 数字,字母,下划线\W=> 一个 非数字字母下划线\s=> 一个 空白字符\S=> 一个 非空白字符.=> 一个 非换行字符- `` => 转义字符
- 边界元字符
^=> 以谁开头$=> 以谁结尾
- 限定元字符
*=> 0到多个+=> 1到多个?=> 1到0个{n}=> n个{n,}=> 至少n个{n,m}=> n到m个
- 特殊元字符
()=> 一个整体|=> 或者[]=> 一个[^]=> 非-=> 到,至
- 重复元字符
\n=> 表示将第n个小括号里面的内容重复一遍
- 标识符
i=> 忽略大小写g=> 全局匹配
- 正则表达式的方法
- test => 判断字符串是否符合正则表达式的内容,符合返回true,不符合返回false
- exec => 捕获字符串里面的内容
- 贪婪模式
-
非贪婪 => 尽可能的少获取
*?+???{n}?{n,}?{n,m}?
-
贪婪 => 尽可能的多获取
*+?{n}{n,}{n,m}
- 字符串与正则的方法
- replace('正则','换上字符')
- search('正则')
- match('正则')
JavaScript第17天
知识点
面向对象
面向对象的是一个抽象的思想
- 面向过程和面向对象
-
面向过程 注重代码的过程,步骤,按部就班做事情 比如: 吃面 1. 买面 2. 烧水 3. 和面 4. 下面 5. 捞面 6. 拌面 7. 吃 我们以前写代码都是面向过程的代码
-
面向对象 不注重过程,只注重结果 比如:
- 找一个面馆
- 点一碗面
- 吃 面向对象是对面向过程的一个高度封装
- 面向对象的核心思想
-
封装 将代码内部隐藏起来,不直接给外部进行访问
-
继承 子承父业,子类将父类里面的内容给继承下来
-
多态 同一种事物的表现出来的多种形态
- 继承
- 父类的引用指向子类的实例
- 重写
- 学习的面向对象的目的 就是能够看的懂别人封装的代码
创建对象
- 创建对象
-
字面量创建对象
- 优点:创建对象方便
- 缺点:创建对象一次只能创建一个对象
比如
var obj = {
name:"张三"
}
-
内置构造函数创建对象
- 优点:使用
new的关键字来创建对象 - 缺点:创建对象一次只能创建一个对象
- 优点:使用
比如
const obj = new Object();
obj.name = "张三"
obj.age = 18;
obj.gender = "男"
obj.eat = function(){
console.log("吃");
}
const obj = new Object();
obj.name = "李四"
obj.age = 19
obj.gender = "女"
obj.eat = function(){
console.log("吃");
}
// 利用函数进行封装
function Person(name,age,gender){
const obj = new Object();
obj.name = name;
obj.age = age;
obj.gender = gender;
obj.eat = function(){
console.log("吃");
}
return obj;
}
const p1 = Person("张三",18,"男")
const p2 = Person("李四",19,'女')
- 构造函数
- 内置构造函数
- 自定义构造函数
比如
function Person(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
this.eat = function(){
console.log("吃");
}
}
const p1 = new Person("张三",18,"男")
const p2 = new Person("李四",19,"女")
- 构造函数的特点
比如
/*
构造函数的特点
1. 构造函数也是函数,在创建的需要使用function关键字进行声明
2. 构造函数为了区分其他函数,建议将函数的名首字母大写
3. 构造函数内部的this指向的是创建对象的实例对象
4. 构造函数里面的return不建议写
如果返回的是基本数据类型 => 不起作用
如果返回的是引用数据类型 => 构造函数失效
5. 构造函数一定需要搭配new关键子使用
*/
function Person(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
// return 1;
// return [1,2,3,4,5]
}
const p1 = new Person("张三",18,"男")
console.log("p1",p1);
- 构造函数的缺点
比如
function Person(name,age){
this.name = name;
this.age = age;
this.eat = function(){
console.log(this.name + "正在吃");
}
}
const p1 = new Person("张三",18)
const p2 = new Person("张三",18)
console.log(p1.name === p2.name);
console.log(p1.eat === p2.eat);
原型
- 所有的对象天生自带一个属性(
__proto__),隐式原型,实例对象也是对象,所以实例对象也有一个属性(__proto__),指向原型的空间 - 所有的函数天生自带一个属性(
prototype),显示原型,构造函数也是函数,所以构造函数也有一个属性(prototype),指向原型的空间 - 所有的构造函数都是
Function函数的实例对象
比如
function Person(name,age){
this.name = name;
// this.age = age;
}
//在原型对象当中添加一个方法
Person.prototype.eat = function(){
console.log("吃");
}
//在Person的原型对象里面添加一个age的属性
Person.prototype.age = 99
//1. 所有的函数天生自带一个属性 prototype(显示原型),构造函数也是函数,也有一个属性prototype => 原型对象
//访问Person的原型,可以通过Person.prototype来访问,原因Person.prototype就是指向Person的原型对象
console.log(Person.prototype);
//2. 所有的对象天生自带一个属性 __proto__(隐式原型),实例对象也是对象,也有一个属性__proto__ => 原型对象
const p = new Person("张三",18)
//访问原型对象,通过实例对象进行访问 p.__proto__
console.log(p.__proto__);
console.log(p.__proto__ === Person.prototype); //true
console.log(p.__proto__.eat === Person.prototype.eat); //true
/*
如果直接使用对象.属性名
如果在对象的自身当中有这个属性,那么就直接使用对象自己身上的属性,如果对象自己身上的没有这个属性,那么就去原型当中进行找
*/
console.log(p.age);
- 原型链 通过proto进行一直往外进行访问,一直访问null为止,形成了一个链条,那么我们管这个链条叫做原型链
- 对象的访问机制
比如
/*
对象的访问机制
1. 先去自己身上找,如果找不到,那么就去原型身上找,在原型的身上找到了,那么就使用,如果没有找到,那么就去原型的原型身上找,一直null为止,还找不到就是undefined
*/
function Person(){
}
const p1 = new Person();
/*
1. 先去自己p实例对象自身去找,找到了就使用,如果找不到,那么就去原型身上找
2. 如果没有再去原型的原型身上找,依次类推
3. 最终找不到,那么就undefined
*/
console.log(p1.__proto__.__proto__.hasOwnProperty);
console.log(p1.hasOwnProperty);
console.log(p1.__proto__.__proto__.hasOwnProperty === p1.hasOwnProperty);
this的总结
- this在全局作用域 => window
- 谁调用这个函数 => 调用这
- 定时器 => window
- 强制改变this的指向,call,apply,bind
- 箭头函数 => 没有自己的this,箭头函数的this指向外部作用域的this
- 在构造函数当中,this指向实例对象
利用原型做点事情
给数组去重
const arr = new Array(1,2,3,1,2,3,1,2,3)
//方式一
Array.prototype.noRepeat = function(){
// console.log(this);
// console.log([...new Set(this)]);
return [...new Set(this)]
}
//方式二
Array.prototype.noRepeat = function(){
//先排序
this.sort()
for(let i = 0 ; i < this.length ; i++){
if(this[i] == this[i+1]){
this.splice(i,1)
//解决数组塌陷
i--
}
}
return this;
}
//方式三
Array.prototype.noRepeat = function(){
//先排序
this.sort()
//倒循环
for(let i = this.length - 1; i>=0 ; i--){
if(this[i] == this[i+1]){
this.splice(i,1)
}
}
return this;
}
//方式四
Array.prototype.noRepeat = function(){
const obj = {}
const newArr = []
this.forEach((item)=>{
//将数组里面的每一个元素都存储到对象的key里面,value无所谓
obj[item] = "无所谓"
})
//遍历对象
for(let key in obj){
newArr.push(+key)
}
return newArr;
}
//方式五
Array.prototype.noRepeat = function(){
//定义一个新的数组,当遍历老的数组的时候,如果新的数组里面没有这个元素,那么就存储进去
const newArr = [1]
this.forEach((item)=>{
if(!newArr.includes(item)){
newArr.push(item)
}
})
return newArr;
}
const res = arr.noRepeat()
console.log(res);
- 创建对象的方式
-
字面量
-
内置构造函数
-
封装内置构造函数
-
构造函数
-
特点
- 构造函数也是函数,使用function关键字进行声明使用
- 构造函数为了区别其他函数,一般构造函数的首字母大写
- 构造函数里面的this执行创建对象的实例对象
- 构造函数里面不要写return,return基本数据类型,return没有用,return引用数据类型,构造函数失效
- 构造函数必须要搭配new关键字进行使用
-
缺点 占用内存空间,利用原型来解决
- 原型
- 所有的函数天生自带一个属性prototype,显示原型,指向的原型空间
- 所有的对象天生自带一个属性proto,隐式原型,指向原型的空间
- 所有构造函数都是Function的实例对象
- 原型链(原型的访问机制) 先在自身的属性当中找到,找到了就使用,找不到就去原型当中查找,如果在原型当中还找不到,那么就去原型的原型当中进行查找,依次类推,一直null位置
JavaScript第18天
回顾
- 面向对象
-
面向对象的核心思想
- 封装
- 继承
- 多态
-
面向对象与面向过程 面向过程面向对象重视的结果,不重视过程 面向对象是对面向过程一个高度的封装
- 创建对象的方式
-
字母量
-
内置构造函数
-
对内置构造函数进行封装
-
构造函数
-
构造函数需要注意的地方
-
构造函数也是函数,使用function关键字声明
-
构造函数为了区分其他的函数,一般建议将构造函数的名首字母大写
-
构造函数里面的this指向的是创建对象的实例对象
-
构造函数里面return建议不要写
- 如果写了基本数据类型,return没用
- 如果写的复杂数据类型,构造函数失效
-
-
构造函数也有缺点 没创建一个对象,对象的方法都开启了一个新的空间,占用内存空间,我们使用公共的一块区域来进行存储实例对象里面的方法
- 原型
- 所有的函数天生自带一个属性
prototype显示原型,构造函数也是函数,也有一个属性prototype,指向构造函数的原型对象 - 所有的对象天生自带一个属性
__proto__隐式原型,实例对象也是对象,也有一个属性__proto__,指向构造函数的原型对象 - 所有的构造函数都是
Function的实例对象
- 原型链
- 当我们使用对象.属性的时候,先在对象的自身当中进行查找,如果找到了,那么就使用,如果没有找到,那么就去对象的原型对象当中进行查找,如果找到那么就使用,否则就去原型的原型对象当中查找,依次类推,一直找到null为止
- 究极原型链
知识点
ES6的类与对象
在JS的ES6里面添加了类的概念,关键字 class
- 什么是类 类是一类事物的统称
- 什么是对象 对象是一类事物当中具体的体现 比如: 人是一个类,张三这一类事物当中具体存在一个个体(对象)
- 创建一个类 类的关键字 -> class
比如
//类的关键字 class
//类的属性是写在constructor里面,但凡有一个类,那么一定会有constructor的存在
//注意: 当我们new Person(实参),JS会自动的调用constructor的方法,并且constructor里面的参数就是形参
class Person{
//属性=>constructor的给属性赋值
constructor(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
console.log(this);//this=>实例对象
}
//方法 => 相当于构造函数的原理中的方法
eat(){
console.log(this.name + '吃');
}
}
//利用类来创建对象
const p1 = new Person("张三",18,"男");
const p2 = new Person("李四",19,"女");
console.log(p1,p2);
JavaScript第19天
回顾
- ES6的类与对象
语法
class 类名{
//属性
constructor(){
}
//方法
方法名(){
}
}
JavaScript第20天
知识点
1. 初始nodejs
- 什么是nodejs? 我们的JS是运行在浏览器里面的,浏览器并不认识JS,nodejs就是将ChromeV8解析引擎复制一份然后重写修改,打包,变成了一个新的内容=>nodejs
- 前端JS与后端JS
-
前端JS是运行在浏览器当中 是通过引入的方式将JS引入到HTML当中,所以才会有DOM和BOM
- BOM是浏览器给的
- DOM是HTML给的
-
后端JS直接安装在电脑的操作系统当中 在电脑当中是可以直接使用的,直接运算
- 操作电脑的操作系统
- 操作数据库
- 操作文件/文件夹(IO)
- nodejs的作用?
- 可以使用nodejs编写后端相关的一些代码
- 可以使用CommonJS的规范一样进行模块化的开发
2. nodejs运行
- 黑窗口命令
-
打开黑窗口 -> 按
window+r键 -> 输入cmd-> 黑窗口就出来了 -> 如果黑窗口太小了,那么将ctrl键按住,并且按鼠标的滚轮进行放大或者缩小 -
黑窗口指令
-
dir => 可以查看当前文件夹里面的相关内容
-
cls => 当我们在黑窗口里面写代码过多的时候,可以使用cls进行清屏
-
cd
- cd / => 返回根目录
- cd ./文件夹 => 进入到某一个文件夹,注意
./可以省略不写 - cd ../ => 返回上一级,注意
/可以省略
-
node => 用来在直接JS代码
写js代码
//敲node => enter //写js代码 //按 => enter 执行JS代码 //退出node编辑环境 => 按ctrl+c,如果一下没有作用,那么就多按几下-
盘符: => 进入到某一个盘符当中,注意:如果进入的是系统的根目录一般是C盘,会默认进入到当前用户的文件夹当中
-
tree => 将电脑里面文件以树形的给展示出来
-
DOS小技巧:
- 可以按键盘的上键 => 返回之前敲的命令 ,可以按键盘的下键 => 返回之后所敲过的命令
- 对于文件名比较长度的内容来说,可以敲几个前面的内容,然后后面的内容可以使用
TAB键进行补充
-
- 运行nodejs代码
- 可以在黑窗口当中使用cd的方式进入到JS代码所在路径,然后使用
node 文件名.js运行 - 可以找到
js文件,在地址栏里面直接敲cmd,然后使用node 文件名.js运行 - 在vscode里面->点击js文件->右键在集成终端中打开,然后使用
node 文件名.js运行
3. nodejs的模块化
nodejs里面每一个js文件都是一个模块,nodejs的开发都需要使用模块化开发
自定义模块
就是我们程序员自己写的js文件
- module是nodejs里面的模块属性
比如
Module {
id: '.', //表示就是模块的编号
path: 'F:\Desktop\JavaScript第20天\代码', //当前这个模块所在的路径
exports: {}, //模块的导出
filename: 'F:\Desktop\JavaScript第20天\代码\02.module.js', //当前文件的完整路径
loaded: false,//当前这个模块是否被加载过
children: [],//当前这个模块的子模块
paths: [
'F:\Desktop\JavaScript第20天\代码\node_modules',
'F:\Desktop\JavaScript第20天\node_modules',
'F:\Desktop\node_modules',
'F:\node_modules'
]
}
-
nodejs的导出
- module.exports=>导出
- exports=>导出
- require("路径")
-
module.exports与exports的区别
- module.exports 是真正的暴露语法
- exports就是module.exports的地址
内置模块
就是我们将node这个软件安装好了之后,就可以直接使用的模块,由nodejs官方提供
-
fs => 文件系统
-
读文件
- 同步读文件 => fs.readFileSync
- 异步读文件 => fs.readFile
-
写文件
- 同步写文件 => fs.writeFileSync
- 异步写文件 => fs.writeFile
-
比如
//内置模块->node官方给我们提供的模块,安装好了nodejs就可以直接使用的模块
/*
导入内置模块fs
const fs = require("fs")
*/
const fs = require("fs")
writeFileSync(文件名,文件的内容) => 同步读文件
fs.writeFileSync("./wenyuan","世上只要妈妈好!")
//writeFile(文件名,文件内容,回调函数) => 异步写文件
//nodejs里面的函数有一个特性,一般提示错误的参数就是函数的第一个参数
fs.writeFile('./abc.txt',"大宝SOD蜜,你值的拥有",(err)=>{
if(err) return console.log(错误了);
console.log("文件写入完毕");
})
//fs.readFilSync('文件名,'编码格式') => 同步读文件
const res = fs.readFileSync('./abc.txt','utf-8')
console.log(res);
//readFile(文件名,编码格式,回调函数) => 异步读文件
fs.readFile("./wenyuan",'utf-8',(err,data)=>{
if(err) return console.log("当前读取有错误")
console.log(data);
})
- path
- path.join => 将路径拼接成相对路径
- path.resolve => 将路径拼接成绝对路径
- path.parse => 解析完整路径
比如
//导入path模块
const path = require("path")
//使用path.join拼接相对路径
//语法: path.join(路径片段1,路径片段2...)
console.log(path.join('a/b/c','e/f/g'));
//使用path.resolve拼接绝对路径 (盘符的根目录,或是是一个网页的地址)
const res = path.resolve("a/b","c/d","e/f")
console.log(res);
//path.parse("解析路径")
const result = path.parse("F:\Desktop\JavaScript第20天\代码\05.内置Path模块\a\b\c\d\e\f.txt")
// {
// root: 'F:\', //路径的根目录
// dir: 'F:\Desktop\JavaScript第20天\代码\05.内置Path模块\a\b\c\d\e', //完整文件名包含路径+文件名
// base: 'f.txt', //文件名
// ext: '.txt', //文件的后缀
// name: 'f' //文件名
// }
console.log(result);
- url
比如
//导入url模块
const url = require("url")
//解析网址
const res = url.parse("http://www.1000phone.com:80/a/b/c/d/e/f?username=admin&password=123456")
console.log(res);
/*
{
protocol: 'http:', //请求协议
slashes: true,
auth: null,
host: 'www.1000phone.com:80', //主机地址 域名+端口号
port: '80', //端口号
hostname: 'www.1000phone.com', //域名
hash: null,
search: '?username=admin&password=123456', //请求参数
query: 'username=admin&password=123456', //请求参数
pathname: '/a/b/c/d/e/f', //路径名称
path: '/a/b/c/d/e/f?username=admin&password=123456',
href: 'http://www.1000phone.com:80/a/b/c/d/e/f?username=admin&password=123456'
}
*/
- http
比如
//我们引入http模块
const http = require("http")
//http://localhost:8080
//搭建一个http服务器
const server = http.createServer((req,res)=>{
/*
req 参数表示请求
res 表示响应
如果要给前端响应一句话 =>res.end("")
访问一个服务器 => 请求协议+IP+端口号
请求协议
file => 本地打开页面
http => 超文本传输协议
https => 比http多了一层套接字
IP地址
一般情况IP地址分为内网与外网
一般情况内网的IP地址是
192.xxx.xxx.xxx
172.xxx.xxx.xxx
10.xxx.xxx.xxx
查看本机IP地址
ipconfig
IP地址,子网掩码,网关
本机Ip地址
localhost
127.0.0.1
*/
console.log("那个前端又来访问我们来了");
//响应给前端一个话
let ip = (req.headers['x-real-ip'] || req.connection.remoteAddress).slice(7);
//解决中文乱码
res.setHeader("content-Type",'text/plain;charset=UTF-8')
res.end("你的IP地址是"+ip)
})
//设置服务器端口号
server.listen(8080)
第三方模块(★)
npm的使用
第三方模块就是第三方机构或者是大牛写一个模块
- npm --version 查看npm的版本
- npm的作用? 下载一切和JS相关的第三方包,npm不需要安装,当我们把nodejs安装好了之后,那么在node安装包里面会自动带npm 注意: 第一次使用的时候,仓库有可能是在国外,那么下载包的时候会比较慢,所以,用
npm config set registry https://registry.npm.taobao.org来修改仓库地址 - npm init 初始化项目的包文件,记录项目一些下载过了的包的文件
- npm init --yes => 一步到位
- npm init -y => 简写
- npm install 包名 下载第三方包 => npm install swiper ,默认下载的包名都是最新版的包名
- npm i 包名 => 简写
- npm uninstall 包名 卸载第三方包
- npm un 包名 => 简写
- npm view 包名 versions 查看可以下载的第三方包里面的所有版本
- npm install 包名@版本号 下载指定的版本
- npm i 包名@版本 => 简写
- npm install 统一下载package.json里面所有记录的包
- npm i => 简写
- npm cache clear -f 清除下包缓存
- nrm 下载包的仓库
- npm install -g nrm => 将nrm下载到本地,如果
npm i -g nrm还是无法下载,那么我们需要下载npm i nrm - npm i -g nrm => npm install -g nrm 简写
- nrm test => 查看可以下载的仓库地址
- nrm use 仓库地址 => 切换仓库
其他的第三方包
- moment 是一个格式化时间的包
-
步骤
- 下载包 => npm i moment
- 导入moment => const moment = require("moment")
- 使用
//1. 下载moment => npm i moment //2. 要使用moment.js => 引入 const moment = require("moment") //3. 翻官网 const res = moment().format('YYYY年MM月DD HH时mm分ss秒'); console.log(res);
JavaScript第21天
回顾
- node的模块化
-
自定义模块
-
导出
- module.exports
- exports
-
导入
- require
-
-
内置模块
- fs => 文件系统
- path > 文件的路径
- url => 地址
- http => 搭建原生服务器的
-
第三方模块
-
npm 的使用
- npm --version
- npm init,npm init --yes,npm init -y
- npm install 包名,npm i 包名
- npm uninstall 包名,npm un 包名
- npm install 包名@版本号,npm i 包名@版本号
- npm install,npm i
- npm cache clear -f
- npm i -g nrm,nrm test,nrm use 地址
- npm view 包名 versions
-
moment => 格式化时间
- YYYY => 年
- MM => 月
- DD => 日
- HH => 时
- mm => 分
- ss => 秒
-
知识点
1. 检测数据类型
- typeof => 一般使用typeof来检测基本数据类型,但是使用typeof检测null,结果为Object
- constructor => 可以检测复杂数据结构(对undefined和null不管用)
- instanceOf => 可以检测谁是谁的实例对象
- Object.prototype.toString.call() => 可以检测任意数据类型
比如
// - typeof => 一般使用typeof来检测基本数据类型,但是使用typeof检测null,结果为Object
console.log(typeof 1);//number
console.log(typeof '2');//string
console.log(typeof null);//object
console.log(typeof {});//object
console.log(typeof []);//object
// - instanceOf => 可以检测谁是谁的实例对象
function Person(){}
// const p = new Person();
//检测p是否是Person的一个实例对象
console.log(p instanceof Person);
console.log(Person instanceof Function);
console.log(Function instanceof Function);
console.log(Object instanceof Function);
console.log(Array instanceof Function);
console.log(RegExp instanceof Function);
console.log(Date instanceof Function);
// - constructor => 可以检测复杂数据结构(对undefined和null不管用)
console.log(Person.prototype.constructor);
console.log(Object.prototype.constructor);
console.log(Array.prototype.constructor);
// - Object.prototype.toString.call() => 可以检测任意数据类型,万能检测
// 是一个字符串,格式如下 => "[object Null]" "[object Number]"
console.log(Object.prototype.toString.call(null));
console.log(Object.prototype.toString.call(1));
console.log(Object.prototype.toString.call('1'));
console.log(Object.prototype.toString.call({}));
console.log(Object.prototype.toString.call([]));
2. express
express基本HTTP搭建的一个服务端框架,常见的nodejs的服务端框架有,express,koa,egg,nest
express的基本使用
- 下载包 npm i express
- 导包 const express = require("express")
- 搭建服务器
比如
//下载包 npm i express
//导入express
const express = require("express")
//启动express
const app = express();
//给服务器配置端口号
app.listen(8080,()=>console.log("启动服务器成功! http://localhost:8080"))
配置基本请求和响应
常见的请求方式有get和post请求
- 配置GET请求
比如
//导入
const express = require("express")
//配置服务器
const app = express()
//接受get请求
//url地址 => http://localhost:8080/login?username=admin&password=123456
app.get("/login",(req,res)=>{
//请求前端请求过来的参数
// { username: '1111111', password: '222222222' }
// console.log("前端接收到了请求",req.query);
// const username = req.query.username
// const password = req.query.password
const {username,password} = req.query;
//解决中文乱码
res.setHeader("content-Type",'text/plain;charset=UTF-8')
if(username == 'admin' && password == '123456'){
//响应给前端
res.end("登录成功!")
}else{
res.end("登录失败!")
}
})
//配置端口号
app.listen(8080,()=>console.log("http://localhost:8080"))
配置POST请求
比如
const express = require("express")
const app = express();
//添加中间件获取post请求
bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({extended:false}))
app.use(bodyParser.json())
//接收客户端请求的post请求方式
app.post("/login",(req,res)=>{
//get请求获取前端(客户端)请求过来的参数 => req.query
//post请求获取前端(客户端)请求过来的参数 => req.body
const {username,password} = req.body //获取不到username和password
console.log(username,password);
//设置响应中文
res.setHeader("content-type","text/plain;charset=utf-8");
// //模拟数据库
if(username == 'admin' && password == '123456'){
res.end("登录成功!")
}else{
res.end("登录失败!")
}
})
app.listen(8080)
GET和POST的区别
- GET请求在URL中,POST请求在请求体当中
- GET请求不安全,POST请求相对安全
- GET请求会缓存,POST请求没有缓存
- GET请求有URL长度限制,POST请求没有URL长度限制
- GET请求会产生一个TCP数据包,POST请求会产生两个TCP数据包
Ajax
a => async => 异步 j => JavaScript => JS a => and x => xml
- from表单和ajax的区别
- form表单提交是同步的,ajax是异步的,同步阻塞,异步非阻塞
- form表单全部刷新,ajax是局部刷新,ajax的用户体验度强
- form表单是前后端不分离的项目(项目组的成员全部都做)加重服务器的压力,ajax是前后端分离的产物(前端做前端的,后端做后端的)
- ajax使用简单,原生JS就可以支持
- ajax的缺点 缺点: 跨域 => 浏览器发送ajax会出现跨域的问题 => 是浏览器的一个安全机制(同源策略)导致的
- 同协议
- 同域名
- 同端口
- 想办法让请求处于同源
- 让服务器开方一个公共资源
express.use(express.static("public"))
- 使用ajax
比如
//发送ajax
//1. 创建一个ajax
const xhr = XMLHttpRequest()
//2. 打开请求
xhr.open("请求的方式 GET/POST","请求接口地址","是否异步")
//注意:如果是post请求,那么需要修改请求头
xhr.setRequestHeader("content-type"."application/x-www-form-urlencoded");
//3. 发送请求
xhr.send()
//4. 获取服务器响应的数据
xhr.onload = function(){
//获取响应的数据
console.log(xhr.responseText);
}
JavaScript第22天
回顾
- express的使用
- form的表单的get请求
- form表单的post请求
- ajax => 跨域(浏览器的安全机制导致的,同协议,同域名,同端口)
- ajax的get请求
- ajax的post请求
- get请求与post请求的区别
知识点
nodemon
我们之前每修改一次服务器,都需要重新启动一下服务器才能让代码生效,我们可以使用nodemon让代码不需要重启,也可以生效
- 下包 => npm i nodemon
- 使用 => 在启动的时候, 直接使用nodemon js文件名
ajax的获取数据的两种形式
- xhr.onload = function(){console.log(xhr.responseText)}
- xhr.onreadyStateChange = function(){ if(xhr.readState == 4 && /^2\d{2}$/.test(res.status)){xhr.responseText} }
比如
const xhr = new XMLHttpRequest();
//使用open
xhr.open("post", "http://localhost:8080/login");
//状态码为0 => 发送成功
//状态码为1 => 配置本次请求成功
//状态码为2 => 浏览器获取到响应
//状态码为3 => 浏览器解析响应的数据
//状态位为4 => 浏览器解析响应成功
xhr.send();
//HTML5提出使用xhr.onload来接收服务的数据
// xhr.onload = function(){
// console.log(xhr.responseText);
// }
//当ajax的状态码发生改变的时候,那么就会触发这个事件
xhr.onreadystatechange = function () {
//获取ajax的状态码
// xhr.readyState === 4 => 表示从服务器获取到数据了
// console.log(xhr.readyState);
// console.log(xhr);
if(xhr.readyState === 4 && /^2\d{2}$/.test(xhr.status)){
console.log(xhr.responseText);
}
}
封装原生的Ajax
JS异常
- 系统异常 我们在编写代码的过程当中,然后代码出错了,写错了,都会报系统的
比如
let a = null;
console.log(a.length); //报一个系统异常
- 自定义异常
比如
//我们自己人为的抛出一个错误
throw new Error("错误提示")
- 处理异常 为什么要处理异常? 当我们编写的代码报错了的时候,那么代码终止运行,我们需要对有可能出现异常的代码进行捕获
- try 尝试捕获
- catch 解决异常
- finally 不管有没有异常,他都执行
比如
console.log(1111111111);
//当执行到这一句话之后,代码有可能会出现异常,会导致后面的代码停止运行
try{
//写在try里面的代码是有可能会出现异常的,如果出现了异常那么代码就会走catch,如果没有出现异常,那么就不会走catch
// throw new Error("我是故意的报错")
console.log("我现在没有异常了");
}catch(err){
//有异常,走这里,没有异常不走
console.log("代码出现了错误,请修复");
}finally{
//不管有没有异常他都执行
console.log("我是善后处理");
}
console.log(2222222222);
HTTP协议
一般传送协议分为两种 http => 默认端口是80 https => 默认端口是443
- 请求行
比如
点击view source查看请求头
POST => 请求头
/login => 请求接口地址
HTTP/1.1 => HTTP版本号
- 请求头
比如
Accept => 接收的数类型
content-type => 将数据交给服务器的数据类型
Host => 主机地址(IP地址+端口号)
Origin => 源地址
- 空行 隔开请求头和请求体
- 请求体 在payload里面
- 响应行
比如
HTTP/1.1 => HTTP版本号
200 => 响应状态码 => 200成功
- 响应体
比如
Date => 服务器响应的时间
Content-Type => 服务器的响应的数据格式
参考地址 : www.cnblogs.com/Listener-wy…
HTTP的状态码
- 100~199 发送成功
- 200~299 发送成功,响应成功
- 300~399 重定向错误
- 400~499 客户端错误
- 500~599 服务器错误
NodeJs的路由
-
URL分析
http://121.89.205.189:3000/api/banner/list- http => 请求协议
- 127.89.205.189 => 服务器IP地址
- 3000 => 端口号
- api => 前台的一级路由
- admin => 后台的一级路由
- banner => 二级路由
- list => 三级路由
数据库
- 关系型数据库 msyql,Oracle,sql server
- 非关系型数据库 MongoDB,redis
- 数据库的安装
-
下载msyql绿色版,Navicat => 解压 => 根着视频弄
-
使用Navicat连接mysql数据库
- 连接名 => localhost
- 主机地址 => localhost
- 端口号 => 3306
-
数据库的了解
- 数据库 => 大库(带地址)
- 数据库 => 仓库
比如
## 添加
## 语法: insert into 表名 value(null,字段1,字段2,字段3....)
insert into student value (null,'李四','男',18,'123745671234',1)
insert into student value (null,'王五','男',18,'123745671234',1)
insert into student value (null,'赵六','男',18,'123745671234',1)
insert into student value (null,'田七','男',18,'123745671234',1)
insert into student value (null,'王八','男',18,'123745671234',1)
insert into student value (null,'文九','男',18,'123745671234',1)
insert into student value (null,'刘十','男',18,'123745671234',1)
## 删除
## 语法: delete from 表名 where id = ?
delete from student where id = 7;
## 修改
## 语法: update 表名 set 字段1 = 值1 , 字段2 = 值2 ... where id = ?
update student set name = '文渊',age = 15 where id = 8;
## 查询
## 语法: select * from 表名
select * from student;
## where条件查询
## select * from student where 条件
select * from student where age = 15;
select * from student where gender = '女'
select * from student where age > 18;
select * from student where age > 18 and age <= 22
select * from student where username = "admin" and `password` = "123456"