diff --git "a/20 \347\237\263\350\211\257\346\266\233/20231207 XMLHttpRequest\345\257\271\350\261\241.md" "b/20 \347\237\263\350\211\257\346\266\233/20231207 XMLHttpRequest\345\257\271\350\261\241.md"
new file mode 100644
index 0000000000000000000000000000000000000000..377fa1b95ae8ed35bf1d004205d749a1e99fa147
--- /dev/null
+++ "b/20 \347\237\263\350\211\257\346\266\233/20231207 XMLHttpRequest\345\257\271\350\261\241.md"
@@ -0,0 +1,63 @@
+#### XMLHttpRequest 对象
+
+使用步骤:
+
+```html
+
+```
+
+#### XMLHttpRequest - 数据提交
+
+通过 XHR 提交用户名和密码,完成注册功能
+
+```html
+
+
+```
+
+#### xhr对象执行收发数据的五种状态:
+
+| 状态码 | 说明 |
+| --- | -------------------------------------------------------------- |
+| 0 | (**未初始化**)未启动 |
+| 1 | (**启动**)已经调用 open(),但尚未调用 send() |
+| 2 | (**发送**)发送状态,已经调用 send(),但尚未接收到响应 |
+| 3 | (**接收**)已经接收到部分响应数据 |
+| 4 | (**完成**)已经接收到全部响应数据,而且已经可以在浏览器中使用了 |
diff --git "a/20 \347\237\263\350\211\257\346\266\233/20231210 HTTP\345\215\217\350\256\256.md" "b/20 \347\237\263\350\211\257\346\266\233/20231210 HTTP\345\215\217\350\256\256.md"
new file mode 100644
index 0000000000000000000000000000000000000000..471d72b3ef5836b2b1ce635ecc5cdb3af8272fd5
--- /dev/null
+++ "b/20 \347\237\263\350\211\257\346\266\233/20231210 HTTP\345\215\217\350\256\256.md"
@@ -0,0 +1,197 @@
+## HTTP 协议
+
+规定了浏览器发送及服务器返回内容的==格式==
+
+**HTTP协议 - 请求报文**:浏览器发送给服务器的内容
+
+组成:请求行、请求头、空行、请求体
+
+**HTTP协议 - 响应报文**:服务器按照 HTTP 协议要求的==格式==,返回给浏览器的==内容==
+
+组成:
+
+- ==响应行(状态行)==:协议、==HTTP 响应状态码==、状态信息
+- ==响应头==:以键值对的格式携带的附加信息,比如:==Content-Type==
+- 空行:分隔响应头,空行之后的是服务器返回的资源
+- ==响应体==:返回的资源
+
+## 作业
+
+```js
+/**
+ * 目标一: 获取接口数据并渲染
+ * 1.1 定义自己的外号
+ * 1.2 通过自己的外号,发送异步请求,获取数据
+ * 1.3 将获取的数据渲染
+ */
+
+// 获取标签元素
+const tbody = document.querySelector('tbody')
+
+// 1.1 定义自己的外号
+const creator = '墨下皆是心酸'
+
+// 因为,添加、删除、编辑后都要渲染一遍,所有分装一个渲染函数
+function getBooksList() {
+ // 1.2 通过自己的外号,发送异步请求,获取数据
+ axios({
+ url: 'https://hmajax.itheima.net/api/books',
+ params: {
+ creator
+ }
+ }).then(result => {
+ // 1.3 将获取的数据渲染
+ // console.log(result.data.data);
+ const list = result.data.data
+ tbody.innerHTML = list.map((item, i) => {
+ // 解构数据
+ const { id, bookname, author, publisher } = item
+ // console.log(id, bookname, author, publisher);
+ return `
+
+ ${i + 1} |
+ ${bookname} |
+ ${author} |
+ ${publisher} |
+
+ 删除
+ 编辑
+ |
+
+ `
+ }).join('')
+ })
+}
+getBooksList()
+
+
+/**
+ * 目标二:添加图书
+ * 2.1 获取添加弹框d对象
+ * 2.2 给保存按钮添加点击事件,收集表单信息,隐藏弹框
+ * 2.3 通过获取的表单内容,发送异步请求
+ * 2.4 清空表单,刷新图书列表
+*/
+
+// 2.1 获取 添加弹框 对象
+const addModalDom = document.querySelector('.add-modal')
+const addModal = new bootstrap.Modal(addModalDom)
+
+// 2.2 给保存按钮添加点击事件,收集表单信息,隐藏弹框
+document.querySelector('.add-btn').addEventListener('click', () => {
+ // 获取添加弹框中的表单对象
+ const addForm = document.querySelector('.add-form')
+ // console.log(addForm);
+ // 使用表单插件,获取表单信息
+ const objBook = serialize(addForm, { hash: true, empty: true })
+ // console.log(objBook);
+ // 2.3 通过获取的表单内容,发送异步请求
+ axios({
+ url: "https://hmajax.itheima.net/api/books",
+ method: 'post',
+ data: {
+ creator,
+ ...objBook
+ }
+ }).then(result => {
+ // 2.4 清空表单,刷新图书列表
+ // console.log(result);
+ // 刷新图书列表
+ getBooksList()
+ // 隐藏 添加弹框
+ addModal.hide()
+ // 清空表单
+ addForm.reset()
+ })
+})
+
+/**
+ * 目标三:删除图书
+ * 3.1 给 tbody 添加点击事件(事件委托)
+ * 3.2 通过自定义属性,向接口发送异步请求,删除图书
+ * 3.3 刷新图书列表
+ */
+
+tbody.addEventListener('click', e => {
+
+ // 判断点击的是不是删除
+ if (e.target.className === 'del') {
+ // 是否删除弹框(提高数据安全性)
+ if (!confirm('你确定要删除吗?')) {
+ return
+ }
+ // console.log('你点击的是删除');
+ // 获得父级身上的自定义属性
+ const id = e.target.parentNode.dataset.id
+
+ // 3.2 通过自定义属性,向接口发送异步请求,删除图书
+ axios({
+ url: 'https://hmajax.itheima.net/api/books/' + id,
+ method: 'delete'
+ }).then(result => {
+ // 3.3 刷新图书列表
+ getBooksList()
+ })
+ }
+})
+
+/**
+ * 目标四:修改图书
+ * 4.1 给 tbody 添加点击事件(事件委托),显示弹框
+ * 4.2 通过 id 发送异步请求,获取当前图书的信息,回显在表单上
+ * 4.3 点击 修改 将修改后的数据提交给异步请求,隐藏弹框,刷新表单页面
+ */
+
+// 获取 编辑弹框对象
+const editModalDOM = document.querySelector('.edit-modal')
+const editModal = new bootstrap.Modal(editModalDOM)
+// 4.1 给 tbody 添加点击事件(事件委托),显示弹框
+tbody.addEventListener('click', e => {
+ // 判断点击的是不是编辑
+ if (e.target.className === 'edit') {
+ // console.log('你点击的是编辑');
+ // 获得父级身上的自定义属性
+ const id = e.target.parentNode.dataset.id
+ // 4.2 通过 id 发送异步请求,获取当前图书的信息,回显在表单上
+ axios({
+ url: 'https://hmajax.itheima.net/api/books/' + id,
+ }).then(result => {
+ // console.log(result.data.data);
+ // 因为,获取到的数据的 key 名刚好是每个表单的 类名
+ // 所以,可以先获取响应数据中的所有 key,遍历回显
+ const bookInfo = result.data.data
+ const keys = Object.keys(bookInfo)
+ // console.log(keys);
+ keys.forEach(key => {
+ document.querySelector(`.edit-form .${key}`).value = bookInfo[key]
+ })
+ // 显示弹框
+ editModal.show()
+ })
+ }
+})
+
+// 获取编辑弹框中的表单对象
+const editForm = document.querySelector('.edit-form')
+// 4.3 点击 修改 将修改后的数据提交给异步请求,隐藏弹框,刷新表单页面
+document.querySelector('.edit-btn').addEventListener('click', () => {
+ // 使用插件获取表单信息,并解构
+ const objBook = serialize(editForm, { hash: true, empty: true })
+ // console.log(objBook);
+ // 将修改后的数据提交给异步请求
+ axios({
+ url: 'https://hmajax.itheima.net/api/books/' + objBook.id,
+ method: 'put',
+ data: {
+ creator,
+ ...objBook
+ }
+ }).then(result => {
+ // console.log(result);
+ // 隐藏弹框
+ editModal.hide()
+ // 刷新图书列表
+ getBooksList()
+ })
+})
+```
diff --git "a/20 \347\237\263\350\211\257\346\266\233/20231212 jQuery\351\242\204\344\271\240.md" "b/20 \347\237\263\350\211\257\346\266\233/20231212 jQuery\351\242\204\344\271\240.md"
new file mode 100644
index 0000000000000000000000000000000000000000..80a571e813dce26a190d5f9f1efe8637943f1d00
--- /dev/null
+++ "b/20 \347\237\263\350\211\257\346\266\233/20231212 jQuery\351\242\204\344\271\240.md"
@@ -0,0 +1,228 @@
+## jQuery
+
+jQuery 是一个JavaScript库
+
+jQuery极大简化JavaScript编程
+
+### jQuery 库特性
+
+jQuery 是一个 JavaScript 函数库。
+
+jQuery 库包含以下特性:
+
+- HTML 元素选取
+- HTML 元素操作
+- CSS 操作
+- HTML 事件函数
+- JavaScript 特效和动画
+- HTML DOM 遍历和修改
+- AJAX
+- Utilities
+
+### 添加 jQuery库
+
+jQuery 库位于一个 JavaScript 文件中,其中包含了所有的 jQuery 函数。
+
+可以通过下面的标记把 jQuery 添加到网页中:
+
+```html
+
+
+
+```
+
+请注意,
+
+```
+
+### 使用 Microsoft 的 CDN
+
+```html
+
+
+
+```
+
+### 使用百度的CDN
+
+
+
+">
+
+
+## jQuery 语法实例
+
+- [$(this).hide()](https://www.w3school.com.cn/tiy/t.asp?f=jquery_hide_this)
+ 演示 jQuery hide() 函数,隐藏当前的 HTML 元素。
+
+- [$("#test").hide()](https://www.w3school.com.cn/tiy/t.asp?f=jquery_hide_id)
+ 演示 jQuery hide() 函数,隐藏 id="test" 的元素。
+
+- [$("p").hide()](https://www.w3school.com.cn/tiy/t.asp?f=jquery_hide_p)
+ 演示 jQuery hide() 函数,隐藏所有 元素。
+
+- [$(".test").hide()](https://www.w3school.com.cn/tiy/t.asp?f=jquery_hide_class)
+ 演示 jQuery hide() 函数,隐藏所有 class="test" 的元素。
+
+## jQuery 语法
+
+jQuery 语法是为 HTML 元素的选取编制的,可以对元素执行某些操作。
+
+基础语法是:*$(selector).action()*
+
+- 美元符号定义 jQuery
+- 选择符(selector)“查询”和“查找” HTML 元素
+- jQuery 的 action() 执行对元素的操作
+
+### 示例
+
+$(this).hide() - 隐藏当前元素
+
+$("p").hide() - 隐藏所有段落
+
+$(".test").hide() - 隐藏所有 class="test" 的所有元素
+
+$("#test").hide() - 隐藏所有 id="test" 的元素
+
+**提示:**jQuery 使用的语法是 XPath 与 CSS 选择器语法的组合。在本教程接下来的章节,您将学习到更多有关选择器的语法。
+
+关键点是学习 jQuery 选择器是如何准确地选取您希望应用效果的元素。
+
+jQuery 元素选择器和属性选择器允许您通过标签名、属性名或内容对 HTML 元素进行选择。
+
+选择器允许您对 HTML 元素组或单个元素进行操作。
+
+在 HTML DOM 术语中:
+
+选择器允许您对 DOM 元素组或单个 DOM 节点进行操作。
+
+## jQuery 元素选择器
+
+jQuery 使用 CSS 选择器来选取 HTML 元素。
+
+$("p") 选取
元素。
+
+$("p.intro") 选取所有 class="intro" 的
元素。
+
+$("p#demo") 选取所有 id="demo" 的
元素。
+
+## jQuery 事件函数
+
+jQuery 事件处理方法是 jQuery 中的核心函数。
+
+事件处理程序指的是当 HTML 中发生某些事件时所调用的方法。术语由事件“触发”(或“激发”)经常会被使用。
+
+通常会把 jQuery 代码放到
部分的事件处理方法中:
+
+### 实例
+
+```html
+
+
+
+
+
+
+
+ This is a heading
+ This is a paragraph.
+ This is another paragraph.
+
+
+
+
+```
+
+## 单独文件中的函数
+
+如果您的网站包含许多页面,并且您希望您的 jQuery 函数易于维护,那么请把您的 jQuery 函数放到独立的 .js 文件中。
+
+当我们在教程中演示 jQuery 时,会将函数直接添加到 部分中。不过,把它们放到一个单独的文件中会更好,就像这样(通过 src 属性来引用文件):
+
+### 实例
+
+```html
+
+
+
+
+```
+
+## jQuery 名称冲突
+
+jQuery 使用 $ 符号作为 jQuery 的简介方式。
+
+某些其他 JavaScript 库中的函数(比如 Prototype)同样使用 $ 符号。
+
+jQuery 使用名为 noConflict() 的方法来解决该问题。
+
+*var jq=jQuery.noConflict()*,帮助您使用自己的名称(比如 jq)来代替 $ 符号。
+
+## axios 封装
+
+```html
+
+```
diff --git "a/20 \347\237\263\350\211\257\346\266\233/20231213 jQuery\347\254\224\350\256\260.md" "b/20 \347\237\263\350\211\257\346\266\233/20231213 jQuery\347\254\224\350\256\260.md"
new file mode 100644
index 0000000000000000000000000000000000000000..65d800520d263418d9d5599f9b8ccfe04759c8a5
--- /dev/null
+++ "b/20 \347\237\263\350\211\257\346\266\233/20231213 jQuery\347\254\224\350\256\260.md"
@@ -0,0 +1,354 @@
+# jQuery
+
+
+
+### 1 关于原生js对象(DOM对象)和jQuery对象的误区:
+
+```js
+1.javascript对象又称dom对象,是指使用javascript操作的对象,
+例如:
+ document.getElementById("id值")方法 获得的对象就是dom对象
+ document.querySelectorAll("")
+2.jquery对象是指使用jquery操作的对象,
+例如:
+ $("选择器");
+3.关于javascript对象与jquery对象之间的转换
+ 因为jquery对象默认是集合或者数组,所以可以使用数组或者集合的取值方法
+
+ dom->jquery: $(dom对象);
+ jquery->dom: jquery对象[0]或者jquery对象.get(0)
+
+4.dom对象只能使用javascript方法,jquery对象只能使用jquery方法
+
+```
+
+### 2 jQuery 是第三方库,使用前要先引入
+
+```js
+
+```
+
+### 3 选择器
+
+```js
+我是一个标题
+我是有id的p段落
+
+```
+
+### 4 jQuery事件
+
+***1.js事件回顾***
+
+```js
+javascript事件
+ 1.以on开头,比如鼠标单击事件onclick,onchange,onready,onblur,oninput,
+ javascript事件一般通过注册事件句柄实现绑定
+ 2.js事件通常是一个函数,通过事件驱动执行,js函数内部可以使用jquery方式进行选中元素
+ 3.位置:js事件函数写在标签内,ready()外
+
+ 定义onclick事件函数
+
+
+
+ function jsClick(){
+ alert("js鼠标单击事件...");
+ // 使用jquery选中选中其它元素
+ $("#myText").css("background-color","red");
+ }
+
+```
+
+***2.jQuery事件***
+
+```js
+/*
+ jquery事件:
+ 1.没有on,直接以js事件去掉相应的on即可
+ 2.位置:ready()内
+ ready(function){
+ $("jquery选择器").事件类型(function(){
+ 事件体...
+ })
+ }
+ */
+ $(document).ready(function(){
+ // 鼠标单击事件
+ $("#myButton").click(function(){
+ $("#myText").css("background-color","red");
+ })
+ })// ready()结束标记
+
+```
+
+***3.常见的jQuery事件***
+
+```js
+ 鼠标事件
+ -click:鼠标单击
+ -- dblclick 双击
+ -mouseover:鼠标进入(进入子元素也会触发)
+ -mouseout:鼠标离开(离开子元素也会触发)
+ -focus:元素获得焦点
+ -blur:元素失去焦点
+
+ 键盘事件
+ -keydown:键盘按下事件,从上到下的过程
+ -keyup:松开键盘
+ -keypress:键盘被按到最底部
+ 绑定事件
+ 1.形式 addEventLister("事件名",函数)
+ $("jquery选择器").bind("事件名",函数)
+ 好处:更加通用
+ 2.多组事件绑定:
+ $("jquery选择器").bind({"事件名":函数,"事件名":函数,"事件名":函数,})
+
+
+显示效果:
+ -show(参数1,参数2):显示
+ -hide(参数1,参数2):隐藏
+
+
+ -fadeIn(参数1,参数2):淡入
+ -slideDown(参数1,参数2):展开
+ 关于参数:参数1表示速度,可选值有slow、fast、normal
+ 参数2表示回调函数
+ 隐藏效果:
+
+ -fadeOut(参数1,参数2):淡出
+ -slideUp(参数1,参数2):拉升 (压缩)
+
+ $("p").one( "click", fun...) //one 绑定一个一次性的事件处理函数
+ $("p").unbind( "click" ) //解绑一个事件
+
+```
+
+### 5 jQuery操作DOM对象
+
+***1.jQuery操作样式***
+
+```js
+i.设置css
+ 获取对象的某个样式的属性对应的值jquery对象.css("属性名") style
+ 设置单个样式:jquery对象.css("属性名","属性值")
+ 设置多个样式:jquery对象.css({"属性名":"属性值",属性名":"属性值,属性名":"属性值})
+classList.add .remove toggle .contains
+ii.追加或移出预定义样式
+ addClass("xxx"):追加单个属性
+ addClass("xxx xxx xxx"):追加多个属性
+ removeClass("xxx"):移除单个属性
+ removeClass("xxx xxx xxx"):移除多个属性
+ toggleClass("xxx xxx xxx"):轮换属性
+ 可以在style标签预定义一些样式,通过add或remove方法进行追加或移除属性
+
+```
+
+***2.jQuery操作内容***
+
+```js
+i.jquery操作DOM之内容
+ 取值(文本):
+ html():获取值,获取的是元素的内容,包括元素内部的各种标签 innerHTML
+ text():获取值,只获取内容值,不包括各种标签 innerText
+ 赋值:
+ html("xxx"):先渲染,后显示 innerHTML= xxx
+ text("xxx"):原封不动显示,不进行渲染 innerText = xxx
+
+ 表单的:
+ val():获取属性值 .value
+ val("xxx"):赋值 .value =xxx
+
+
+ii.jquery工厂$()的作用
+ -$("jquery选择器"):jquery选择器:
+ -$(document):类型转换,DOM对象转换为jquery对象
+ -$(html字符串):创建节点
+
+ 插入节点:
+ -内部插入:
+ $("A").append($("B")):将B插入到A尾部
+ $("A").prepend($("B")):将B插入到A头部
+
+ 外部插入:
+ $("A").before($("B")):将B插入到A前面(外部)
+ $("A").after($("B")):将B插入到A后面(外部)
+
+ 替换节点
+ -$("A").replaceWith($("B")):用B替换A
+
+ 删除节点
+ -remove():彻底删除,包括节点关联的一切
+ -empty():只删除节点内容
+
+ 克隆节点
+ -clone(true|false)
+ 其中true代表克隆节点的同时克隆节点所绑定的事件,false代表只克隆节点
+
+iii.属性操作
+ attr("属性名"):根据属性名获取属性值
+ attr("属性名","属性值"):设置单个属性值
+ attr({"属性名":"属性值","属性名":"属性值","属性名":"属性值"}):设置多个属性值
+ removeAttr("属性名"):删除属性值
+
+iiii.jquery获取集合和遍历集合
+ 获取子节点集合:$("选择器").children("过滤")
+
+
+ 同辈集合:
+ -next():下一个
+ -prev():前一个
+ -sublings():左右
+
+ 前辈集合:
+ -parent():父辈
+ -parents():祖先
+
+iiiii.集合遍历:
+ $("选择器").each(function(index,element){
+
+ })
+ 其中参数index表示当前是第几个元素,element代表当前元素,注意element是dom对象,必须进行jquery工厂进行转换
+
+```
+
+### 6 jQuery表单验证(后端必会知识)
+
+***1.关于表单验证***
+表单验证是java后端程序员必须要掌握的前端技能,表单验证减轻了前端对服务器的访问量。
+表单验证三大步:
+-获取要校验的元素值(选择器)
+-要触发校验的事件或方法:blur或是submit,或change
+-验证:采用字符串处理方法或是正则表达式
+***2.采用字符串验证表单(传统模式)***
+————————————————
+
+```js
+// 采用字符串处理方法对表单进行校验
+ $("#uname").blur(function(){
+ if($(this).val().length<2 || $(this).val().length>6){
+ if($(this).val().length==0 || $(this).val()==""){
+ $("#nameTip").css("display","none");
+ }else{
+ $("#nameTip").css("display","inline");
+ }
+ }else{
+ $("#nameTip").css("display","none");
+ }
+ })
+```
+
+***3.采用正则表达式验证表单***
+————————————————
+
+```js
+// 使用正则验证邮箱
+ $("#uemail").blur(function(){
+ var $email = $(this).val();
+ // 定义正则规则
+ var reg = /^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/;
+ // 调用方法校验
+ if(!reg.test($email)){
+ if($email=="" || $email.length==0){
+ $("#emailTip").css("display","none");
+ }else{
+ $("#emailTip").css("display","inline");
+ }
+ }else{
+ $("#emailTip").css("display","none");
+ }
+ })
+```
+
+### 7 对象访问
+
+```js
+$.trim(对象) //去除字符串两端的空格
+$.map(data,(item)=>{})
+
+$.each(对象) //遍历一个数组或对象,for循环
+
+$.inArray(对象) //返回一个值在数组中的索引位置,不存在返回-1
+
+$.grep() //返回数组中符合某种标准的元素
+
+$.extend() //将多个对象,合并到第一个对象
+
+$.makeArray() //将对象转化为数组
+
+$.type() //判断对象的类别(函数对象、日期对象、数组对象、正则对象等等
+
+$.isArray() //判断某个参数是否为数组
+
+$.isEmptyObject() //判断某个对象是否为空(不含有任何属性)
+
+$.isFunction() //判断某个参数是否为函数
+
+$.isPlainObject() //判断某个参数是否为用"{}"或"new Object"建立的对象
+
+$.support() //判断浏览器是否支持某个特性
+```
diff --git "a/20 \347\237\263\350\211\257\346\266\233/20231214 jQuery\344\275\234\344\270\232.md" "b/20 \347\237\263\350\211\257\346\266\233/20231214 jQuery\344\275\234\344\270\232.md"
new file mode 100644
index 0000000000000000000000000000000000000000..1ef01c0a620c86c7ede08322369b8c67c92718e5
--- /dev/null
+++ "b/20 \347\237\263\350\211\257\346\266\233/20231214 jQuery\344\275\234\344\270\232.md"
@@ -0,0 +1,248 @@
+### tab栏切换
+
+```js
+// 1. 给 ul 添加点击事件(事件委托)
+$('ul').on('click','a',function(){
+ // 先删除 li里的 active
+ $('a.active').removeClass('active')
+ // 自己添加 active 类
+ $(this).addClass('active')
+
+ // 先删除 有item类 里的 active
+ $('.item.active').removeClass('active')
+ // 获取当前点击的 a 的索引
+ const id = $('a').index($(this))
+ // 根据 id 指定某个div添加 active 类
+ $(`.item:eq(${id})`).addClass('active')
+})
+```
+
+### 轮播图
+
+```js
+// 定义起始值
+let i = 0
+// 1. 给 > 按钮 添加点击事件
+$('.next').bind('click', () => {
+ // 判断 i 是否大于数组长度
+ i = i >= sliderData.length - 1 ? 0 : i + 1
+ // 调用切换函数
+ toggleData()
+})
+
+// 2. 给 < 按钮添加点击事件
+$('.prev').bind('click', () => {
+ // 判断 i 是否大于数组长度
+ i = i <= 0 ? sliderData.length - 1 : i - 1
+ // 调用切换函数
+ toggleData()
+})
+
+// 3. 添加定时器
+let time = setInterval(() => {
+ $('.next').click()
+}, 1000)
+
+// 4. 添加 鼠标经过、移出事件
+$('.slider-wrapper,.slider-footer').bind({
+ 'mouseover': () => {
+ // console.log(111);
+ // 暂停定时器
+ clearInterval(time)
+ },
+ 'mouseout': () => {
+ // console.log(222);
+ // 开启定时器
+ time = setInterval(() => {
+ $('.next').click()
+ }, 1000)
+ }
+})
+
+// 分装一个切换(图片、标题、背景颜色、小圆点)的类
+function toggleData() {
+ // 切换图片
+ $('.slider-wrapper img').attr('src', sliderData[i].url)
+ // 切换标题
+ $('.slider-footer p').html(sliderData[i].title)
+ // 切换标题背景颜色
+ $('.slider-footer').css('background', sliderData[i].color)
+ // 切换小圆点
+ // 先删除 active 类
+ $('.slider-indicator li.active').removeClass('active')
+ // 自己添加 active 类
+ $(`.slider-indicator li:eq(${i})`).addClass('active')
+}
+```
+
+### 图书管理系统
+
+```js
+/**
+ * 目标一: 获取接口数据并渲染
+ * 1.1 定义自己的外号
+ * 1.2 通过自己的外号,发送异步请求,获取数据
+ * 1.3 将获取的数据渲染
+ */
+
+// 1.1 定义自己的外号
+const creator = '墨下皆是心酸'
+
+// 因为,添加、删除、编辑后都要渲染一遍,所有分装一个渲染函数
+function getBooksList() {
+ // 1.2 通过自己的外号,发送异步请求,获取数据
+ $.ajax({
+ url: 'https://hmajax.itheima.net/api/books',
+ data: {
+ creator
+ },
+ success: (result) => {
+ const data = result.data
+ // 将获取的数据渲染到页面上
+ const htmlStr = $.map(data, (item, index) => {
+ // 解构数据
+ const { id, bookname, author, publisher } = item
+ return `
+
+ ${index + 1} |
+ ${bookname} |
+ ${author} |
+ ${publisher} |
+
+ 删除
+ 编辑
+ |
+
+ `
+ }).join('')
+ $('tbody').html(htmlStr)
+ }
+ })
+}
+getBooksList()
+
+
+/**
+ * 目标二:添加图书
+ * 2.1 获取添加弹框d对象
+ * 2.2 给保存按钮添加点击事件,收集表单信息,隐藏弹框
+ * 2.3 通过获取的表单内容,发送异步请求
+ * 2.4 清空表单,刷新图书列表
+*/
+
+// 2.1 获取 添加弹框 对象
+const addModal = new bootstrap.Modal($('.add-modal'))
+
+// 2.2 给保存按钮添加点击事件,收集表单信息,隐藏弹框
+$('.add-btn').bind('click', () => {
+ // 获取 添加弹框 中的表单对象
+ const addForm = $('.add-form')[0]
+ // 使用表单插件,获取表单信息
+ const objBook = serialize(addForm, { hash: true, empty: true })
+ console.log(objBook);
+ // 2.3 通过获取的表单内容,发送异步请求
+ $.ajax({
+ url: 'https://hmajax.itheima.net/api/books',
+ type: 'post',
+ data: {
+ ...objBook,
+ creator
+ },
+ success: () => {
+ // 2.4 清空表单,刷新图书列表
+ // console.log(result);
+ // 刷新图书列表
+ getBooksList()
+ // 隐藏 添加弹框
+ addModal.hide()
+ // 清空表单
+ addForm.reset()
+ }
+ })
+})
+
+
+/**
+ * 目标三:删除图书
+ * 3.1 给 tbody 添加点击事件(事件委托)
+ * 3.2 通过自定义属性,向接口发送异步请求,删除图书
+ * 3.3 刷新图书列表
+ */
+
+$('tbody').on('click', '.del', function () {
+ // 是否删除弹框(提高数据安全性)
+ if (confirm('你确定要删除吗?')) {
+ // 获得父级身上的自定义属性
+ const id = $(this).parent().data('id')
+ // console.log(id);
+ // 3.2 通过自定义属性,向接口发送异步请求,删除图书
+ $.ajax({
+ url: `https://hmajax.itheima.net/api/books/${id}`,
+ type: 'delete',
+ success: () => {
+ // 3.3 刷新图书列表
+ getBooksList()
+ }
+ })
+ }
+})
+
+
+/**
+ * 目标四:修改图书
+ * 4.1 给 tbody 添加点击事件(事件委托),显示弹框
+ * 4.2 通过 id 发送异步请求,获取当前图书的信息,回显在表单上
+ * 4.3 点击 修改 将修改后的数据提交给异步请求,隐藏弹框,刷新表单页面
+ */
+
+
+// 获取 编辑弹框对象
+const editModal = new bootstrap.Modal($('.edit-modal'))
+// 4.1 给 tbody 添加点击事件(事件委托),显示弹框
+$('tbody').on('click', '.edit', function () {
+ // 获得父级身上的自定义属性
+ const id = $(this).parent().data('id')
+ // 4.2 通过 id 发送异步请求,获取当前图书的信息,回显在表单上
+ $.ajax({
+ url: `https://hmajax.itheima.net/api/books/${id}`,
+ success: result => {
+ // 因为,获取到的数据的 key 名刚好是每个表单的 类名
+ // 所以,可以先获取响应数据中的所有 key,遍历回显
+ const bookInfo = result.data
+ // console.log(bookInfo);
+ const keys = Object.keys(bookInfo)
+ // console.log(keys);
+ keys.forEach(key => {
+ document.querySelector(`.edit-form .${key}`).value = bookInfo[key]
+ })
+ // 显示弹框
+ editModal.show()
+ }
+ })
+})
+
+
+// 获取编辑弹框中的表单对象
+const editForm = $('.edit-form')[0]
+// 4.3 点击 修改 将修改后的数据提交给异步请求,隐藏弹框,刷新表单页面
+$('.edit-btn').bind('click', () => {
+ // 使用插件获取表单信息,并解构
+ const objBook = serialize(editForm, { hash: true, empty: true })
+ // console.log(objBook);
+ // 将修改后的数据提交给异步请求
+ $.ajax({
+ url: `https://hmajax.itheima.net/api/books/${objBook.id}`,
+ type: 'put',
+ data: {
+ ...objBook,
+ creator
+ },
+ success: result => {
+ // 隐藏弹框
+ editModal.hide()
+ // 刷新图书列表
+ getBooksList()
+ }
+ })
+})
+```
diff --git "a/20 \347\237\263\350\211\257\346\266\233/20231214 js\347\254\224\350\256\260.md" "b/20 \347\237\263\350\211\257\346\266\233/20231214 js\347\254\224\350\256\260.md"
new file mode 100644
index 0000000000000000000000000000000000000000..4c5ead29b83050d36994d61087a2fb46267a5310
--- /dev/null
+++ "b/20 \347\237\263\350\211\257\346\266\233/20231214 js\347\254\224\350\256\260.md"
@@ -0,0 +1,2436 @@
+## 第一单元
+
+## 一. JS基础知识
+
+### 1. JS的书写方式:行内、内嵌、外部
+
+#### 行内式:写在body里
+
+```javascript
+
+```
+
+#### 内嵌式:写在head里
+
+```javascript
+
+```
+
+#### 外部式:新建一个my.JS文件
+
+```javas
+alert('你好Js')
+```
+
+### 2. JS的输入与输出语句
+
+| 方法 | 说明 |
+| ------------------ | ---------------------- |
+| alert('内容') | 浏览器弹出警示框 |
+| console.log('内容') | 浏览器控制台打印输入信息(给程序员测试用的) |
+| prompt('内容') | 浏览器弹出输入框,用户可以输入 |
+| document.write(内容) | 浏览器打印出该内容 |
+
+#### 3. 变量
+
+```javascript
+//1.声明变量
+let age;
+//2.赋值
+age = 18;
+//3.输出结果
+console.log(age);
+//4.变量的初始化
+let name = '张三';
+//5.用户输入并输出
+let name =prompt('请输入你的名字');
+alert(name);
+//6.声明多个变量
+let age = 18, //前面是0就是八进制,0x十六进制
+ name = '张三',
+ gz = 2000;
+```
+
+#### 4. 数据类型
+
+##### (1) 数字型:number
+
+infinity,代表无穷大,大于任何数值
+
+-infinty,代表无穷小,小于任何数值
+
+NaN,Not a number,代表一个非数值
+
+isNaN() 判断是否为非数字
+
+##### (2) 字符串型:String
+
+字符串引号嵌套 (外双内单,外单内双)
+
+```javascript
+let str1 ='我是"高富帅"程序猿';
+let str1 ="我是'高富帅'程序猿";
+alert(str1.length); //显示str1的长度
+//模板字符串 外面用`` 里面${变量名}
+let age = 20;
+document.write(`我今年${age}岁了`);
+```
+
+字符串转义符:\n 换行 \\ \ 斜杆 \t 缩进 \b 空格
+
+##### (3) 简单数据类型
+
+布尔(true,false) undefined NaN null
+
+```javascript
+var flag = true;
+var flag = false;
+console.log(flag+1); //true 参与计算当1来看
+console.log(flag+1); //false 参与计算当0来看
+//如果一个变量声明未赋值,默认就是 undefined 未定义数据类型
+var str;
+var a1 = undefined;
+console.log(a1+'张三'); //undefined张三
+console.log(a1+1); //NaN undefined和数字相加最后结果是NaN
+// null 空值
+var space = null;
+console.log(space+'张三');//null张三
+console.log(space+1); //1
+```
+
+##### (4)获取变量数据类型
+
+```javascript
+let num = 18;
+console.log(typeof num); //number
+//特殊
+let a1 = null;
+console.log(typeof null); //object (对象)
+```
+
+#### 5. 常量
+
+概念:使用 const 声明的变量称为"常量"
+
+使用场景:当某个变量永远不会改变的时候,就可以使用 const 来声明,而不用 let
+
+例:
+
+```javascript
+const PI =3.14; //声明的时候必须赋值,声明后不允许改变
+```
+
+#### 6. 数据的转换
+
+##### 1. 隐式转换
+
+某些运算符执行时,系统内部自动将数据类型进行转换,这种转换为隐式转换
+
+规则:
+
+ +号两边只要有一个字符串,都会把另一个转成字符串
+
+ 除了+以外的算术运算符 比如 - * / 等都会把数据转成数字类型
+
+缺点:转换类型不明确,靠经验才能总结
+
+```javascript
+console.log(1+1) //2
+console.log(1+'pink') //1pink
+console.log('2'-'2') //0
+console.log(+'123') //转换为数字123
+```
+
+##### 2. 显式转换
+
+编写程序时过度依靠系统内部是隐式转换是不严禁的,因为隐式转换规律并不清晰,大多是靠经验总结的规律。为了避免隐式转换带来的问题,通常根逻辑需要对数据进行显示转换。
+
+转换为数字型
+
+**Number(数据)**
+
+ 转换数字类型
+
+ 如果该里的数据为非数字,将显示NaN(不是一个数字)
+
+ NaN也是number类型的数据,代表非数字
+
+**parselnt(数据)**
+
+ 只保留整数
+
+**parseFloat(数据)**
+
+ 可以保留小数
+
+#### 7. 比较运算符
+
+ > < >= <= ==
+
+特殊:
+
+ === 左右两边是否类型和值都相等 (全等)
+
+ !== 左右两边是否不全等(不全等)
+
+```javascript
+console.log(2 == '2') //隐式转换 只判断值,不考虑数据类型 true
+console.log(2 === '2') //判断值和数据类型都一样才行 false
+console.log(NaN === NaN) //NaN 不等于任何人,包括自己 false
+console.log(2 !== '2') //与 === 相反 true
+```
+
+字符串的比较:通过ASCII码表
+
+ 从左往右依次比较
+
+ 如果第一位一样再比较第二位,以此类推
+
+```javascript
+console.log('a'<'b') //true
+console.log('aa'<'ab') //true
+console.log('aa'<'aac') //true
+```
+
+总结:NaN 不等于任何人,包括自己。
+
+ 尽量不要比较小数,因为小数有精度问题(将小数转为整数比较再转回小数)
+
+ 不同类型之间比较会发生隐式转换
+
+#### 8. 逻辑运算符
+
+! > && > ||
+
+```javascript
+let d = !false || true && false //true
+```
+
+**补充:所有数字都是True,只有0为False**
+
+ **所有字符串都是True,只有空字符串(' ') 为False**
+
+#### 9. 三元运算符
+
+利用三元运算符补零:大于10前面补零(01,02,03...)
+
+```javascript
+let num = prompt("请输入一个数字:")
+num = num < 10 ? 0 + num : num
+alert(num)
+```
+
+### 10. 数组
+
+ **数组中可以存放任意类型的数据**
+
+**数组的定义:**
+
+```javascript
+//方式一:
+let arr =[1,'p',true,"张三"] //常用
+//方式二:
+let arr = new Array(1,'p',true,"张三") //了解即可
+```
+
+**数组的增、删、改、查:**
+
+```javascript
+let arr =['red']
+//增,可一次性增加多个
+arr.push('pink','green') //尾部插入 ['red','pink','green'] 并表示数组的新长度(3)
+arr.unshift('black') //开头插入 ['black','red','pink','green']
+//删,可重复使用
+arr.pop() //删除数组的最后一个元素
+arr.shift() //删除数组的第一个元素
+arr.splice(1,2) //格式:arr.splice(起始位置,删除几个元素) 如果不指名删几个,默认删除后面所有
+//改
+arr[0]='gray'
+//查
+document.write(arr[0])
+```
+
+例:筛选出数组中大于10的数据
+
+```javascript
+ let arr =[1,12,56,48,5,98,4]
+ let newarr =[]
+ for(let i =0; i=10){
+ newarr.push(arr[i])
+ }
+ }
+ document.write(newarr)
+```
+
+##### 数组排序函数
+
+```javascript
+let arr = [9,23,45,12,6,28]
+arr.sort(function(a,b){
+ // return a - b 升序
+ // return b - a 降序
+})
+```
+
+## 第二单元
+
+### 1.函数:抽取-分装 (将相同的逻辑代码“包裹”成一个方法)
+
+```javascript
+function sheet99(){
+ // 分装的内容
+}
+// 调用方法
+sheet99()
+```
+
+1. 有参函数
+
+```javascript
+// 求某个范围的累加和
+function gatSun(start,end){
+ let sum = 0
+ for(let i = start,i <= end,i++){
+ sum = sum +i
+ }
+ console.log(sum)
+}
+// 调用方法
+gatSun(1,50)
+gatSun(50,100)
+```
+
+2. 默认参数 (让程序更严谨)
+
+```javascript
+function getSum(x = 0,y = 0){
+ document.write(x + y)
+}
+// 调用方法
+getSum(1,50) // 有参覆盖值
+getSum() // 无参使用默认值0
+// 实参可以是变量
+let x = 20
+let y = 30
+getSum(x,y)
+```
+
+3. 函数的返回值
+
+```javascript
+function getSum(x = 0,y = 0){
+ return x + y
+}
+// 调用方法
+let sum = getSum(1,2)
+console.log(sum)
+```
+
+4. 匿名函数(没有函数名的函数)
+
+```javascript
+// 函数表达式
+// 将一个匿名函数赋值给一个变量
+let fn = function (x,y){
+ console.log(x + y)
+}
+fn(1,2)
+```
+
+匿名函数 与 具名函数 的不同:.具名函数的调用可以写到任何地方,而匿名函数不行,因为匿名函数需先定义在使用
+
+5. 立即执行函数(不需要调用就可以执行)
+
+```javascript
+// 语法1:(function(){})();
+// 语法1:(function(){}());
+(function(){
+ console.log(20)
+})(); // 多个立即执行函数之间需要分号隔开
+(function(){
+ console.log(30)
+})();
+// 立即执行函数本质是需要调用的
+(function(x,y){
+ console.log(x + y)
+})(1,2); // 这里的 小括号(1,2) 就表示方法的调用
+```
+
+### 2. 对象
+
+对象:在 javascript 里对象是一种数据类型,==无序的集合==
+
+对象是由==属性==和==方法==组成的
+
+语法:
+
+```javascript
+let 对象名 = {}
+//例:
+let obj = {
+ uname: '张三',
+ age: 18,
+ gender:'男'
+}
+// 打印对象
+console.log(obj) // 显示一个集合
+```
+
+对象的增、删、改、查
+
+```javascript
+let obj = {
+ gName: '小米10青春版', //多个属性或方法之间用逗号隔开
+ num: '152623024',
+ weight: '0.55kg',
+ address: '中国'
+}
+// 查
+console.log(obj.name) //方法一
+console.log(obj['name']) //方法二
+// 改
+obj.weight = '0.25kg'
+// 增
+obj.price = 1999
+// 删
+delete obj.weight
+```
+
+对象里的方法 (对象里的函数,也就是方法)
+
+```javascript
+let myObj = {
+ uname: '张三',
+ // 方法
+ getSum: function(x,y){
+ console.log(x + y);
+ }
+}
+// 调用对象里的方法
+myObj.getSum(1,2)
+```
+
+遍历对象(获取对象中的每一个值)
+
+```javascript
+let student = {
+ uname: '张三',
+ age: 18,
+ sex: '男'
+}
+for(let k in student){
+// k相当于获取对象的属性名,获取的是字符串型的
+ console.log(student[k]); //表示获取属性值,用查询的第二种方法
+}
+```
+
+遍历数组对象
+
+```javascript
+ //定义一个存放多个学生对象的数组
+let students = [
+ { uname: '小明', age: 18, sex: '男' },
+ { uname: '小红', age: 19, sex: '女' },
+ { uname: '小刚', age: 20, sex: '男' },
+ { uname: '小利', age: 22, sex: '女' }
+]
+//遍历获取根据索引获取每个对象
+for (let i = 0; i < students.length; i++) {
+ let index = students[i]
+ //根据对象获取属性值
+ for (let k in index) {
+ console.log(index[k]);
+ }
+}
+```
+
+内置对象 - Math
+
+```javascript
+//向上取整
+console.log(Math.ceil(1.1)); //2
+console.log(Math.ceil(1.9)); //2
+//向下取整
+console.log(Math.floor(1.1)); //1
+console.log(Math.floor(1.9)); //1
+//四舍五入
+console.log(Math.round(1.49)); //1
+console.log(Math.round(1.5)); //2
+console.log(Math.round(-1.5)); //-1
+console.log(Math.round(-1.51)); //-2
+//pow:幂运算 abs:绝对值 sqrt:求平方根
+```
+
+内置函数 - 随机数 random() [0,1)
+
+```javascript
+// 0 ~ 10 之间的整数
+console.log(Math.floor(Math.random() * 11))
+// N ~ M 之间的随机数
+Math.floor(Math.random() * (M - N +1) + N)
+// 获取一个指定范围的随机整数
+ let getRd = function(N,M){
+ return Math.floor(Math.random() * (M - N +1)+N)
+}
+console.log(getRd(5,10));
+```
+
+### 3. APIs
+
+#### 1.作用和分类
+
+作用:就是使用 JS 去操作 HTML 和浏览器
+
+分类:==DOM (文档对象模型)==,==BOM (浏览器对象模型)==
+
+#### 2. 什么是DOM
+
+DOM是用来显现以及与任意 HTML 或 XML 文档交互的 API
+
+DOM是浏览器提供的一套专门用来==操作网页内容==的功能
+
+作用:开发网页内容特效和实现用户交互
+
+#### 3.什么是DOM树
+
+将 HTML 文档以树状结构直观的表现出来,称为文档树或 DOM 树
+
+作用 :==文档树直观的体现了标签与标签之间的关系==
+
+#### 4.什么是DOM对象
+
+DOM对象:浏览器根据 HTML 标签生成的JS对象
+
+ 所有的标签属性都可以在这个对象上面找到
+
+ 修改这个对象的属性会自动映射到标签身上
+
+DOM的核心思想:==把网页内容当做对象来处理==
+
+#### 5.document 是什么
+
+是网页中最大的一个对象,网页所以内容都在 document 里面
+
+#### 6.根据CSS选择器来获取DOM元素
+
+语法1:选择匹配的第一个元素
+
+```javascript
+ document.querySelector('css选择器')
+```
+
+例:
+
+```html
+测试
+
+```
+
+语法2:选择匹配的多个元素
+
+```javascript
+ document.querySelectorAll('css选择器')
+```
+
+例:
+
+```html
+
+
+```
+
+循环遍历(伪数组)或取其每一个对象
+
+```html
+
+
+```
+
+#### 7.操作元素内容
+
+元素:**innerText** 属性 (显示纯文本,不解析标签)
+
+```html
+看看我可不可以变
+
+```
+
+元素:**innerHTML** 属性 (解析标签)
+
+```html
+看看我可不可以变
+
+```
+
+扩充
+
+```javascript
+body{
+ background : url(背景图片地址) no-repeat top center/cover;
+ // 取消背景图片平铺,居中全屏
+}
+```
+
+#### 8.操作元素样式属性
+
+1.通过**style**属性修改样式
+
+```html
+
+
+
+
+```
+
+2.通过类名修改样式
+
+```html
+
+
+123
+
+```
+
+3.通过 **classList** 操作类控制 css
+
+为了解决 className 容易覆盖以前的类名,我们可以通过 classList 方式追加和删除类名
+
+**add()**:添加类 **remove()**:删除类 **toggle()**:切换类,有就删除没有就添加
+
+**contains()**:看看有没有包含某个类,有返回 true ,没有就返回 false
+
+```html
+
+
+abc
+
+```
+
+4.修改表单属性
+
+```html
+
+
+
+
+```
+
+5.自定义属性
+
+标准属性:标签天生自带的属性,如:class id title
+
+自定义属性:
+
+ 在html5中推出来了专门的 **data-自定义属性**,在标签一律用**data-开头**
+
+ 在DOM对象上一律以**dataset**对象方式获取
+
+```html
+
+ 盒子
+//获取自定义属性
+
+```
+
+#### 9.定时器
+
+语法:**setInterval(执行语句,秒数)**
+
+```html
+
+```
+
+#### 10.事件
+
+事件:事件是在编程时系统内发生的动作或者发生的事件,如:用户单击按钮
+
+**1.事件监听**:就是程序检查是否有事件产生,一旦有事件触发,就立即调用一个函数做出响应
+
+语法:**元素对象 . addEventListener(‘事件类型’,要执行的函数)**
+
+```html
+
+
+```
+
+**2.事件类型**
+
+1.鼠标事件:**click**(鼠标点击) **mouseenter**(鼠标经过) **mouseleave**(鼠标离开)
+
+2.焦点事件:**focus**(获取焦点) **blur**(失去焦点)
+
+3.键盘事件:**keydown**(键盘按下触发) **keyup**(键盘抬起触发)
+
+4.文本事件:**input**(用户输入事件)
+
+5.**change**事件:当鼠标离开了表单,并且表单值发生了变化时触发
+
+**3.事件对象**
+
+事件对象:也是个对象,这个对象里有事件触发时的相关信息
+
+例如:鼠标点击事件中,事件对象就存了鼠标点在那个位置等信息
+
+使用场景:可以判断用户按下哪个键,或哪个元素,从而做相应的操作
+
+语法:事件对象在,事件函数里的第一个参数
+
+```javascript
+btn.addEventListener('click',function(e){
+ alert('点我干嘛!')
+ })
+```
+
+**事件对象常用属性**
+
+**type**:获取当前的事件类型
+
+**clientx / clienty**:获取光标相对于浏览器可见窗口左上角的位置(x,y)
+
+**offsetx / offsety**:获取光标相对于当前DOM元素左上角的位置
+
+**key**:获取用户按下键盘的值
+
+```html
+
+
+```
+
+**4.环境对象**
+
+环境对象:指的是函数内部特殊的**变量 this**,他代表 着当前函数运行时所处的环境
+
+作用:弄清楚 this 的指向。 **谁调用,this就是谁**
+
+比如:按钮添加了事件,那么this就是这个按钮(指向这个按钮)
+
+**5.回调函数**
+
+如果将函数 A 做为参数传递给函数 B 时,我们称函数 A 为回调函数
+
+```javascript
+//场景一
+function fn(){
+ log('我是回调函数')
+}
+setInterval(fn,1000) //表示每一秒回头调用一下fn函数
+//场景二
+box.addEventListener('click',function(){
+ log('我是回调函数')
+}) //表示每点击一次,回头调用函数
+```
+
+#### 11.事件流
+
+事件流指的是事件完整执行过程中的流程路径
+
+过程:事件捕获 => 事件目标阶段 => 事件冒泡 整个完整的过程就是事件流
+
+
+
+**事件捕获**
+
+概念:从DOM的根元素开始去执行对应的事件(从外到里)
+
+格式:
+
+```html
+DOM.addEventListener(事件类型,事件处理函数,是否使用捕获)
+```
+
+**事件冒泡**
+
+概念:当一个元素的事件被触发时,同样的事件将会在该元素的所有祖先元素中依次被触发,这个过程被称为事件冒泡
+
+事件冒泡的必要性:如果没有冒泡给大盒子注册点击事件,点击的是里面的小盒子,会导致大盒子的点击无法执行
+
+**阻止冒泡**
+
+```javascript
+事件对象.stopPropagation()
+e.stopPropagation()
+```
+
+**阻止元素默认行为**
+
+```javascript
+e.preventDefault() //阻止提交事件,或a连接跳转
+```
+
+**事件移除解绑**
+
+```javascript
+//添加点击事件
+事件对象.addEventListener('click',fn)
+//移除点击事件
+事件对象.removeEventListener('click',fn)
+```
+
+**事件委托**
+
+事件委托:给父元素注册事件,当我们触发子元素的时候,会冒泡到父元素身上,从而触发父元素的事件
+
+优点:减少注册次数,提高程序性能
+
+```html
+
+
+ - 第一个小li
+ - 第二个小li
+ - 第三个小li
+ - 第四个小li
+ - 第五个小li
+ 我不用变色
+
+
+```
+
+#### 12.其他事件
+
+1.页面加载事件
+
+事件名:**load**
+
+加载外部资源(如图片、外联css、javaScript等)加载完毕时触发的事件
+
+```javascript
+// 在页面加载完之后,回头调用这个函数,写在head里的script
+标签对象.addEventListener('load',function(){
+ //执行的代码
+})
+```
+
+事件名:**DOMContentLoaded**(比 load 加载速度更快)
+
+当初始的 HTML 文档被完全加载和解析完成之后,该事件被触发,而无需等待样式表、图像等完全加载
+
+```javascript
+//无需等待样式表、图像等完全加载
+document.addEventListener('DOMContentLoaded',function(){
+ //执行的代码
+})
+```
+
+2.页面滚动事件
+
+事件名:**scroll**
+
+滚动条在滚动的时候持续触发的事件
+
+场景:很多网页需要检测用户把页面滚动到某个区域后做一些处理,比如固定导航栏,返回顶部
+
+```javascript
+// 监听整个页面滚动
+window.addEventListener('scroll',function(){
+ // 执行的代码
+})
+```
+
+页面滚动事件 - 获取位置
+
+关键字:**scrollLeft 和 scrollTop** (属性)
+
+获取 div 滚动的长度 (px)
+
+```html
+
+```
+
+获取页面滚动的长度
+
+```javascript
+//页面滚动事件
+ window.addEventListener('scroll',function(){
+ //获取 HTML(页面)滚动的长度
+ const n = document.documentElement.scrollTop
+ //判断,如果页面滚动100就显示div
+ if(n >=100){
+ div.style.display = 'block'
+ }else{
+ div.style.display = 'none'
+ }
+ })
+//document.documentElement.scrollTop = 800 修改页面的滚动长度为800
+```
+
+3.页面尺寸事件
+
+会在窗口尺寸改变的时候触发事件:**resize**
+
+```javascript
+window.addEventListener('resize',function(){
+ //执行代码
+}
+```
+
+获取页面宽高:**clientWidth 和 clientHeight**
+
+获取元素的可见部分宽高==(不包含边框,margin,滚动条等)==
+
+```javascript
+const diw = document.querySelector('div')
+// 通过js获取div的宽度
+log(div.clientWidth)
+```
+
+检测屏幕宽度
+
+```javascript
+window.addEventListener('resize',function(){
+ let w = document.documentElement.clientWidth
+ log(w)
+ )
+```
+
+获取元素尺寸位置
+
+获取宽高:获取元素的自身宽高、==包含元素自身设置的宽高、padding、border==
+
+ 关键字:**offsetWidth 和 offsetHeight**
+
+ 注意:获取的是可视宽高,如果盒子是隐藏的,获取结果是0
+
+获取位置:获取元素距离自己定位父级元素的左、右距离
+
+ 关键字:**offsetLeft 和 offsetTop** 注意是只读属性
+
+#### 总结
+
+| 属性 | 作用 | 说明 |
+| -------------------------- | -------------------- | --------------------------------- |
+| scrollLeft 和 scrollTop | 被卷去的头部和左侧 | 配合页面滚动来用,==可读写== |
+| clientWidth 和 clientHeight | 获取元素宽度和高度 | 不包含边框,margin,滚动条,用于js获取元素的大小,只读属性 |
+| offsetWidth 和 offsetHeight | 获取元素宽度和高度 | ==包含边框,margin,滚动条,只读== |
+| offsetLeft 和 offsetTop | 获取元素距离自己定位父级元素的左、上距离 | 获取元素位置的时候使用,只读 |
+
+#### 补充:
+
+```javascript
+//1.让滚动条丝滑的滚动
+html{
+ scroll-behavior: smooth
+}
+//2.重置表单
+表单.reset()
+//3.弹出有确认和取消的警示框,返回 true 或 false
+confirm('你确定要删除这条数据吗?')
+```
+
+#### 13.日期对象
+
+日期对象:用来表示时间的对象,可以得到当前系统的时间
+
+实例化:在代码中发现了new关键字,一般将这个操作称为实例化
+
+1.获取当前时间
+
+```javascript
+const date = new Date()
+```
+
+2.获取指定时间
+
+```javascript
+const date = new Date('2023-10-2 20:12:25')
+```
+
+3.日期对象方法
+
+| 方法 | 作用 | 说明 |
+| ------------- | --------- | -------------------- |
+| getFullYear() | 获取年份 | 获取四位年份 |
+| getMonth() | 获取月份 | 取值为 0 ~ 11 ==要手动加一== |
+| getDate() | 获取月份中的第几天 | 不同月份取值也不同 |
+| getDay() | 获取星期 | 取值为 0~ 6 ==星期天是0== |
+| getHours() | 获取小时 | 取值为 0~ 23 |
+| getMinutes() | 获取分钟 | 取值为 0~ 59 |
+| getSeconds() | 获取秒 | 取值为 0~ 59 |
+
+```javascript
+const date = new Date()
+div.innerHTML = date.toLocaleString() // 2023/10/2 20:33:26
+```
+
+4.时间戳(毫秒数)
+
+使用场景:如果计算倒计时效果,就需要借助于时间戳完成
+
+算法:将来的时间戳 - 现在的时间戳 = 剩余时间毫秒数
+
+获取时间戳:现在 距 1970年01月01号,已经过去了多少毫秒
+
+```javascript
+//1. getTime()方法
+const date = new Date()
+log(date.getTime())
+//2. +new Date() 隐式转换
+log(+new Date())
+//3. Date.now() 无须实例化,只能得到当前时间戳,前两种可以返回指定时间的时间戳
+log(Date.now())
+//获取指定时间的时间戳
+log(+new Date('2023-10-2 23:30:00'))
+```
+
+**毫秒转换公式**:
+
+```javascript
+d = parseInt(总秒数 / 60 / 60 / 24); //计算天数
+h = parseInt(总秒数 / 60 / 60 % 24); //计算小时
+m = parseInt(总秒数 / 60 % 60); //计算分钟
+s = parseInt(总秒数 % 60); //计算秒数
+```
+
+#### 14.节点操作
+
+**DOM节点**:DOM树里每一个内容都称之为节点
+
+节点类型
+
+ 元素节点:所有的标签,比如:body、div, HTML 是根节点
+
+ 属性节点:所有的属性,比如:href、id、class
+
+ 文本节点:所有的文本
+
+**查找节点**
+
+父节点查找:**parentNode** 属性,返回最近一级的父节点,找不到返回 null
+
+```Html
+
+
+```
+
+子节点查找
+
+ childNodes:获取所有子节点、包括文本节点(空格、换行)、注释节点等
+
+ **children** 属性(重点):仅获得所有元素节点,返回一个伪数组
+
+```Html
+
+
+```
+
+兄弟关系查找
+
+ 下一个兄弟节点:**nextElementSibling** 属性
+
+ 上一个兄弟节点:**previousElementSibling** 属性
+
+```html
+
+
+```
+
+**增加节点**
+
+创建节点:**createElement**
+
+ 创建一个新的网页元素,再添加到页面内,一般先创建节点,在插入节点
+
+追加节点:将创建的节点插入到某个父元素中
+
+ 插入到父元素的最后一个子元素:**appendChild(要插入的元素)**
+
+ 插入到某个子元素的前面:**insertBefore(要插入的元素,在哪个元素前面)**
+
+```Html
+
+
+```
+
+克隆节点:**cloneNode(布尔值)**
+
+ 复制一个原节点,把复制的节点放入到指定的元素内部
+
+ 若为 true,则代表克隆时会包含后代节点一起克隆(克隆所有)
+
+ 若为 false,则代表克隆时不包含后代节点,默认为 false(只克隆标签,里面的内容不克隆)
+
+```html
+
+
+```
+
+**删除节点**
+
+要删除元素必须==通过父元素删除==,如果不存在父子关系则删除失败
+
+语法:父元素**.removeChild**(要删除的元素)
+
+```Html
+
+
+```
+
+#### 15.M端事件
+
+**移动端触摸事件 touch**
+
+| 触摸touch事件 | 说明 |
+| ---------- | ---------------- |
+| touchstart | 手指触摸到一个DOM元素时触发 |
+| touchmove | 手指在一个DOM元素上滑动时触发 |
+| touchend | 手指从一个DOM元素上移开时触发 |
+
+#### 16.Window 对象
+
+**1. DOM(Browser Object Model) 是浏览器对象模型**
+
+ window对象是一个全局对象,是JavaScript中的顶级对象
+
+ 像 document、alert()、log()都是window的属性基本BOM的属性都是window的
+
+ 所有通过var定义在全局作用域中的变量、函数都会变成window对象的属性和方法
+
+**2. 定时器 - 延时函数**
+
+ 延迟执行的函数:**setTimeout**,只执行一次
+
+ 语法:**setTimeout (回调函数,等待的毫秒数)**
+
+ 清除延时函数:
+
+```javascript
+let timer = setTimeout (回调函数,等待的毫秒数)
+clerTimeout(timer)
+```
+
+**3. JS执行机制**
+
+ 单线程,同一时间只能做一件事,所有任务排队执行,会遇到堵塞的可能
+
+ 为了解决这个问题,HTML5 提出 Web Worker 标准,允许JS脚本创建多个线程,于是有了**同步**和**异步**
+
+ **同步**:所有的任务都要按照顺序执行 如:等开水开了再去切菜
+
+ **异步**:执行任务遇见堵塞时,在堵塞的同时,处理其他的任务 如:在烧开水的同时,去切菜
+
+ 耗时少的为同步任务,耗时多的为异步任务,**先执行完同步任务,在回头去执行异步任务**
+
+ 同步任务交个JS处理,异步任务交个浏览器处理
+
+ 主线程不断获取任务并执行任务,这种机制被称为**事件循环(event loop)**
+
+**4. location** :数据类型是对象,它拆分并保存了 URL 地址的各个组成部分
+
+ 常用属性和方法:
+
+ **href** 属性获取完整的 URL 地址,对其赋值时用于地址的跳转
+
+ **search** 属性获取地址中携带的参数,符号 ?后面部分
+
+ **hash** 属性获取地址中的哈希值,符合 # 后面部分
+
+```javascript
+location.href = 'http://www.baidu.com'
+location.search
+location.hash
+```
+
+ **reload()** 方法用来刷新当前页面,传入参数true时表示强制刷新
+
+```html
+
+
+```
+
+**5. navigator** 对象:该对象下记录了浏览器自身的相关信息
+
+ 通过 **userAgent** 检测浏览器的版本及平台
+
+**6. history** 数据类型对象
+
+ 主要管理历史记录,该对象与浏览器地址栏的操作相对应,如:前进、后退、历史记录等
+
+ 常用属性和方法:
+
+| history对象方法 | 作用 |
+| ----------- | -------------------------------- |
+| back() | 后退功能 |
+| forward() | 前进功能 |
+| go(参数) | 前进后退功能,参数如果是1 前进1个页面,如果是-1后退一个页面 |
+
+#### 17. 本地存储
+
+- 数据存储在用户浏览器中
+- 设置、读取方便、甚至**页面刷新不丢失数据**
+
+**本地存储分类 - localStorage**
+
+ 作用:可以将**数据永久存储在本地**(用户的电脑),除非手动删除
+
+ 特性:可以多窗口(页面)共享(同一浏览器可以共享),**以键值对的形式存储使用**
+
+```html
+
+```
+
+**本地存储分类 - sessionStorage**
+
+ 特性:生命周期为关闭浏览器窗口,数据消失 (其他用法跟上面一样)
+
+**存储复杂数据类型**
+
+ 解决:需要将复杂数据类型转换成 JSON 字符串,在存储到本地
+
+```html
+
+```
+
+**字符串拼接新思路**:(效果更高,开发常用的写法)
+
+ 利用 **map()** 和 **join()** 数组方法实现字符串拼接
+
+ **map() 方法**:可以遍历数组处理数据,并且返回新的数组
+
+ **join() 方法**:用于把数组中的所有元素转换成一个字符串
+
+```html
+
+```
+
+#### 18.正则表达式
+
+ 正则表达式:是用于匹配字符串中字符组合的模式,通常用来查找、替换
+
+ 正则表达式的使用:**test()** **exec()**
+
+```html
+
+```
+
+**元字符**
+
+ 是一些具有特殊含义的字符
+
+ 如:普通字符:abcdefg …. 元字符:[a-z]
+
+**1.边界符**:用来提示字符所在的位置
+
+| 边界符 | 说明 |
+| ----- | --------------- |
+| **^** | 表示匹配行首的文本(以谁开始) |
+| **$** | 表示匹配行尾的文本(以谁结束) |
+
+ 如果 ^ 和 $ 在一起,表示必须是精确匹配,只能是这两个边界符夹着的字
+
+**2.量词**:设定某个模式出现的次数
+
+| 量词 | 说明 |
+| --------- | ---------------------- |
+| ***** | 重复零次或多次(>=0) |
+| **+** | 重复一次或多次(>=1) |
+| **?** | 重复零次或一次(0 \|\|1) |
+| **{n}** | 必须重复 n 次 |
+| **{n,}** | 重复 n 次或更多次(>=n) |
+| **{n,m}** | 重复 n 到 m 次(>=n && <=m) |
+
+**3.元字符**:[abc] 匹配字符集合,只要包括其中一个就行,只选1个
+
+**字符类**
+
+ 使用连字符 - 表示一个范围
+
+ 如:[a-z] 表示 a 到 z 26个英文字母都可以
+
+ [a-zA-z] 表示大小写英文字母都可以
+
+ [0-9] 表示 0 - 9 的数字都可以
+
+ [ ] 里面加上 ^ 表示取反符号 如:[ ^ a-z] 除了小写字母以外的字符
+ **.** 匹配换行符之外的任何单个字符
+
+**预定类**:指的是 某些常见模式的简写方式
+
+| 预定类 | 说明 |
+| --- | ------------------------------------- |
+| \d | 匹配 0-9 之间的任一数字,相当于 [0-9] |
+| \D | 匹配所有 0-9 以外的字符,相当于 [ ^0-9] |
+| \w | 匹配任意的字母、数字和下划线,相当于 [A-Za-z0-9_] |
+| \W | 除所有字母、数字和下划线以外的字符,相当于 [ ^A-Za-z0-9_] |
+| \s | 匹配空格(包括换行符、制表符、空格符等),相当于 [\t\r\n\v\f] |
+| \S | 匹配非空格的字符,相当于 [ ^\t\r\n\v\f] |
+
+ **4.修饰符**
+
+ 修饰符约束正则执行的某些细节行为,如是否区分大小写、是否支持多行匹配
+
+ 语法: /表达式/修饰符
+
+- i 是单词 ignore 的缩写,正则匹配时字母不区分大小写
+- g 是单词 global 的缩写,匹配所有满足正则表达式的结果
+
+```html
+
+```
+
+### 第三单元
+
+#### 1. 作用域
+
+规定了变量能够被访问的 “范围”
+
+**局部作用域**
+
+- 函数作用域:
+
+ - 在函数内部声明的变量,外部无法直接访问
+ - 函数的参数也是函数内部的局部变量
+ - 不同函数内部声明的变量无法互相访问
+ - 函数执行完毕后,函数内部的变量实际被清空了
+
+- 块作用域:
+
+ - 使用 {} 包裹的代码为代码块,其内部声明的变量,外部无法访问
+ - let 声明的变量会产生块作用域,var 不会产生块作用域
+ - const 声明的常量也会产生块作用域
+ - 不同代码块之间的变量无法互相访问
+
+**全局作用域**
+
+script 标签和 .js文件的【最外层】就是全局作用域
+
+**作用域链**
+
+本质上是底层的==变量查找机制==
+
+- 在函数执行时,会==优先查找当前==函数作用域中的变量
+- 如果当前作用域查不到则会依次==逐级查找父级作用域==直到全局作用域
+
+总结:
+
+- 嵌套关系的作用域串联起来形成2了作用域链
+
+- 相同作用域链中按着从小到大的规则查找变量
+
+- 子作用域能够访问父作用域,父级作用域无法访问子级作用域
+ **垃圾回收机制**(生命周期)
+
+- 内存分配:当我们声明变量、函数、对象的时候,系统会自动为它们分配内存
+
+- 内存使用:即读写内存,也就是使用变量、函数等
+
+- 内存回收:使用完毕,由==垃圾回收器==自动回收不再使用的内存
+
+说明:全局变量一般在关闭页面后回收,局部变量不用了就会自动回收
+
+内存泄漏:程序中分配的==内存==由于某种原因程序==未释放==或==无法释放==叫做==内存泄漏==
+
+**闭包**
+
+概念:一个函数对周围状态的引用捆绑在一起,内层函数中访问到其外层函数的作用域
+
+简单理解:闭包 = 内层函数 + 外层函数的变量 ==可能会有内存泄漏的问题==
+
+```javascript
+//内部使用外部
+function outer(){
+ const a = 10
+ function fn(){
+ log(a) // 内部函数使用外部变量
+ }
+ fn()
+}
+outer()
+```
+
+```javascript
+//外部使用内部
+function outer(){
+ const a = 10
+ function fn(){
+ log(a)
+ }
+ return fn //将内部函数,返回给外部函数
+}
+const fun = outer() //拿变量接收内部函数
+fun() //调用内部函数
+```
+
+实现数据的私有:防止 i 被修改,如果 i 定义在函数外面,全局变量容易被改,不安全
+
+```javascript
+function fn(){
+ let i = 1
+ function fun(){
+ i++
+ log(`函数被调用了${i}次`)
+ }
+ return fun
+}
+const result = fn()
+result() // 2
+result() // 3
+```
+
+**变量提升**
+
+```javascript
+//1.把所有 var 声明的变量提升到 当前作用域的最前面
+//2.只提升变量声明,不提升变量赋值
+log(num+'件') // undefined件
+var num = 10
+log(num) // 10
+
+//相当于
+var num
+log(num+'件')
+num = 10
+log(num)
+```
+
+#### 2. 函数进阶
+
+ **函数提升**
+
+```javascript
+//1. 会把所有函数声明提升到当前作用域的最前面
+//2. 只提升函数声明,不提升函数调用
+fn()
+function fn(){
+ log('函数提升')
+}
+```
+
+总结:
+
+- 函数提升能够使函数的声明调用更灵活
+- 函数表达式不存在提升
+- 函数提升出现在当前作用域当中
+
+**函数参数**
+
+- **动态参数:arguments** 是函数内部内置的伪数组,它包含调用函数时传入的所有实参
+
+```javascript
+function getSum(){
+ let sum = 0
+ for(let i = 0;i <= arguments.length;i++){
+ sum = sum + arguments[i]
+ }
+ log(sum) // 35
+}
+getSum(5,10,20)
+```
+
+总结:
+
+- arguments 是个伪数组,只存在于函数中
+- arguments 的作用是动态获取函数的实参
+- 可以通过 for 循环依次得到传递过来的实参
+
+**剩余参数**(类似java的可变参数 …num)
+
+- 允许我们将一个不定数量的参数表示为一个**真数组**(常用)
+
+```javascript
+// 表示前两个实参被a和b形参接收,后面的实参被arr数组接收
+function getSum(a,b,...arr){
+ log(arr)
+}
+getSum(1,2) // []
+getSum(1,2,3,4,5) // [3,4,5]
+```
+
+**展开运算符**:可以展开数组
+
+```javascript
+const arr1 = [1,2,3]
+log(...arr) // 1 2 3 ...arr1 === 1,2,3
+//1.求数组中的最大值
+//log(Math.max(1,2,3))
+log(Math.max(...arr1)) // 3
+//2.合并数组
+const arr2 = [4,5,6]
+const arr =[...arr1, ...arr2]
+log(arr) // [1,2,3,4,5,6]
+```
+
+**箭头函数(重要)**
+
+- 需要匿名函数或函数表达式的地方,更适用箭头函数,可以简化代码
+
+基本语法
+
+```javascript
+/*
+const fn = function(){
+ log(123)
+}
+*/
+//1.箭头函数,基本语法
+const fn = () => {
+ log(123)
+}
+//2.只有一个形参的时候,可以省略小括号
+const fn = x => {
+ return x + x
+}
+fn(1)
+//3.只有一行执行代码的时候,大括号和 return
+const fn = x => x + x
+log(fn(1)) //2
+//4.箭头函数可以直接返回一个对象
+const fn = (uname) => ({uname:uname})
+fn('pink老师')
+```
+
+箭头函数参数:没有 arguments 动态参数,但是有==剩余参数== …args
+
+箭头函数 this:不会创建自己的 this,它只会从作用域链的上一层找
+
+```javascript
+const obj = {
+ uname:'pink老师'
+ sayHi:function(){
+ let i = 10
+ const count = () => {
+ log(this) //此时this指向obj
+ }
+ count()
+ }
+}
+obj.sayHi
+```
+
+#### 3. 解构赋值
+
+- 将数组的单元值快速批量,赋值给一系列变量的简洁语法
+
+**数组解构**
+
+```javascript
+// 将数组中的值依次赋值给变量
+const arr = [100,60,80]
+// const max = arr[0]
+// const min = arr[1]
+// const avg = arr[2]
+const [max,min,avg] = arr
+// 典型应用,交换2个变量
+let a = 1
+// 立即执行函数、数组开头时,前面有代码要加分号,不然会和前面语句连在一起执行
+let b = 2;
+[b,a] = [a,b]
+log(a,b) // 2 1
+```
+
+```javascript
+//1. 变量多,单元值少,变量undefined
+const [a,b,c,d] = [1,2,3]
+//2. 变量少,单元格多
+const [a,b] = [1,2,3]
+//3. 剩余参数,变量少,单元值多
+const [a,b, ...c] = [1,2,3,4,5]
+//4. 防止 undefined 传递(给变量赋默认值)
+const [a = 0,b = 0] = []
+const [a = 0,b = 0] = [1,2] //覆盖默认值
+```
+
+**对象解构**
+
+```javascript
+const obj = {
+ uname: 'pink老师',
+ age: 18
+}
+//1. 对象解构语法
+//要求:变量名必须与属性名一致
+// const {uname,age} = obj
+const {uname,age} = {uname: 'pink老师',age: 18}
+log(uname,age)
+// 解构的变量名,可以重新该值
+const {uname: username,age} = {uname: 'pink老师',age: 18}
+log(username,age)
+//2. 数组对象解构
+const pig = [
+ {
+ uname: '佩奇',
+ age: 6
+ }
+]
+const [{uname,age}] = pig
+//3. 多级对象解构
+//要求:指名是哪个对象
+const pig = {
+ uname: '佩奇',
+ family: {
+ mother: '猪妈妈'
+ father: '猪爸爸'
+ brother: '乔治'
+ },
+ age: 6
+}
+const {uname,family: {mother,father,brother},age} = pig
+```
+
+**forEach 方法(适合遍历数组对象)**
+
+与 map 方法 语法相同,但是 map 会返回一个新的数组,forEach 不会
+
+```javascript
+遍历的数组.forEach(function(当前数组元素,当前元素索引){
+ //函数体
+})
+```
+
+**filter 方法(重点)**
+
+主要使用场景:==筛选数组符合条件的元素==,并返回筛选之后的新数组
+
+```javascript
+const arr = [10,20,30]
+const newArr = arr.filter(function(item,index){
+ return item >= 20
+})
+log(newArr) // [20,30]
+// 箭头函数写法
+const newArr = arr.filter(item => item >= 20)
+```
+
+#### 4.深入对象
+
+**构造函数**:是一种特殊的函数,主要用来初始化对象
+
+使用场景:==多个对象有相同属性,封装成一个构造函数==
+
+```javascript
+// 创建一个构造函数,首字母要大写
+function Pig(uname,age){
+ this.uname = uname
+ this.age = age
+}
+// 创建对象
+const p1 = new Pig('佩奇',6)
+const p2 = new Pig('乔治',4)
+```
+
+实例成员:通过构造函数创建的对象称之为实例对象,==实例对象中==的属性和方法称之为==实例成员==(实例属性和实例方法)
+
+- 为构造函数传入参数,创建结构相同但值不同的对象
+- 构造函数创建的实例对象彼此独立互不影响
+
+静态成员:构造函数的属性和方法被称为静态成员(静态属性和静态方法)
+
+- 静态成员只能构造函数访问
+- 静态方法中 this 指向构造函数
+
+```javascript
+// 静态成员
+function Pig(name){
+ this.name = name
+}
+Pig.eyes = 2 // 静态属性
+Pig.sayHi = function(){
+ log(this)
+}
+Pig.sayHi() // 指向构造函数
+log(Pig.eyes) // 2
+```
+
+#### 5.内置构造函数
+
+其实字符串。数值。布尔等基本数据类型也都有专门的构造函数,称为包装类型
+
+**Object**
+
+object 是内置的构造函数,用于创建普通对象
+
+三个常用静态方法:
+
+- **Object.keys** 获取对象中的所有属性(键),返回数组
+- **Object.values** 获取对象中的所有属性值(值),返回数组
+- **Object.assign** 常用于对象拷贝(合并对象)
+
+```javascript
+const o = {uname: 'pink',age: 18}
+log(Object.keys(o)) // [uname,age]
+log(Object.values(o)) // ['pink',18]
+// 拷贝
+const oo = {}
+Object.assign(oo,o) // 将 o 对象拷贝给 oo 对象
+// 给对象追加属性
+Object.assign(o,{sex: '男'})
+log(o) // [uname: 'pink',age: 18,sex: '男']
+```
+
+**Array**
+
+Array 是内置构造函数,用于创建数组
+
+常用实例方法:
+
+| 方法 | 作用 | 说明 |
+| ----------- | ---- | ------------------------------- |
+| **forEach** | 遍历数组 | 不返回数组,经常用于==查找遍历数组元素== |
+| **filter** | 过滤数组 | ==返回新数组==,返回==筛选满足条件==的数组元素 |
+| **map** | 迭代数组 | ==放回新数组==,返回==处理之后==的数组元素 |
+| **reduce** | 累计器 | 返回累计处理的结果,经常用于求和等 |
+| **find** | 查找元素 | 返回符合条件的第一个数组元素值,没则有返回undefined |
+| **every** | 检查数组 | 检查数组中所有元素,都满足某个条件,返回 true或false |
+| **some** | 检查数组 | 检查数组中所有元素,有元素满足条件,返回 true或false |
+| **concat** | 合并数组 | 合并两个数组,返回一个新数组 |
+| **sort** | 排序数组 | 对原数组单元值进行排序 |
+| **reverse** | 反转数组 | 将数组反转 |
+
+```javascript
+// 数组 reduce 方法
+const arr = [1,5,8]
+//1. 没有初始值
+const total = arr.reduce(function(prev,current){
+ return prev + current //上一次的值 + 当前的值
+})
+log(total) // 14
+//2. 有初始值
+const total = arr.reduce(function(prev,current){
+ return prev + current //上一次的值 + 当前的值
+}.10)
+log(total) // 24
+//3. 箭头函数写法
+const total = arr.reduce((prev,current) => prev + current, 10)
+```
+
+案例:有一个员工数组对象,计算当月支出多少薪资
+
+```javascript
+const arr =[
+ {
+ uname: '张三',
+ salary: 10000
+ }, {
+ uname: '李四',
+ salary: 10000
+ }, {
+ uname: '王五',
+ salary: 10000
+ }
+]
+//一定要有初始值,否则默认第一个对象为初始值
+const total = arr.reduce((prev,current) => prev + current.salary, 0)
+log(total) // 30000
+```
+
+静态方法 **Array.from(数组)** 将伪数组转换为真数组
+
+```javascript
+const lis = document.querySelectorAll('ul li')
+const liArr = Array.from(lis)
+```
+
+**String**
+
+常见实例方法1:
+
+| 方法 | 说明 |
+| ---------------------------- | -------------------------- |
+| **split(’分隔符’)** | 将字符串转换为数组,和 join() 相反 |
+| **substring(起始索引,结束索引)** | 截取字符串 |
+| **startswith(检查字符串,检测开始索引)** | 检测是否以某字符开头,返回布尔值,endwith相反 |
+| **includes(搜索的字符串,位置索引)** | 判断一个字符串是否包含某个字符 |
+
+**Number**
+
+ **toFixed()** 设置保留小数位的长度
+
+```javascript
+const num = 10.923
+log(num.toFixed(1)) //10.9
+log(num.toFixed(2)) //10.92
+log(num.toFixed()) //11 四舍五入
+```
+
+#### 7.深入面向对象
+
+**1. 编程思想**
+
+面向过程:就是按照我们分析好的步骤去解决问题(蛋炒饭)
+
+- 优点:性能比面向对象高
+- 缺点:没有面向对象易维护、易复用、易扩展
+
+面向对象:是以对象功能来划分问题,而不是步骤(盖浇饭)
+
+- 优点:易维护、易复用、易扩展、更加灵活
+- 缺点:性能比面向过程低
+
+**2. 原型**
+
+目的:为了解决构造函数浪费内存
+
+**原型对象:prototype**
+
+- ==每个构造函数都有一个 prototype 属性==,指向另一个函数,称为原型对象
+- 可以把那些不变的方法,直接定义在 prototype 对象上,实现对象的实例==共享==这些方法
+- ==构造函数和原型对象中的 this 都指向 实例化的对象==
+
+```javascript
+//1. 创建构造函数
+function Star(uname,age){
+ this.uname = uname
+ this.age= age
+ /*
+ 函数方法写在这里面,每 new 一次都会生成一个新的函数(浪费内存)
+ this.sing = function(){
+ log('唱歌')
+ }
+ */
+}
+//2. 利用 prototype 属性,解决浪费内存问题
+// 将函数方法定义在 prototype 对象上,实现共享函数
+Star.prototype.sing = function(){
+ log('唱歌')
+}
+//3. 创建实例对象
+const ldh = new Star('刘德华',55)
+const zxy = new Star('张学友',58)
+ldh.sing()
+zxy.sing()
+log(ldh.sing === zxy.sing) // true
+```
+
+自己定义 数组扩展方法,求最大值
+
+```javascript
+const arr = [1,2,3]
+//自定义方法写到,数组.prototype 身上,任何实例化数组都能使用
+Array.prototype.max = function(){
+ //展开运算符,此时 this 指向实例化对象(调用者 arr)
+ return Math.max(...this)
+}
+log(arr.max()) // 3
+```
+
+**原型对象的 constructor 属性**:==指向==创建该原型对象的==构造函数==
+
+```javascript
+// 定义一个空属性的构造函数
+function Star(){}
+// 自定义多个方法,用对象形式赋值
+Star.prototype = {
+// 因为采取的是赋值,所以会覆盖原有的函数 constructor,从而找不到是谁构造函数里的
+ // 需要重新指回这个原型对象的 构造函数
+ constructor: Star,
+ sing: function(){
+ log('唱歌')
+ },
+ dance: function(){
+ log('跳舞')
+ }
+}
+```
+
+**对象原型:_ _proto_ _**
+
+==实例对象都有一个属性 _ _proto_ _ ,对象原型 指向构造函数的 prototype 原型对象==
+
+**对象原型的 constructor 属性**:==指向==创建该原型对象的==构造函数==
+
+
+
+**原型继承**
+
+```javascript
+//1. 封装公共部分
+function Person() {
+ this.eays = 2,
+ this.head = 1
+}
+//2. 创建女人的构造函数
+function Woman(){}
+//3.1 Woman 通过原型来继承 Person
+//3.2 将公共部分,放到该构造函数原型 prototype 上
+Woman.prototype = new Person()
+//3.3 指回原来的构造方法
+Woman.prototype.constructor = Woman
+//4. 创建女人对象
+const red = new Woman()
+log(red)
+// 创建男人以此类推
+```
+
+**原型链**
+
+基于原型对象的继承使得不同构造函数的原型对象关联在一起,并且这种关联的关系是一种链状的结构,我们将原型对象的链状结构关系称为原型链
+
+
+
+#### 8.高级技巧
+
+**1. 深浅拷贝**
+
+**浅拷贝**:简单数据类型拷贝值,引用数据类型拷贝的是地址(单层对象可以,多层对象有问题)
+
+```javascript
+const obj = {
+ uname: 'pink',
+ age: 18,
+ famliy: {
+ baby: '小pink'
+ }
+ // 浅拷贝
+ // 方式一
+ const o = {...obj}
+ o.age = 20 // 修改的是自己 obj 对象 值不变
+ // 方式二
+ Object.assign(o,obj)
+ o.age = 20
+ o.famliy.baby = '老pink' // 因为是多层对象,所以 obj 也会跟着修改
+}
+```
+
+**深拷贝**:拷贝的是对象,不是地址
+
+ 1.通过**递归**实现深拷贝
+
+ 递归函数:一个函数内部调用自己,这个函数就是递归函数,==递归必须要加退出条件 return==
+
+```javascript
+const obj = {
+ uname: 'pink',
+ age: 18,
+ hobby: ['乒乓球','羽毛球'],
+ family: {
+ baby: '小pink'
+ }
+}
+// 深拷贝
+const o = {}
+function deepCoppy(newObj,oldObj){
+ for(let k in oldObj){
+ //1. 判断属性值是否是数组类型(一定要先判断数组,在判断对象,因为数组也是对象)
+ if(oldObj[k] instanceof Array){
+ // 是数组,就给要拷贝的对象的 hobby 属性先添加一个空数组
+ newObj[k] = []
+ // 递归,把要拷贝的属性 hobby,拷贝的值传入函数
+ deepCopy(newObj[k],oldObj[k])
+ //2. 判断属性值是否是对象类型
+ }else if(oldObj[k] instanceof Object){
+ // 是对象,就给要拷贝的对象的 family 属性先添加一个空对象
+ newObj[k] = {}
+ // 递归,把要拷贝的属性 hobby,拷贝的值传入函数
+ deepCopy(newObj[k],oldObj[k])
+ }else{
+ // k 属性值 uname oldObj[k] 属性值 18
+ // newObj[k] === o.uname
+ newObj[k] = oldObj[k]
+ }
+
+ }
+}
+// 调用函数
+deepCopy(o,obj)
+```
+
+2. 利用 js 库 lodash 里面的 **_.cloneDeep()**
+
+```javascript
+// 先引用
+
+
+ const obj = {
+ uname: 'pink',
+ age: 18,
+ hobby: ['乒乓球','羽毛球'],
+ family: {
+ baby: '小pink'
+ }
+}
+const o = _.cloneDeep(obj)
+
+```
+
+3. 利用 **JSON** 实现深拷贝
+
+```javascript
+const obj = {
+ uname: 'pink',
+ age: 18,
+ hobby: ['乒乓球','羽毛球'],
+ family: {
+ baby: '小pink'
+ }
+}
+//1. 把要拷贝的对象转换为 JSON 字符串(直接存值)
+//2. 再将 JSON 字符串 转成对象
+const o = JSON.parse(JSON.stringify(obj))
+```
+
+**2. 异常处理**
+
+ **throw 抛异常**
+
+- throw 抛出异常信息,程序也会终止执行
+- throw 后面跟的是错误提示信息
+- Error 对象配合 throw 使用,能够设置更详细的错误信息
+
+```javascript
+function fn(x,y){
+ if(!x || !y){
+ // throw '没有传递参数进来'
+ throw new Error('没有传递参数进来')
+ }
+ return x + y
+}
+log(fn())
+```
+
+ **try / catch 捕获错误信息**
+
+```javascript
+123
+function fn(){
+ try {
+ //可能出错的代码,写在 try 里
+ const p = document.querySelector('.p')
+ p.style.color = 'red'
+ } catch (err) {
+ // 拦截错误,浏览器提示出错信息,但是不中断程序执行
+ log(err.message)
+ throw new Error('你看看,选择器错误了')
+ // 需要加 return 中断程序
+ // return
+ }
+ finally {
+ // 不管程序有没有错误,都会执行这里面的代码
+ alert('弹出警示框')
+ }
+ log(123)
+}
+fn()
+```
+
+ **debugger** :代码断点标记
+
+**3. 处理 this**
+
+ **this 指向-普通函数**
+
+- 谁调用 this 就指向谁
+- 普通函数没有明确调用者时 this 指向 window
+
+ **this 指向-箭头函数**
+
+- 箭头函数内不存在 this,沿用上一级的
+- 不适用:构造函数,原型函数,dom 事件函数
+- 适用:需要使用上层 this 的地方
+
+ **改变 this 指向**
+
+- **call (this指向谁 , 其他形参…)**
+
+```javascript
+const obj = {
+ uname: 'pink'
+}
+function fn(x,y) {
+ log(this) // 没有 call 指向 window,此时指向 obj
+ log(x + y) //3
+}
+fn.call(obj,1,2) // 让 this 指向 obj 对象,可以传入参数
+```
+
+- **apply (this指向谁 , [数组])**
+
+```javascript
+const obj = {
+ uname: 'pink'
+}
+function fn(x,y) {
+ log(this) // 没有 call 指向 window,此时指向 obj
+ log(x + y) //3
+}
+fn.apply(obj, [1,2]) // 与 call() 的区别:实参一定要是数组,并且形参是根据数组的个数来接
+// 使用场景:求数组最大最小值
+const arr = [100,56,89]
+const max = Math.max.apply(null,arr)
+const min = Math.min.apply(null,[56,89,100])
+// 利用扩展运算符求
+log(Math.max(...arr))
+```
+
+- **bind (this指向谁 , 其他形参…)**
+ 上面两个都会调用函数,这个==不会调用函数,会返回一个新函数(修改后的)==
+
+```html
+
+
+
+```
+
+**4. 防抖(debounce)**
+
+ 单位时间内,频繁触发事件,只执行最后一次
+
+ 假设:有一个定时器5秒钟执行一次,在未执行完前再次调用(会累加),此时利用防抖会先取消上一次,重新开始执行(王者荣耀的回城)
+
+方式一:lodash 里的 **_.debounce()**
+
+方式二:手写防抖函数
+
+```html
+<- 案例:实现鼠标在盒子上滑动,盒子内的数字 ++ ->
+
+
+```
+
+**5. 节流(throttle)**
+
+ 单位时间内,频繁触发,只执行一次()
+
+ 例:王者荣耀技能冷却,期间不能使用该技能
+
+```html
+<- 案例:实现鼠标在盒子上滑动,隔1秒 盒子内的数字 ++ ->
+
+
+```