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 + + + + +``` + +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.事件流 + +事件流指的是事件完整执行过程中的流程路径 + +过程:事件捕获 => 事件目标阶段 => 事件冒泡 整个完整的过程就是事件流 + +![](图片/事件流.png) + +**事件捕获** + +概念:从DOM的根元素开始去执行对应的事件(从外到里) + +格式: + +```html +DOM.addEventListener(事件类型,事件处理函数,是否使用捕获) +``` + +**事件冒泡** + +概念:当一个元素的事件被触发时,同样的事件将会在该元素的所有祖先元素中依次被触发,这个过程被称为事件冒泡 + +事件冒泡的必要性:如果没有冒泡给大盒子注册点击事件,点击的是里面的小盒子,会导致大盒子的点击无法执行 + +**阻止冒泡** + +```javascript +事件对象.stopPropagation() +e.stopPropagation() +``` + +**阻止元素默认行为** + +```javascript +e.preventDefault() //阻止提交事件,或a连接跳转 +``` + +**事件移除解绑** + +```javascript +//添加点击事件 +事件对象.addEventListener('click',fn) +//移除点击事件 +事件对象.removeEventListener('click',fn) +``` + +**事件委托** + +事件委托:给父元素注册事件,当我们触发子元素的时候,会冒泡到父元素身上,从而触发父元素的事件 + +优点:减少注册次数,提高程序性能 + +```html + + + +``` + +#### 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 +
+
+
x
+
+
+ +``` + +子节点查找 + +​ 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 属性**:==指向==创建该原型对象的==构造函数== + +![](图片/原型.png) + +**原型继承** + +```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) +// 创建男人以此类推 +``` + +**原型链** + +基于原型对象的继承使得不同构造函数的原型对象关联在一起,并且这种关联的关系是一种链状的结构,我们将原型对象的链状结构关系称为原型链 + +![](图片/原型链.png) + +#### 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秒 盒子内的数字 ++ -> +
+ +```