diff --git "a/19\345\275\255\345\213\207\346\226\214/\345\244\215\344\271\240.md" "b/19\345\275\255\345\213\207\346\226\214/\345\244\215\344\271\240.md"
new file mode 100644
index 0000000000000000000000000000000000000000..4057199cb5e7f7c8a7bbba2e2b3280521c6c7e13
--- /dev/null
+++ "b/19\345\275\255\345\213\207\346\226\214/\345\244\215\344\271\240.md"
@@ -0,0 +1,2433 @@
+## 第一单元
+
+## 一. 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秒 盒子内的数字 ++ ->
+
+
+~~~
\ No newline at end of file