1.事件流
指的是事件执行的流动路径
①事件捕获:从父到子 (document——>div)
②事件冒泡:从子到父 (当一个元素触发事件后,会依次调用父级元素的同名事件)
③阻止冒泡:
④阻止默认行为:e.preventDefault()
应用场景:对于某些链接或者按钮,没有达到触发条件时使用
2.事件委托
利用事件冒泡
原理:给父元素注册事件,当触发子元素时会自动冒泡到父元素,从而触发父元素的事件
以上的例子是一个简单的事件委托示例,核心就是对父元素绑定事件,控制子元素事件
3.页面加载事件
跟vue里面的生命周期差不多
window.addEvwntListener('load',function(){
console.log('页面加载完毕')
})
4.页面滚动事件
滑动条到固定位置:
<script>
window.addEventListener('scrol', function ()
{
//获取滚动时的距离
const n = document.documentElement.scrollTop
if (n > 100) {
console.log('页面滚动超过100')
}
})
</script>
点击按钮回到顶部:
<script>
const btn = document.querySelector('button')
btn.addEventListener('click', function ()
{
document.documentElement.scrollTop = 0
})
</script>
得到元素的宽高,同样获取dom对象,对象.属性就行
滚动条到一定的位置,搜索栏显示:
<script>
const header = document.querySelector('.header')
const box = document.querySelector('.box')
window.addEventListener('scroll', function ()
{
const n = document.documentElement.scrollTop
if (n > box.offsetTop) {
header.style.top = 0
} else {
header.style.top = -80 + 'px'
}
})
</script>
以上的应用场景是,当窗口滑动到一定的地方时,显示头部导航栏
下标随着点击的盒子移动
5.日期对象
主要作用是在页面上显示时间
①实例化:new创建对象就是实例化
创建一个时间对象并获取事件
function(){
const date = new Date()
const year = date.getFullYear()
const month = date.getMonth()
const day = date.getDate()
const hours = date.getHours()
}
date.toLocalString()方法可以返回标准格式的事件 /// 2024/4/1 09:41:21
6.DOM节点
DOM树里面的每个内容都称之为节点,只用考虑元素节点
父节点查找:子元素.parentNode //返回最近一级的父节点
字节点查找:父元素.children //获得所有元素节点,返回一个伪数组
下一个兄弟节点:nextElementSibling
上一个兄弟节点:previousElementSibling
在ul里面添加创建的节点,常用的情况是发表评论
通过对节点操作也可以达到渲染页面的目的
7.Window对象(浏览器对象模型)
1.浏览器对象
window对象是一个全局对象,JavaScript的顶级对象
像document、alert()、console.log()这些都是window的属性,window对象下的属性和方法调用的时候可以省略window
Window.document.querySelector() ===document.querySelector()
2.定时器-延时函数
setTimeout(回调函数,等待的毫秒数)
延时函数:执行一次
间歇函数:每隔一段时间就执行一次,除非手动清除
3.执行机制
①渲染引擎 ②解析js的引擎
由于JS是一门单线程语言,产生了同步任务2和异步任务
同步任务:在主线程上执行,形成一个执行栈
异步任务:js的异步是通过回调函数执行的(普通事件、资源加载、定时器)
异步任务相关的添加到任务队列,也称为消息队列
由于主线程不断地重复的获取任务,执行任务,这种机制成为事件循环(even loop)
4.location对象
location是一个对象,保存了URL地址的各个部分
常用方法:location.href = 'www.baidu.com' //跳转到百度的首页
search: 搜索网页的时候一般是在?后面显示内容:location.search :可以得到?后面的值
hash: 得到的是#后面的部分 //经常用于不刷新页面,显示不同的页面
reload: 这是一个方法(location. reload()) //用于刷新页面
5.navigator
获取浏览器信息
!(function(){
//检测浏览器信息
const userAgent = navigator.userAgent
//验证是否为苹果和安卓
const android = userAgent.match(/(Android);?[\s\/]+([\d.])?/)
const iphone = userAgent.match(/(iPhone\sOS)\s([\d_]+)/)
// 如果是苹果或者安卓就跳转到移动端
if(android || iphone){
location.href = 'http:www.baidu.com'
}
})()
以上是一段检测浏览器环境的代码,以后用的时候可以直接复制
6.history
数据类型也是数据,主要用来管理浏览器地址栏相应的操作,如前进、后退、历史记录等
8.本地存储
1.数据存储到用户浏览器中
2.设置、读取方便、跳转页面刷新数据也不会丢失数据
3.容量比较大,sessionStorage和localStrorage大约是5M左右
除非手动删除,就算是关闭页面也会存在,而且同意浏览器可以共享
两者用法一模一样,sessionStorage生命周期是关闭页面,关闭以后数据就没了
语法:
//存储数据
localStorage.setItem((key,value))
//获取数据
localStorage.getItem(key)
//以键值对方式存储数据
localStorage.setItem('name','mihu')
localStorage.setItem('age',18)
本地存储只能存字符串,所以会有转换
2.本地储存处理复杂数据类型
复杂数据类型没有办法存到本地储存里面
转换为JSON字符串,键(key)永远带引号
将复杂数据类型转换为字符串:语法 JSON.stringfy(复杂数据类型)
const obj = {
name: '张三',
age: 18,
adress: '北京',
email: '1125@gmail.com'
}
//转换为字符串数据类型
localStorage.setItem('obj', JSON.stringify(obj))
// 转换为对象
const obj1 = JSON.parse(localStorage.getItem('obj'))
console.log(obj1)
数组的两个重要渲染方法:map()和join()实现字符串拼接
数组中的map方法
遍历数组处理数据,并且返回新的数组
<script>
const list = ['red', 'blue', 'red']
//使用map方法
const newList = list.map(function (event, index)
{
console.log(event)
console.log(index)
return event + '颜色'
})
// 打印新数组
console.log(newList)
</script>
结果:
join()方法
用于把数组中的所有元素转换为一个字符串
const newList = list.map(function (event, index)
{
console.log(event)
console.log(index)
return event + '颜色'
})
// 打印新数组
console.log(newList)
console.log(newList.join(''))
console.log(newList.join('|'))
结果如下,如果括号里面不加任何字符,默认字符串以逗号隔开
在JS里面可以通过map返回数组渲染页面,然后通过join用innerhtml放到对应位置
9.正则表达式
就是对一些需要的片段查找,替换,提取操作
步骤:1.定义规则
2.查找
1.定义正则表达式语法
①基本语法
<script>
const str = '这是一过简单的实列'
//正则表达式
//1.定义规则(在正则表达式里面不需要加‘’)
const reg = /简单/
//2.是否匹配
console.log(reg.test(str))
</script>
②exec()语法
如果匹配成功,该方法返回一个数组,否则返回null
2.元字符
一些具有特殊含义的字符
例如abcdefghijk......用元字符表示为:【a-z】
边界符:
如果^和$在一起,表示精确匹配
量词:(表示重复的次数)
console.log(/^哈哈哈*$/.test('哈哈哈哈'))
console.log(/^哈哈哈?$/.test('哈哈哈哈'))
console.log(/^哈哈哈+$/.test('哈哈哈哈'))
console.log(/^哈哈哈{4}$/.test('哈哈哈哈'))
3.字符类
【abc】这个匹配的不是abc,匹配的是a或b或c,匹配到任何一个都是true
//需要十分注意的是【】只选择一个,超过一个都不行
console.log(/^[abc]*$/.test('hello this is ahj')) //false
console.log(/^[abc]?$/.test('a')) //true
console.log(/^[a-zA-Z0-9]$/.test('M')) //true
console.log(/^[a-zA-Z0-9-_]{6,16}$/.test('dhjhhs'))
4.预定义类
5.修饰符
6.替换replace
10.JS进阶语法
1.作用域
scope规定了变量能够被访问的范围,离开了这个范围便不能被访问
查找规则:就近原则
2.垃圾回收机制
内存分配:当我们声明变量、函数、对象的时候,系统会自动的分配内存
内存使用:读写内存,就是使用变量,函数
内存回收:使用完毕后,由垃圾回收器自动回收,不再使用
备注:
全局变量:一般不回收,关闭页面回收
局部变量:一般不用就会被自动回收
内存泄漏:程序中分配的内存由于某种原因程序未释放或无法是哦放叫做内存泄漏
垃圾回收机制的算法:
1.引用计数算法:计算变量的指向,如果等于0就进行释放
缺陷;如果两个变量相互引用,就算不用了也无法释放,导致内存泄漏
2.标记清除法:将不使用的对象定义为”无法到达的对象“
从根部全局对象定时扫描,凡是从根部能到达的,都是要使用的,无法到达的进行标记,稍后释放
3.闭包
闭包=内存函数+外层函数变量 //就是里层函数用到了外层的变量
作用:外部也可以使用内部的变量
主要就是函数套函数,实现数据私有
闭包会形成内存泄漏
4.变量提升
当代码执行之前,先把在当前作用域下所有用var声明的变量提升到当前作用域的最前
只提升声明,不提升赋值
ES6语法引入块级作用域,用let或者const声明变量,使代码更加规范
5.函数提升
只提升声明,不提升调用
*****函数表达式不存在函数提升,必须先声明后调用
<script>
fn()
function fn ()
{
console.log('函数提升了')
}
</script>
6.函数参数
1.动态参数
arguments使函数内部内置的伪数组变量,包含了调用函数时传入的所有实参
<script>
function getSum ()
{
console.log(arguments)
let sum = 0
for (let i = 0; i < arguments.length; i++) {
sum += arguments[i]
}
console.log(sum)
}
getSum(2, 23)
</script>
特点:
①arguments是一个伪数组,只存在于函数中
②arguments的作用是动态获取函数的实参
③可以通过for循环依次得到传递过来的值
2.剩余参数
function getSum1 (...arr)
{
console.log(arr)
}
getSum1(100, 20, 25, 45, 8)
getSum1() //结果:[100,20,25,45,8]
function getSum1 (a,b,c...arr)
{
console.log(arr)
}
getSum1(100, 20, 25, 45, 8)
getSum1() //结果:[48,8]
两者的区别:
①。。。是符号语法,置于末尾参数之前,用于获取多余的参数
②借助剩余参数获得的数组是一个真实的数组
③在使用的时候尽量使用剩余参数
3.展开运算符
不会修改原素组
const arr = [1, 2, 5, 47, 7, 9]
//展开运算符
console.log(...arr) //1 2 5 47 7 9
//求数组的最大值
console.log(Math.max(...arr))
//求数组的最小值
console.log(Math.max(...arr))
//合并数组
const newArr = [...arr1,...arr2]
作用:求数组的最大值和最小值、合并数组等
剩余参数用在函数内
展开运算符主要是展开数组
4.箭头函数
箭头函数是代码更简洁,并且不绑定this
箭头函数指向的都是window
<script>
const fn = function ()
{
console.log('这是普通函数')
}
fn()
const fn1 = () =>
{
console.log('这是箭头函数')
}
fn1()
const fn2 = x =>
{
console.log(`只有一个参数:${x}`)
}
fn2(12)
const fn3 = x => console.log('只有一句话的时候:' + x)
fn3(2)
const fn4 = x => x + x
fn4(15)
//箭头函数可以返回一个对象
const fn = (uname)=>({uname:uname})
console.log()fn('张三')
</script>
组织表单的默认事件
const form = document.querySelector('form')
form.addEventListener('click',e=>e.preventDefault)
①箭头函数属于表达式函数,因此不存在变量提升
②箭头函数只有一个参数时可以省略圆括号()
③箭头函数只有一行代码时可以省略花括号
④加括号的函数返回对象字面量表达式
重点
①普通函数有arguments动态参数
②箭头函数没有arguments动态参数,但是有剩余参数。。。args
7.解构赋值
数组结构
基本语法:
//变量的顺序一次从数组中得到
const arr = [100, 20, 30]
const [a, b, c] = arr
console.log(a)
console.log(b)
console.log(c)
交换两个变量的值:
仔细看这里必须要加分号的地方
<script>
let a = 10
let b = 20;
[b, a] = [a, b]
console.log(a, b) //20 10
;[1, 2, 3].map(function (item)
{
console.log(item + '数字')
})
const [a,b,...c] = [1,2,3,4,5]
console.log(c) //[3,4,5] 得到一个真数组
</script>
对象解构
<script>
//对象解构,要求变量名与属性名相同
const { name, age } = { name: '张三', age: 28 }
//等价于:const name = obj.name
console.log(name, age)
const user = {
name: '小明',
age: 18
}
const { name: myname, age: myage } = user
console.log(myname, myage)
</script>
解构的时候需要改变名字就需要把原理的属性给新的属性
数组对象解构
拿到的json数据在传参的时候就直接解构
传进来的数组改个名字
8.遍历数组foreach方法
遍历数组中的每个元素(只能遍历数组)
优势在于遍历数组对象,数组对象越复杂,优势越明显
<script>
const arr = ['blue', 'green', 'red']
const result = arr.forEach((item, index) =>
{
console.log(item)
console.log(index)
})
//foreach和map一样,但是foreach没有返回值,打印的是undefined
console.log(result)
</script>
渲染数据的例子
从数组对象中拿到对象,然后通过解构拿到每个属性,通过模板语法渲染到页面
11.构造函数
构造函数是一种特殊的函数,主要用来初始化对象
创建对象的三种方式:
//第一种,利用字面量创建对象
const obj1 = {
name: '张三',
age: 18
}
//利用objec创建对象
const obj2 = new Object()
obj2.name = '迷糊'
//利用构造函数创建对象
function Peplo (name, age, gender)
{
this.naem = name
this.gender = gender
this.age = age
}
const peplo = new peplo('Mihu1', 18, '男')
实例成员
实例对象里面的属性和方法称为实例成员
像字符串、数值、布尔、等基本类型也都有专门的构造函数,称为包装类型,虽然我们没有实例化对象,但是其内部是已经实例化对象了
内置构造函数
object
Object.key()
Object.values()
Object.assign
object函数提供了静态方法可以获取对象中的所有属性
获得所有属性值:object.values(o)
拷贝对象
Array
arry也是一个内置构造函数,主要在是用来创建数组的
数组的核心重要方法:
reduce
作用:返回累计处理的结果,经常用于求和等
如果是有初始值的话,加上初始值,没有就不加
<script>
const arr = [10, 20, 12]
const total = arr.reduce(function (prev, current)
{
return prev + current
}, 58)
console.log(total) //100
</script>
reduce的执行过程,感觉上其实就是一个循环,不断地那上一次的结果加下一次的结果
数组常见的方法(了解)
String
常见方法:
Number
<script>
const number = '123'
console.log(Number(number)) //123
console.log(Number(number).toFixed(2)) //123.00
</script>
12.原型
①由于构造函数里面的方法造成内存浪费,所以公用的方法都应该写到原型里面,圆形分配的函数是所有对象共享的
②规定每一个构造函数都有一个prototype属性,指向另一个对象,也称之为原型对象
③这个对象可以挂载函数,实例对象不会创建原型上的函数,节约内存
④构造函数和原型对象中的this都指向实例化对象
例子:
构造函数里面的this就是指向的实例对象
原理就是谁调用this指向谁,现在已经是实例化以后得到的对象,就相当于现在这个就是调用者
不管是构造函数还是原型对象里面的this都是指向实例对象
之前说的那些构造函数,如果想要自定义方法也可以:构造函数.prototype.max=function(){}
可以仔细研究一下上文中的this,弄明白的话就没什么问题了
constructor属性
每个原型对象里面都有一个constructor属性(constructor构造函数)
上图给了两种原型挂载函数的方法,第一种是追加,第二种是赋值
对象原型
刚才说的是原型对象,现在是对象原型,顾名思义是实例化对象的原型,主要是用来解释为什么实例对象可以使用原型对象的函数
①__proto__是js的非标准属性
②[[prototype]]和_proto_意义相同
③表明当前实例对象指向的原型对象prototype
④__proto__对象原型里面也有一个constructor属性,指向创建该实例对象的构造函数
原型继承
面向对象的三大特性之一
其实就是实例化对象的原型对象继承过去
1.创建构造函数(父类)
2.创建子类构造函数
3.子类.prototype=new 父类
4.子类.prototype.constructor = 子类 (上一步重新写了对象,现在需要把有对象原型指回去)
5.实例化对象
原型链
基于原型对象的继承使得不同构造函数的原型对象关联在一起,并且这种关联的关系是一种链状的结构,我们将原型对象的链状结构关系称为原型链
① 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。
② 如果没有就查找它的原型(也就是 proto 指向的 prototype 原型对象)
③ 如果还没有就查找原型对象的原型(Object的原型对象)
④ 依此类推一直找到 Object 为止(null)
⑤__proto__ 对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线
⑥ 可以使用 instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上