JS笔记-自用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.pink {
background-color: pink;
}
</style>
</head>
<script>
//JS是运行在客户端的编程语言,实现人机交互
//作用:网页特效,表单验证,数据交互(获取后端数据,处理后渲染到前端),服务端编程node.js
//js基本语法,DOM页面文档对象模型:对业面元素进行操作 BOM浏览器对象模型:操作浏览器
</script>
<body>
<!--定义四个按钮-->
<button class="pink">按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
<script>
let bs = document.querySelectorAll('button')
for(let i=0; i<bs.length; i++){
bs[i].addEventListener('click', function(){
document.querySelector('.pink').className = ''
this.className = 'pink'
})
}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!--css也是三种书写位置:行内的直接在标签上写,内部的写在head之间,外部的用link方式引入-->
</head>
<body>
<!--引入外部js-->
<!-- <script src="./my.js" ></script> -->
<!--比如按钮事件可以直接在标签内部写js,vue框架是这种写法-->
<div class="box">我是文字内容</div>
<ul class="nav">
<li>test1</li>
<li>test2</li>
<li>test3</li>
</ul>
<button>点我一下</button>
<form action="http://www.baidu.com">
<input type="submit" value="提交">
</form>
<a href="http://www.baidu.com">支付成功 <span>5</span>秒之后跳转到首页</a>
<!--内部js-->
<script>
// 一般内部js是写在body的底部,先加载html元素,在用js去操作
/*
js的注释和java类似,单行与多行
*/
// js的输入与输出语法
// 文档输出内容,向body输出
// document.write('我是标签')
// document.write('<h1>我是标题</h1>')
// 对话框
// alert('对话框内容')
// 控制台打印,程序员自己看
//console.log('日志')
// js的输入语法
// prompt('请输入你的姓名')
// 变量
// 变量的声明与赋值
// let age = 19 , name = 'wang'
// age = 30
// let num1 = 10, num2 = 20
// let tmp = num1
// num1 = num2
// num2 = tmp
// 变量严格区分大小写
// 小驼峰命名法
//let uname = prompt('输入姓名')
//let uage = prompt('输入年龄')
// let gender = prompt('输入性别')
// document.write(uname, uage, gender)
// var与let的区别:var允许变量的重复声明
// 数组的使用
//let arr = []
// let sname = ['wang', 'li', 'zhang']
//let l = sname.length
// const 声明常量
// const PI = 3.141
// js数据类型:弱数据类型语言
// 基本数据类型:数字,字符串,布尔,未定义,空
// 引用数据类型:object对象
// 数字可以用算数运算符操作
// 字符串是用单引号、双引号、反引号引起来的都可以
// 字符串内部包含字符串,外单内双 或者外双内单
// 字符串的拼接
// let s = 'a' + 'b'
// 模板字符串:拼接字符串和变量
//let age = 18
// 模板字符串反引号 ${}声明变量
//let x = `good ${age}`
// document.write(x)
// 布尔类型
// let flag = true
// 未定义类型 声明变量未定义
// 空值null
// 检测数据类型 typeof(数据)
// 隐式转换 +左右一侧是字符串转换成字符串 其它运算符号有数字看数字
// +'字符串' 可以把字符串转换成数字类型
// 类型转换 Number(字符串) 也可以用+
// parseInt()
// parseFloat()
// 赋值运算符 自增运算符
// ==相等 ===值与类型相等
// 逻辑与&& 逻辑或|| 逻辑非!
//let a = []
// a[1] = 1
//alert(a[1])
//alert((typeof a[1]) === true)
// 表达式可以被求值 语句不一定可以被求值
// if else
// 三元运算符
//let a = 1, b = 2
//let res = a < b ? 5 : 4 ;
// switch分支语句
//let a = 1
//switch(a){
//case 1: //分支
//alert(a)
// break
// case 2:
// alert(a)
// break
// default: //没走分支默认的支路
//alert(a)
//}
// 断点调试 Sources中打断点
// while循环
// 数组操作:修改直接赋值,新增arr.push(元素1,元素2):添加到数组末尾,返回数组长度
// arr.unshift(数据):在数组头部插入元素,返回数组长度
// 删除数组元素:arr.pop():删除数组最后一个元素并返回该值
// arr.shift():删除第一个元素并返回元素
// arr.splice(起始位置,删除的数目)
// 函数:小驼峰命名,命名第一个最好是动词
//function sayHi(){
// 函数体
// }
// sayHi() // 函数调用
//function getSum(start, end){
// let sum = 0
// for(let i=start; i<=end; i++){
// sum += i
// }
// }
// 函数形参可以指定默认值,不传参的话就走默认值
// 全局变量与局部变量 特殊:函数内部的局部变量若是没有声明直接使用默认是全局变量
// 命名冲突,先访问局部的再访问全局的
// 具名函数的调用可以在任何位置
// 匿名函数:函数表达式必须先声明再使用
// (function(){})()
// 逻辑中断:左边结束不判断右边
// 对象:是无序的数据集合 由属性和方法组成
//let o = {}
//let o1 = new Object()
// 对象的声明,然后通过.运算符调用对象的属性与方法 delete 对象.属性
// 对象名.属性 对象名['属性名']
// let person = {
// name : "wang",
// sayHi : function(){
//方法体
// },
// sayHello : function(x=1, y=2){
// 方法体
// }
// }
// person.name
// person.sayHi()
// person.sayHello(3,4)
// 对象的遍历 无序的,无法通过索引号遍历,for in 语法 和python一样
// for in 不用来遍历数组,用来遍历对象
//let obj = {
// x : 1,
// y : "2"
// }
// for (let key in obj){
// alert(obj[key]) //对象遍历取值可以用这个
// alert(obj.key) //这个不能用,因为key是字符串
//}
// 数组里面可以放置很多对象,遍历数组取出对象
// 内置对象 js包含多个内置对象,可以直接调用,document.write() console.log()
// Math对象 和java的用法基本一致 ceil floor max min random round pow abs
// 关键字 基本数据类型:存值 引用数据类型:存址
// webAPI
// 变量先用const声明,如果变量后面改变,再用let 注:数组和对象用const声明,简单数据类型用let声明
// DOM树与DOM对象 开发网页内容特效实现与用户交互
// DOM树也称为文档树,直观的体现了标签与标签之间的关系 document->body,head->div meta a
// 浏览器根据 html标签生成js对象 :dom对象
// document是dom里面提供的一个对象
// const box = document.querySelector('.box') // 默认匹配第一个,里面是css选择器,返回值是一个对象
// console.log(box)
// const lis = document.querySelectorAll('.box') 获取所有的满足条件的,返回的是一个伪数组
// 伪数组得到对象需要for循环遍历获取
// const lis = document.querySelectorAll('.nav li')
// for(let i=0; i<lis.length; i++){
// console.log(lis[i])
// }
// 操作dom内容 要修改元素标签内部的内容,可以通过对象.innerText 和对象.innerHTML
//const box = document.querySelector('.box')
//box.innerText = '修改后的内容'
//console.log(box.innerText)
//box.innerHTML = '<strong>加粗的内容</strong>'
// 修改元素的属性 src href title 获取属性后 用对象.属性 = 属性 完成矩阵修改
// 获取元素对象,更换属性即可
// 修改style属性 对象.style.样式属性 = '值'
//通过类名修改样式
// 操作表单属性 表单.value 获取表单的值 表单.type 获取表单的类型
// 对象.checked = true 勾选 disabled 禁用
// 自定义属性 html5允许自定义属性 一般以data-开头 对象.dataset.属性 获取
// 定时器
// let n = setInterval((function(){}),1000) //第一个参数是函数名,第二个参数是时间 ,每隔时间调用函数
// clearInterval(n) 关闭定时器
// 时间监听
// 元素对象.addEventListener('事件类型',执行的函数)
//const btn = document.querySelector('button')
//btn.addEventListener('click', function(e){ // e为事件对象,这个对象有事件触发的相关信息
// alert('谢谢点击')
//e.stopPropagation() //阻止事件冒泡
// })
// 事件对象包含的信息:type事件类型,clientX/clientY光标相对于窗口左上角的位置 offsetX/Y光标相对于dom左上角的位置
// key用户按下e.key === 'Enter' 按下回车键
// 环境对象 函数内部特殊的变量this,代标当前函数运行时所处的环境
// 普通函数里面this指向的是window 谁调用,this就指向谁
// 回调函数 函数A作为参数传递给函数B,则函数A叫做回调函数
// 事件类型 click mouseenter mouseleave focus blur keydown keyup input
// 事件流:事件执行的流动路径 事件捕获(父到子)->事件冒泡(子到父)
// dom对象.addEventListener('事件类型',事件处理函数,是否使用捕获机制)
// 事件冒泡,当一个元素触发事件后,会向上调用父级元素的同名事件
// 事件解绑,dom对象.removeEventListener('click', 函数处理事件,获取捕获或者冒泡阶段)
// 匿名事件无法解绑
//事件委托,可以减少注册次数,给父元素注册事件
// 获取父类元素
// const ul = document.querySelector('ul')
//ul.addEventListener('click', function(e){
// alert(l1) // 函数体
// if(e.target.tagName === 'LI'){
// e.target.style.color = 'red'
// }
//})
// 阻止默认行为的发生 阻止链接跳转,阻止表单跳转
// const form = document.querySelector('form')
// form.addEventListener('click',function(e){
// e.preventDefault()
// })
// const href = document.querySelector('a')
// href.addEventListener('click', function(e){
// e.preventDefault()
// })
// 页面加载事件 :等待页面加载完毕再去执行js代码
// window.addEventListener('load', function(){
// 待执行的函数体
// })
// HTML页面加载完就触发 ,无需等待样式之类的加载
// window.addEventListener('DOMContentLoaded', function(){
// 待执行的函数体
// })
// 页面滚动事件 scoll
// 页面尺寸事件 resize
// 日期对象:用来表示时间的对象 new对象进行实例化
// const date = new Date() // 得到当前事件
//const date1 = new Date('2014-01-05 15:24:20')
//const year = date1.getFullYear()
//const month = date1.getMonth() + 1
//const day = date1.getDate()
//const week = date1.getDay() + 1
//const hour = date1.getHours()
//const miniute = date1.getMinutes()
//const second = date1.getSeconds()
// 时间戳
//const date = new Date()
//let time = date.getTime()
//let time1 = new Date().getTime()
//let time2 = Date.now()
//let time3 = +new Date()
// 倒计时:将来的时间戳减去现在的时间戳
// DOM节点操作 元素节点、属性节点、文本节点
// 父节点、子节点、兄弟节点
// 对象.parentNode 对象.children 对象.nextElementSibling 对象.previousElementSibling
// 增加节点 :创建节点,根据需求进行增加即可
//const ul = document.querySelector('ul')
//const li = document.createElement('li') //创建节点
//const li1 = document.createElement('li')
//li.innerHTML = '末尾的li'
//li1.innerHTML = '头部的li'
//ul.appendChild(li) //新增在末尾,作为最后一个子元素
//ul.insertBefore(li1,ul.children[0]) // 新增在首部
// 克隆节点 对象.cloneNode(true)
// 删除节点
// 在js中要删除某一个元素,需要通过父元素进行删除 父元素.removeChild(要删除的元素)
// window对象 BOM浏览器对象模型 是一个全局顶级对象,也可以说是JS中的顶级对象
// window包含:navigator location document history screen
// 定时器:延时函数
// let s = setTimeout(function(){}, 1000)
// 清除延时函数 clearTimeout(s)
// js的执行机制:从上到小执行 js是单线程的,一段时间只干一件事
// 同步任务:在主线程上执行,形成一个任务栈 异步任务:通过回调函数实现,将相关任务添加到任务队列中去
// 事件循环:主线程不断获取任务执行任务再获取任务执行任务,这种机制被称为事件循环 event loop
// location对象 是数据类型的对象,拆分并保存了URL地址的各个组成部分
// href属性获取完整的url地址
// location.href = "http://www.baidu.com" //获取地址自动跳转
// const a = document.querySelector('a')
// let num = 5
// let timer = setInterval(function(){
// num -= 1
// a.innerHTML = `支付成功 <span>${num}</span>秒之后跳转到首页`
//if(num === 0){
// clearInterval(timer)
//location.href = 'http://www.douyin.com'
// }
// }, 1000)
// location.search 拿到表单?后面的
// location.hash 拿到#后面的
// location.reload(true) 页面刷新,有参数强制刷新
// navigator 记录浏览器的相关信息 可以通过userAgent检测浏览器的版本与平台
// history对象 管理历史记录 该对象与浏览器的操作相对应,前进、后退、历史记录等
// back() forward() go(参数)
// 本地存储:数据存储到浏览器中,设置读取页面刷新不丢失数据 容量较大 5M左右
// localStorage.setItem(key,value) 键值对的形式进行存储
// localStorage.getItem(key) 获取值
// localStorage.removeItem(key) 移除
// 本地存储复杂数据
//const obj = {
//uname : 'wang',
//age : 18,
//gender : '男'
//}
// 需要将复杂数据类型转换json字符串再存储
//localStorage.setItem('obj', JSON.stringify(obj))
// 将json字符串转换成对象
// JSON.parse(localStorage.getItem('obj'))
// 数组中的map方法迭代数组,可以返回新的数组
// map是两个对象的映射关系
//const arr = ['red', 'blue', 'yellow']
//const arr1 = arr.map(function(element, index){
// return element + '颜色'
//})
// 数组的join方法是将数组中所有元素转换成一个字符串
// arr1.join()
// arr1.join('')
// 正则表达式 用于匹配字符串中字符组合的模式,通常用来查找和替换那些符合
//定义变量
//const s = '前端,后端,移动端'
// 定义规则
//const reg = /前端/
// 规则能否匹配字符串,true或者false
//let ans = reg.test(s)
//匹配成功返回数组,否则返回为null
//const res = reg.exec(s)
// 元字符 特殊含义的字符 [a-z]表示26个字母
// JS进阶
// 作用域 局部作用域 全局作用域
// 函数作用域在函数内部声明只能内部访问 函数执行完毕后函数内部的变量实际被清空了
// 块作用域 {}包裹 let与const声明的会产生块作用域
// 全局作用域 script标签和.js文件中的 尽可能少声明全局变量 防止变量被污染
// 函数会优先查找当前作用域,逐级向上查找,直至 全局作用域
// 作用域链的本质是底层变量的查找机制
// JS垃圾回收机制 内部分配-使用-回收 局部变量使用完回收 全局变量页面关闭才回收
// 内存泄漏 分配的内存无法回收或者未回收
// 栈存放基本数据类型 堆存放复杂数据类型
// 垃圾回收算法: 引用计数法:循环引用导致内存泄漏 标记清除法:由根部出发不可达的为垃圾
// js闭包 closure 内层函数+外层函数的变量 内层函数使用外层函数的变量,外层函数返回内存函数的引用
// 常用的闭包写法,外部可以访问内部的变量,可以实现变量私用,但是可能会导致内存泄漏
//function outer(){
//let a = 10
//function fn(){
// a ++
// console.log(`函数被调用了${a}次`)
// }
// return fn
// }
// const fun = outer()
//fun()
// 变量提升 var会存在变量提升 提升变量声明到当前作用域 let/const无变量提升
// 函数提升 函数参数 箭头参数
// 先调用再声明会有函数提升 函数表达式必须先声明和赋值然后再调用
// 函数参数 : 不定参数也叫动态参数
//function getSum(){
// arguments动态参数 只存在于函数之中,是个伪数组
// let s = 0
// for(let i=0; i<arguments.length; i++){
// s += arguments[i]
//}
// return s
// }
// getSum(1,2,3)
//getSum(1,2,3,4)
// 剩余参数
// function getSum(a,b,...arr){
// 剩余参数是真数组 用相关的api可以用
// let s = 0
// for(let i=0; i<arr.length; i++){
// s += arr[i]
// }
// return a + b + s
//}
//getSum(1,2,3)
//getSum(1,2,3,4)
// 展开运算符,展开数组,不会修改原数组
//const arr = [1,2,3]
//const arr1 = [4,5,6]
//const max = Math.max(...arr)
//const arr2 = [...arr,...arr1]
// ES6箭头函数的使用 引入箭头函数并且不绑定this 箭头函数用来替代匿名函数的
/*
const fn = function fn(){
}
const fn1 = (x,y) =>{
console.log(`箭头函数${x},${y}`)
}
fn1(1,2)
const fn2 = x => console.log(x)
const fn3 = x => x + x
// 直接返回对象
const fn4 = (uname) => ({name : uname})
const obj = fn4('wang')
// 利用箭头函数求和
const getSum = (...arr) =>{
let sum = 0
for(let i=0; i<arr.length; i++){
sum += arr[i]
}
return sum
}
const result = getSum(1,2,3)
// 箭头函数的this 箭头函数不会创建自己的this 它只会从自己的作用域链的上一层去沿用this
const fn5 = () =>{
// this指向window
}
*/
//const obj1 = {
// uname : 'wang',
// sayHello : function(){
// let i = 10
// const count = () =>{
// this 指向上一层的obj1
// }
// count()
// }
// }
//obj.sayHello()
// 普通函数this指向调用者, 箭头函数this指向上级一般是window
// 解构与赋值 数组解构 对象解构
// 数组解构 就是提取数组的单元值批量赋值给变量的语法
/*
const arr1 = [100, 80, 60]
// 数组解构赋值
const [a, b, c] = arr1
alert(a)
let x = 1, y = 2 ;
// 上面的分号必须加,才能用这种数组解构方式
[x,y] = [y,x]
// 两种情况下必须使用分号,一种是立即执行函数的时候需要加,另外一种是使用数组的时候需要加
const hc = ['海尔','联想','小米','方正']
const [hr, lx, xm, fz] = hc
// 单元值少 变量多 不够的为undefined
// 变量少 单元值多 取前面的赋值即可,剩余的可以用剩余变量接收
const [u = 1, v = 2] = [3,4] //设置默认参数
const [e,f,,g] = [1,2,3,4] // 按需导入
// 多维数组的解构
const arr4 = [1,2,[3,4]]
const [h,i,j] = arr4
*/
// 对象解构
//const obj = {
// uname : 'wang',
// age : 18
//}
//obj.uname
//obj.age
// 对象解构语法 属性名与变量名必须相同
// const {uname, age} = {uname : 'wang', age : 18}
// 对象解构的变量可以修改,如下
// const {uname:username, age} = {uname : 'wang', age : 18}
// 解构数组对象
/*
const pig = [{
uname : 'pig',
age : 4
}]
const [{uname, age}] = pig
*/
//多级对象 的解构
/*
const pig = {
uanme : 'pink',
family : {
mother : 'wang',
father : 'zhang'
}
}
const {uanme, family:{mother, father}} = pig
*/
// 数组对象的解构
/*
const pig = [{
uanme : 'pink',
family : {
mother : 'wang',
father : 'zhang'
}
}
]
const [{uanme, family:{mother, father}}] = pig
*/
// forEach()遍历数组 增强版的for循环 只遍历不返回值
/*
const color = ['pink', 'yellow','red']
color.forEach(function(item, index){
// item是数组元素 index是数组下标
console.log(item[index])
})
*/
// 创建对象的几种方式
/*
const obj = {}
const obj1 = new Object()
// 利用 自定义构造函数进行创建 构造函数是一个特殊函数,主要用来初始化对象
// 通过构造函数来快速创建多个类似的对象 : 函数命名第一个字母大写,只通过new关键子进行操作
function Pig(uname, age){
this.uname = uname
this.age = age
}
const peiqi = new Pig('小猪', 1)
const qiaozhi = new Pig('大猪',2)
*/
// new实例化执行过程 创建对象,构造函数this指向新对象,修改this添加新属性,返回新对象
// 实例成员: 实例对象的属性与方法 静态成员:在构造函数中的属性与方法
// 构造函数创建的实例对象彼此独立互不影响
// 内置的构造函数 基本包装类型
// 有些基本数据类型在js的底层做成了复杂包装类
// 内置构造函数:Object Array String Number
/*
const obj = {
uname : 'pink',
age : 1
}
// 获得所有属性名
const obj1 = Object.keys(obj)
// 获得所有属性值,返回所有的数组
const obj2 = Object.values(obj)
const obj3 = {}
// 对象拷贝
Object.assign(obj3, obj2)
*/
// Array内置函数 reduce(函数,初始值)
/*
const arr = [1,2,3]
arr.forEach(function(item, index){
})
const total = arr.reduce(function(prev, current){
return prev + current
})
const total1 = arr.reduce(function(prev, current){
return prev + current
},10)
const total2 = arr.reduce((prev,current)=>prev+current,10)
*/
// Array实例方法 sort排序 join数组元素拼接成字符串 find找到第一个符合元素 every所有元素符合条件
// some是否有元素符合条件 concat合并数组 splice删除或者替换数组元素 reverse翻转数组 findIndex查找元素索引
// map filter forEach
/*
const arr = ['blue', 'green', 'red']
arr.find(function(item){
return item === 'red'
})
const arr1 = [{
name : '小米',
price : 1999
},{
name : '华为',
price : 3999
}]
// 将name为小米的对象找出来
const xiao = arr1.find(item => item.name === '小米')
*/
/*
const arr = [10, 20, 30]
const res = arr.every(function(element,index, array){
return element >= 10
})
const res1 = arr.every(element => element >= 10)
const res2 = arr.some(element => element > 10)
*/
/*
const spec = {size : '40*40cm', color : '红色'}
const value = Object.values(spec).join('/')
document.querySelector('div').innerHTML = value
// 伪数组转换为真数组
const lis = document.querySelector('ul li')
const liss = Array.from(lis) // 伪数组转换为真数组
*/
// 字符串的常见方法
// length split('')将字符串拆分成数组 substring() startsWith endsWith includes toUpperCase toLowerCase
// indexOf replace match
// split字符串拆分成数组
/*
const str = 'pink,red'
const str1 = 'red'
const arr = str.split(',')
// 左闭右开
const s = str.substring(0,str.length)
const s1 = str.substring(0)
const flag = str.startsWith('p',0)
const flag1 = str.endsWith('d',str.length)
const res = str.includes(str1) // 包含关系,区分大小写
const res1 = str.includes(str1, 2) //从第2个位置开始算
*/
// Object对象的方法 assign合并多个对象到目标对象 keys values
// 编程思想 面向过程 面向对象
// 构造函数
/*
function Star(name, age){
this.name = name
this.age = age
this.sing = function(){
// 函数体
}
}
const liu = new Star('刘**', 38)
const zhang = new Star('张**', 34)
// 构造方法存在内存浪费的问题
// 构造函数的prototype属性称为原型 指向另外一个对象,称为原型对象
// 不变的方法定义在原型上而不是构造方法上,则这些属性就可以共享
// 公共的方法写在原型上,公共的属性写在构造函数
Star.prototype.dance = function(){
// 函数体
}
const res = liu.dance === zhang.dance
*/
/*
const arr = [1,2,3]
Array.prototype.max = function(){
// 原型的this指向Array
return Math.max(...this)
}
Array.prototype.sum = function(){
// 求和方法
return this.reduce((prev, current) => prev + current,0)
}
const ans = arr.sum()
*/
// constuctor属性 该属性指向原型对象的构造函数
/*
function Star(name){
this.name = name
}
Star.prototype = {
// 重新指回创造这个原型对象的构造函数
constructor : Star,
sing : function(){
},
dance : function(){
}
}
*/
// _proto_是JS非标准属性
// prototype是原型对象,构造函数里的,只读的,只能读取不能赋值 _proto_是对象原型,原型对象里的 对象原型指向原型对象
// 对象原型里面也有 一个constructor,指向构造函数
// 原型继承 子类.prototype = new 父类()
// 龙生龙 凤生凤 老鼠的儿子会打洞
//
/*
function Woman(){
this.eays = 2
this.head = 1
}
function Man(){
this.eays = 2
this.head = 1
}
const pink = new Woman()
const red = new Man()
*/
/*
// 用构造函数,然后实例化后赋值给原型对象即可实现继承
function Person(){
this.eays = 2
this.head = 1
}
// 男人和女人都要继承Person
function Woman(){
}
// Woman通过原型来继承Perosn
Woman.prototype = new Person() // woman和man的原型对象指向同一个对象会出现问题,用new就不会出现这个问题
// 指回原来的构造函数
Woman.prototype.constructor = Woman
// 为Woman对象增加一个baby方法,会发现woman和man都有baby方法
Woman.prototype.baby = function(){
}
//
const pink = new Woman()
// Man
Man.prototype = new Person()
Man.prototype.constructor = Man
const red = new Man()
*/
// 作用域链
// 原型链 : 基于原型对象的继承,使得不同构造函数的原型对象关联在一起
// 对象原型 指向原型对象 原型对象指向构造函数, 构造函数具有原型对象 构造函数具有对象原型实例 由此是个链状结构
// 本质上说:原型链就是一个查找规则
// 1.访问对象属性,首先看对象自身有没有该属性
// 2.没有找到就查找原型,即_proto_指向的原型对象prototype
// 3.没有找到就查找原型对象的原型 Object的原型 对象
// 4.以此类推找到Object,没找到为空
// 原型链的作用: 为对象成员查找机制提供一条路线 instanceof 用于检测原型对象是否出现在原型链上
// 深浅拷贝:可以防止直接复制改变当前值原对象被改变的问题
// 1.浅拷贝拷贝的是地址
/*
const obj = {
unmae : 'pink',
age : 18
}
// 浅拷贝
const o = {...obj}
o.age = 20 //修改对象o的属性不会改变原对象obj的属性
const o1 = {}
// 浅拷贝
Object.assign(o1,obj)
*/
// 存在多层对象嵌套的情况下,内层的对象不会被拷贝,浅拷贝只能拷贝简单数据类型,不适合拷贝复杂数据类型
// 浅拷贝:对于简单数据类型拷贝的是值,对于复杂数据类型拷贝的是地址
// 深拷贝有三种方式 1.通过递归方式 2.lodash/cloneDeep 3.JSON.stringfy()
// 函数内部自己调用自己属于递归
/*
let i = 1
function fun(i){
alert(i)
if(i>5){
return
}
fun(i+1)
}
fun(i)
*/
/*
const obj = {
name : 'wang',
age : 18
}
const o = {}
function deepCopy(oldObj,newObj){
// 数组的处理需要放在对象之前
for(let k in oldObj){
// 处理数组等复杂类型直接浅拷贝会用问题
if(oldObj[k] instanceof Array){
newObj[k] = []
deepCopy(oldObj[k], newObj[k])
}else if(oldObj[k] instanceof Object){
newObj[k] = {}
deepCopy(oldObj[k], newObj[k])
}
else{ // 简单数据类型直接浅拷贝
newObj[k] = oldObj[k]
}
}
}
deepCopy(obj, o)
*/
// 深拷贝不会影响原来的对象 可以通过函数递归实现,简单数据类型直接复制,数组递归复制,对象递归复制
// 通过loadash实现深拷贝,先引用库然后使用即可
// 第三种方法利用JSON.stringfy()把对象转换为字符串实现深拷贝
/*
const obj = {
uname : 'wang',
age : 18
}
// 先将JSON转换成字符串,再将字符串转换成JSON
const o = JSON.parse(JSON.stringify(obj))
*/
// 异常处理 throw try-catch-finally debugger
// throw抛出异常,与Error配合使用 ,抛出异常后终止程序
// throw new Error('这是抛出的异常')
// 处理this改变this 普通函数的this指向 箭头函数的this指向
// 普通函数是谁调用this就指向谁 箭头函数是向上层找this
// 改变this call bind apply
/*
const obj = {}
function fun(x,y){
}
fun.call(obj,1,2) // 改变this指向obj
*/
// apply()方法改变this
/*
const obj = {}
function fun(x,y){
}
// apply的实参放的是数组
fun.apply(obj,[1,2])
// 求数组最大值
const max = Math.max.apply(Math,[1,2,3,4])
// bind()方法改变this对象 bind方法步调用函数
// 返回值是一个函数,函数里面的this是更改过的,指向obj
const fn = fun.bind(obj)
// 需求,有个按钮,点击就禁用、2s之后开启
const btn = document.querySelector('button')
btn.addEventListener('click', function(){
this.disabled = true
window.setInterval(function(){
this.disabled = false
// 下面需要将this由window变成btn
}.bind(this), 2000)
})
*/
// 性能优化的防抖:单位时间内触发多次事件只执行最后一次
// 使用lodash库实现防抖 或者使用防抖函数实现
// 性能优化的节流:单位时间内,频繁触发事件,只执行第一次
// lodash实现节流 或者手写节流函数实现
// 应用场景:一般来说,防抖手机号校验,输入框等 节流用在高频事件:验证码的限时
// ES6是一JS的规格,JS是ES的一种实现
// 配合这个地址看:https://www.bookstack.cn/read/es6-3rd/sidebar.md
</script>
</body>
</html>