JS
JS
NuyoahWEB API
DOM
DOM
文档对象模型:用来呈现以及与任意的HTML或XML文档交互的API
DOM树
将HTML中的内容以树状的形式直观的显示出来,直观的体现了标签与标签之间的关系
DOM对象
浏览器根据HTML标签生成的JS对象
标签的所有属性都可以在这个对象上找到
获取DOM对象
-
通过CSS选择器获取对应的标签
document.querySelector获取符合标准的第一个元素
1
2document.querySelector('CSS选择器')
// css选择器: div, #ID .Classdocument.querySelectorAll获取符合标准的所有元素
1
2document.querySelectorAll('CSS选择器')
// css选择器: div, #ID .Class -
其他方法
document.getElementByID
document.getElementByTagName
document.getElementByClassName
操作元素
内容
innerText
只会显示纯文本,不会识别标签
innerHTML
可以识别html标签
属性
常用属性,直接获取元素然后修改集合
样式属性:修改样式时候一定要加上style
通过style属性操作css
对象.style.样式属性 =
单个属性直接写即可,如果属性有多个单词则需要进行小驼峰命名法
操作类名操作css
如果需要修改多种样式的话可以通过给特定元素附上属性类名来进行统一修改
const div = document.querySelector(‘div’)
div.className = “box”
calssName会覆盖原先的类名
通过classList控制类操作css
为了解决className会导致之前的类名被覆盖,所以引入classList来追加或删除类名
元素.classList.add(‘类名’)
元素.classList.remove(‘类名’)
切换一个类
元素.classList.toggle(‘类名’) 如果原先没有这个类名,则添加上,如果之前有这个类名则删除
元素.classList.contains(“类名”) 检测是否有这个类,有:true,没有False
表单属性
只能通过表单元素.value获取表单中的值,而不能通过innerHTML来获取表单中的内容
表单.value
表单.type = password text email
表单.checked = true or false 表单勾选
表单.disabled = true or false 按钮是否能点击
自定义属性
为了和自带属性区别,需要使用data-开头
获取自定义属性需要使用dataset获取属性集合,然后通过 .属性名来获取属性值
定时器-间歇函数
需要网页自动执行的代码,例如倒计时
开启定时器
返回值是一个定时器序号
1 | setInterval(函数, 间隔时间) // 间隔时间以毫秒为单位 |
关闭定时器
1 | let 变量名 = setInterval(函数, 间隔时间) |
setTimeout只执行一次,执行完自动关闭
1 | setTimeout(回调函数, 等待的毫秒数) |
清除延迟函数
1 | let timer = setTimeout(回调函数, 等待的毫秒数) |
事件
事件监听
1 | 语法 |
三要素
- 事件源
- 事件类型:用什么方式触发,click mouseOver
- 被调用的函数
事件类型
鼠标事件
click
mouseenter
mouseleave
鼠标经过事件:
mouseover 和 mouseout:有冒泡效果
mouseenter 和 mouseleave:无冒泡效果
焦点事件:表单获得光标
focus: 获得焦点
input.addEventListener(“fcous”, function(){
})
blur: 失去焦点
键盘事件:键盘触发
Keydown : 键盘按下触发
Keyup: 键盘抬起触发
文本事件
input:用户输入事件
input中的change事件
change:只有当表单中的内容改变了才会触发
视频事件
ontimeupdate 事件在视频/音频 (audio/video)当前的播放位置发送改变时触发
onloadeddata 事件在当前帧的数据加载完成且还没有足够的数据播放视频/音频 (audio/video)的下一帧时触发
事件对象
第一个参数为事件对象,一般命名为 e event
1 | 元素.addEventListener("click", function(e){}) |
事件对象的属性:
type:获取当前事件的类型
clientX、clientY:获取光标相对于浏览器可见窗口左上角的位置
offsetX、offsetY:获取光标相对于当前DOM元素左上角的位置
key:用户按下键盘键的值
环境对象
函数内部特殊的变量this,代表当前函数运行时所处的环境
this表明调用该函数的对象,谁调用该函数,this就指向谁
回调函数
将函数作为参数对象传递的就是回调函数
事件流
事件流指的是事件完整执行过程中流动的路径
捕获:
从大往小:从DOM的根元素开始执行对应的事件
冒泡:
从小往大:当一个元素被触发的时候,同样的事件将会在元素的所有祖先元素的中依次触发,当一个元素被触发 的时候,会依次向上调用所有父级元素的同名事件
阻止冒泡:
事件.stopPropagation()
解绑事件:
L0 :on方法:事件.onclick=null
L2: 事件.addEventListener(“click”, fn) 解绑 事件.removeEventListener(“click”, fn) 匿名函数无法被解绑
鼠标经过事件:
mouseover 和 mouseout:有冒泡效果
mouseenter 和 mouseleave:无冒泡效果
事件委托
优点:减少注册次数,可以提高程序性能
原理:事件委托利用事件冒泡的特点
1 | <ul> |
阻止默认行为
- preventDefault()
1 | <a href="www.baidu.com">百度一下</a> |
其他事件
-
页面加载
作用:等待页面全部加载完毕之后在进行js渲染,防止js写在html上方,js找不到指定元素
window.addEventListener(‘load’, function(){}) 等待页面所有的资源全部加载完毕之后在进行函数中的代码
1
2
3window.addEventListener("load", function(){
// 等待页面加载完毕之后在进行一下js代码
})DOMContentLoaded 等待文档中的HTML标签加载完毕就可以执行下列代码,不用等待页面全部元素加载完之后在进行js渲染
1
2
3document.addEventListener("DOMContentLoaded", function(){
// 需要执行的操作
}) -
页面滚动
事件名:scroll
可以配合scrollLeft和scrollTop:计算被卷去的大小(像素),滑动的距离
1
2
3
4const div = document.querySelector("div")
div.addEventListener("scroll", function(){
div.scrollTop
})获取整个页面滚动的距离
1
2
3
4
5
6
7
8
9
10window.addEventListener("scroll", function(){
// 获取页面的HTML滚动的距离,
// 获取HTML标签:document.documentElement
const n = document.documentElement.scrollTop
if(n>100){
//如果html向上滚动超过100px则进行以下写法
}else{
// 如果没有超过,则进行下面写法
}
})将页面打开的时候就在800px处打开
1
document.documentElement.stroll = 800 // 不带单位
-
页面尺寸
clientWidth 和 clientHeight
获取可见部分的宽高,包含padding不包含border
-
元素尺寸和位置
获取宽高:
offsetWidth和offsetHeight,包含padding和border
获取位置:
获取当前元素距离自己定位父级元素的左上距离
offsetLeft和offsetTop
获取相对于当前窗口的位置
ntRect(), 返回元素大小及其相对于视口的位置
-
属性选择器
1
2
3
4
5
6
7<input type = "text">
<input type = "password">
<!--只给第一个input颜色变为红色-->
input[type = text] {
color:red;
}
日期对象的使用
实例化
1 | // 获取当前时间 |
方法
方法 | 作用 | 说明 |
---|---|---|
getFullYear() | 获得年份 | 获取四位数年份 |
getMonth() | 获取月份 | 取值为0-11 |
getDate() | 获取月份中的每一天 | 不同月份取值不同 |
getDay() | 获取星期 | 取值为0-6 |
getHours() | 获取小时 | 取值为0-23 |
getMinutes() | 获取分钟 | 取值为0-59 |
getSeconds() | 获取秒 | 取值为0-59 |
1 | function getMyDate(){ |
时间戳
是指1970年01月01日00时00分00秒起止到现在的毫秒数
获取方法:
getTime(), 必须实例化date对象
1 | const date = new Date() |
简写 +new Date()
1 | console.log(+new Date()) |
使用Date.now()
1 | console.log(Date.now()) |
节点操作
DOM节点
元素节点:div p 等标签
属性节点:比如class属性
文本节点:比如标签里面的文字
查找节点
1父节点
1 element.parentNode2子节点
element.children // 常用
仅获得所有元素节点
返回的是一个伪数组
element.childNode
获取所有子节点,包括文本节点,注释节点等
3兄弟节点
下一个兄弟节点:nextElementSibling属性
上一个兄弟节点:previousElementSibling属性
增加节点
-
创建节点
创造一个新的网页元素,添加到网页内,一般先创建节点,再添加节点
创建方法
1
document.creatElement('标签名')
-
追加节点
插入到父元素最后一个子元素
1
父元素.appendChild(要插入元素)
插入到父元素中某个子元素的前面
1
2父元素.insertBefore(要插入的元素, 在那个元素前面)
ul.insertBefore(li, ul.children[0]) // 插入到第一元素之前 -
复制节点
1
元素.cloneNode(布尔值)
true:代表复制时会包含后代节点一起复制
false:代表不复制后代节点
默认false
-
删除节点
1
父元素.removeChild(要删除元素)
M端事件
M端:移动端
触屏事件:touch(触摸事件)
触屏touch事件 | 说明 |
---|---|
touchstart | 手指触摸到一个dom元素的时候触发 |
touchmove | 手指在dom元素上滑动的时候触发 |
touchend | 手指从dom元素上移开的时候触发 |
swiper插件
在线演示 https://www.swiper.com.cn/demo/index.html
基本使用流程https://www.swiper.com.cn/usage/index.html
查看APi文档,去配置自己的插件https://www.swiper.com.cn/api/index.html
Window对象
BOM
是浏览器对象模型
window是全局对象,是js顶级对象
所有通过var定义的全局变量函数都会成为window对象的属性和方法
window对象下的属性和方法调用的时候可以省略window
定时器-延迟函数
setTimeout只执行一次,执行完自动关闭
1 | setTimeout(回调函数, 等待的毫秒数) |
清除延迟函数
1 | let timer = setTimeout(回调函数, 等待的毫秒数) |
JS执行机制
同步任务
都在主线程上执行,形成一个执行栈
异步任务
需要消耗时间的任务
通过回调函数来实现
- 普通事件:click, resize
- 资源加载:load,error等
- 定时器:setInterval,setTimeout等
异步任务将添加到任务队列中
JS执行机制
先顺序执行同步任务,遇到异步的任务的之后将其放到任务队列中,当同步任务执行完毕之后,在进行任务队列中的任务进行执行
由于主线程不断重复的获取任务,执行任务,在获取任务,在执行任务,这种机制被称为事件循环(event loop)
location对象
拆分并保存了URL地址的各个部分
常用的属性和方法:
href属性获取完整的URL地址,用于地址的转换
1 | location.href = "http://www.baidu.com" |
search获取地址中携带的参数,符号?后面的部分
1 | location.search |
hash获取地址中#后面的值
1 | location.hash |
reload刷新页面
1 | location.reload() // f5 刷新 |
navigator对象
该对象记录下了浏览器自身的相关信息
1 | // 检测浏览器信息 |
history对象
history对象和方法 | 作用 |
---|---|
back() | 后退 |
forward() | 前进 |
go(参数) | 前进或后退 1表示前进一个页面 -1表示后退一个页面 |
本地存储
只能存储字符串类型
localStorage
1 | // 存数据 |
存储复杂数据类型
需要将复杂数据类型转换成JSON字符串存储到本地
JSON对象属性和值都有引号,且是双引号
1 | JSON.stringify(复杂数据类型) |
将JSON字符串转换为对象
1 | JSON.parse(JSON字符串) |
map() 和 join()方法
map() 可以在不改变原数组的基础上制造一个与原数组一一对应的新数组,
1 | const arr = ['red', 'blue', 'green'] |
**join()**可以将数组转换成字符串
1 | const arr = ['red', 'blue', 'green'] |
正则表达式
语法
1 | const 变量名 = /表达式/ |
test返回true或者false
1 | 变量.test("被检测的字符串") |
exec返回数组
1 | 变量.exec("被检测的字符串") |
元字符
元字符即特殊字符,拥有强大的匹配能力的字符
例如 只能输入英文字母
可以使用 [a-z] [A-Z]
边界符
表示位置,必须以什么开头以什么结尾
^m: 表示以m为开头的字符
m$: 表示以m为结尾的字符
^m$:精确匹配,表示字符中有且只能有一个m
量词
表示字符串的长度
量词 | 说明 |
---|---|
* | 重复零次或更多次 |
+ | 重复一次或更多次 |
? | 重复零次或一次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
1 | const re = /^哈*$/ |
字符类
-
[]匹配字符集合
表示字符串中只要出现[]中的任意一个字符即可
1
const re = /[abc]/
当时用精确匹配的时候,则[]中只能出现一个,出现多个则是错误
1
2
3
4
5
6
7const re = /^[abc]$/
re.test('a') // true
re.test('a') // true
re.test('a') // true
re.test('ab') // false
const re1 = /^[abc]{2}$/
re1.test('ab') // true在[]中使用-表示一个范围
1
2
3
4
5const re = /^$[a-z]{6}/
// 只能输入英文字母和数字
const re = /^$[a-zA-Z0-9]{6}/
// 只能输入大于10000的数字
const re = /^[1-9][0-9]{4}$/ -
在[]里面的^表示取反
1
2// 表示需要输入除了a-z之外的所有字符
const re = /[^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]
修饰符
语法:/表达式/修饰符
修饰符:
- i :ignore,正则匹配不区分大小写
- g:global,匹配所有满足正则表达式的结果
替换:replace
字符串.replace(/正则表达式/, ‘替换文本’)
1 | tx.value.replace(/aa|dd/, 'aa') |
放大镜效果
1 |
|
JS进阶
作用域
规定的变量能被访问的范围,如果出了这个范围就无法被访问
局部作用域
函数作用域:
- 函数生成的变量只能让函数内部来访问,外部无法直接访问
- 函数的参数也是函数内部的局部变量
- 不同函数生命的变量无法互相访问
- 函数执行完毕之后,函数内部的变量实际被清空了
块作用域:
- 只要使用{}包裹的代码称为代码块,代码块内部声明的变量外部有可能无法访问
- let和const声明的块作用域函数无法被外部访问,var声明的块作用域函数可以被外部访问
全局作用域
< script >和.js文件的最外层就是所谓的全局作用域,任何其他的作用域都可以被访问
作用域链
本质就是变量查找机制
当函数执行的时候会优先查找当前函数作用域的变量
如果当前作用域差找不到,则会逐级查找父级作用域,直到全集作用域
子作用域可以访问父作用域,但是父作用域无法访问子作用域
垃圾回收机制
生命周期
- 内存分配:当我们使用声明变量,函数,对象时,系统会自动分配内存
- 内存使用:读写内存
- 内存回收:使用完毕,由垃圾回收器自动回收不再使用的内存
全局变量不会回收(关闭页面回收)
局部变量不用会自动回收
**内存泄漏:**程序中分配的内存由于某种原因未释放或者无法释放
算法说明
堆:由操作系统自动分配,函数的参数值,局部变量,基本数据类型
栈:一般由程序自动分配释放,若程序员不释放,则有垃圾回收机制回收,复杂数据类型放到堆里面
引用计数法:
- 跟踪记录被引用的次数
- 如果被引用了一次,那么就记录次数1,多次引用会累加++
- 如果减少一个引用就减1 –
- 如果引用次数是0,则释放内存
**标记清除法:**找不到就删除
- 标记清除算法将“不再使用的对象”定义为“无法达到的对象”。
- 就是从根部(在JS中就是全局对象)出发定时扫描内存中的对象。凡是能从根部到达的对象,都是还需要使用的
- 那些无法由根部出发触及到的对象被标记为不再使用,稍后进行回收。
闭包
概念:一个函数对周围状态的引用捆绑在一起,内层函数中访问到其外层函数的作用域
简单理解:闭包=内层函数+外层函数的变量,里外层关系
只有通过函数才能访问某一变量,无法直接访问
1 | function count(){ |
闭包可能会引起内存泄漏
变量提升
允许var定义的变量在声明前访问,只提升变量声明不提升变量赋值
- 变量在未声明即被访问时会报语法错误
- 变量在var声明之前即被访问,变量的值为undefinec
- let/const声明的变量不存在变量提升
- 变量提升出现在相同作用域当中
- 实际开发中推荐先声明再访问变量
函数进阶
函数提升
函数在声明前就可以被调用
函数参数
动态参数:arguments是函数内部内置的伪数组变量,包含了调用函数时传入的所有实参
-
arguments是一个伪数组,只存在于函数中
-
arguments的作用是动态获取函数的实参
-
可以通过for循环依次得到传递过来的实参
1 | function sum(){ |
剩余参数
…参数名
获取多余的实参
是真数组
1 | function sum(a, b, ...arr){ |
展开运算符
使用…可以将一个数组进行展开,且不会改变原数组
求数组最大值
1 | arr = [1,2,3] |
合并数组
1 | arr1 = [1,2,3] |
箭头函数
目的:引入箭头函数的目的是更简短的函数写法并且不绑定this,箭头函数的语法比函数表达式更简洁
使用场景:箭头函数更适用于那些本来需要匿名函数的地方
基本语法
-
基本写法
1
2
3
4
5
6
7
8
9
10
11
12
13// 原本
const fn = function() {
console.log(123)
}
// 箭头函数
const fn = () => {
console.log(123)
}
// 参数箭头
const fn = (x, y) => {
console.log(x, y)
}
fn(1, 2) -
当只有一个函数的时候可以省略小括号
1
2
3
4
5// 当只有一个参数从时候可以省略小括号
const fun = x => {
console.log(x)
}
fun(2) -
只有一行代码的时候可以省略大括号
1
const fn = x => console.log(x)
-
只有一行代码的时候可以省略return
1
2
3
4
5
6// 初始写法
const fn = x => {
return x + x
}
// 省略写法
const fn = x => x+x -
箭头函数直接返回对象
1
2
3
4
5// {uname:uname},表示一个对象
// 但是箭头函数后面如果直接跟{},则会将函数体与对象识别混淆
// 所以使用小括号来包装一下对象
const fn = (uname) => ({uname:uname})
fn("张")
更为简介的语法
1 | // 初始写法 |
箭头函数参数
- 普通函数有argument动态参数
- 箭头函数没有argument动态参数,但是有剩余参数…args
1 | const getSum = (...args) => { |
箭头函数this
通常情况下this指向调用者
箭头函数不会创建自己的this,他只会从自己的作用域链的上一层沿用this
1 | const user = { |
解构赋值
数组解构
使用解构快速为变量赋值
数组解构是将数组的单元值快速批量赋值给一系列变量的简洁语法
传统写法
1 | const arr = [100,60,80] |
解构
1 | const [max, min, avg] = [100,60,80] |
交换两个变量的值
1 | const a = 1 |
必须加分号的两种情况
1 | //立即执行函数 |
赋值的几种情况
-
变量多,单元值少
1
2const [a, b, c, d] = [1, 2, 3]
// 其中 a = 1, b = 2, c = 3, d = undefined -
变量少,单元值多
1
2const [a, b] = [1,2,3]
// a = 1, b = 2 -
剩余参数,变量少,单元值多
1
const [a, b, ...args] = [1,2,3,4]
-
防止undefined传递
1
const[a = 0, b = 0] = []
-
按需导入赋值
1
2const [a, b, ,d] = [1, 2, 3, 4]
// a = 1, b = 2, d = 4
对象解构
对象解构:将对象的属性和方法快速批量赋值给一系列变量的简洁语法
1 | // const后面的参数值,一定要和对象中的属性名相同 |
基本语法:
- 赋值运算符=左侧的用于批量声明变量,右侧对象的属性值将被赋值给左侧的变量
- 对象属性的值将被赋值给与属性名相同的变量
- 注意解构的变量名不要和外面的变量名冲突否则报错
- 对象中找不到与变量名一致的属性时变量值为undefined
解构对象改名:
1 | const {uname: name} = {uname:'张三'} |
解构数组对象
1 | const pig = [ |
多级对象解构
1 | const pig = { |
1 | const pig = [ |
传参的时候解构
1 | const pig = { |
forEach方法
语法
1 | 被遍历的数组.forEach(function(当前元素数组,当前元素索引号)){ |
filter方法
1 | const 数组 = 被遍历的数组.filter(function(当前元素数组,当前元素索引号)){ |
深入对象
创建对象的三种方式
-
字面量创建
1
2
3const obj = {
name:"张三"
} -
使用new Object创建对象
1
2
3const obj = new Object({name:"张三"})
const obj2 = new Object()
obj2.name = "张三" -
通过构造函数创建对象
构造函数
目标:利用构造函数来创建对象
可以通过构造函数来创建多个类似对象
1 | function Pig(name, age, gender){ |
约定:
- 命名以大写字母开头
- 他们只能由“new”操作符来执行
说明:
- 使用new关键字调用函数的行为被称为实例化
- 实例化构造函数时没有参数时可以省略()
- 构造函数内部无需写return,返回值即为新创建的对象
- 构造函数内部的return返回的值无效,所以不要写return
- new Object ( ) new Date ( )也是实例化构造函数
实例化执行过程
- 创建新的空对象
- 构造函数this指向新对象
- 执行构造函数代码,修改this,添加新属性
- 返回新对象
实例成员&静态成员
实例成员:通过构造函数创建的对象称为实例对象,实例对象中的方法称为实例成员
说明:
- 为构造函数传入参数,创建结构相同但值不同的对象
- 构造函数创建的实例对象彼此相互不影响
静态成员:构造函数的属性和方法称为静态成员
说明:
- 静态成员中只能构造函数来访问
- 静态方法中的this指向构造函数
内置构造函数
Object
-
Object.keys(o) 获取所有属性的属性名
1
2const o = {name:'张三', age:12}
console.log(Object.keys(o)) // name,age -
Object.values(o) 获取所有的属性值
1
2const o = {name:'张三', age:12}
console.log(Object.values(o)) // 张三, 12 -
Object.assign(new, old) 将old中的属性值和名拷贝到new对象中
1
2
3
4const o = {name:'张三', age:12}
const oo = {}
Object.assign(oo, o)
console.log(oo) // {name:'张三', age:12}
Array
函数具体细节可查询MDNhttps://developer.mozilla.org/zh-CN/
-
forEach遍历数组
-
filter 过滤数组
-
map 迭代数组
-
reduce 累计器
1
2
3
4
5arr.reduce(function(上一次值, 当前值){}, 起始值)
const arr = [1,2,3]
const total = arr.reduce(function(prev, current){
return prev + current
})如果有起始值,则将数组中元素相加完毕之后,再加上起始值,没有则不加
执行过程:
- 如果没有起始值,则上一次值以数组的第一个数组元素的值
- 如果每一次循环,把返回值给作为下一次循环的上一次值
- 如果有起始值,则起始值作为上一次值
当遇到对象数组进行累加的时候,一定要初始值为0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18const arr = [
{
name:"张三",
salary:10000
},
{
name:"李四",
salary:10000
},
{
name:"王五",
salary:10000
},
]
const total = arr.reduce((prve, current) => {
return prve + current.salary
}, 0) -
实例方法 join:数组元素拼接位字符串,返回字符串
-
实例方法 find:查找元素,返回符合测试条件的第一个数组元素值,如果没有则返回undefined
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18const arr = [
{
name:'小米',
price:1999
},
{
name:'华为',
price:9999
},
]
// 找到name为小米的对象并返回
const mi = arr.find(function(item){
return item.name==='小米'
})
//箭头函数
const mi = arr.find(item=>item.name==='小米') -
实例方法 every:检测数组元素是否都符合指定条件,如果所有元素都符合则返回true,否则返回false
1
2const arr1 = [10,20,30]
const flag = arr1.every(itme=>item>=10) -
实例方法 some:检测数组中的元素是否满足指定条件,如果存在满足条件的返回true,否则返回false
-
实例方法 concat:合并两个数组,返回新生成的数组
-
实例方法 sort:对原数组单元值排序
-
实例方法 splice:删除或替换原数组
-
实例方法 reverse:反转数组
-
实例方法 findIndex 查找元素的索引值
-
实例方法 from :将伪数组转换为真数组
String
-
实例属性 length:用来获取字符串的度长(重点)
-
实例方法 split(‘分隔符’):用来将字符串拆分成数组(重点)
1
2const str = '2024-8-9'
const str1 = str.split("-") // ['2024', '8', 9] -
实例方法 substring(需要截取的第一个字符的索引[,结束的索引号]): 用于字符串截取(重点)
1
2const str = '帅气的男人'
const str1 = str.substring(1, 2) -
实例方法 startswith(检测字符串[,检测位置索引号]):检测是否以某字符开头(重点)
-
实例方法 includes(搜索的字符串[,检测位置索引号]):判断一个字符串是否包含在另一个字符串中,根据情况返回true或 false(重点)
-
实例方法 toUpperCase:用于将字母转换成大写
-
实例方法 toLowercase:用于将就转换成小写
-
实例方法 indexof:检测是否包含某字符
-
实例方法 endswith:检测是否以某字符结尾
-
实例方法 replace:用于替换字符串,支持正则匹配
-
实例方法 match:用于查找字符串,支持正则匹配
Number
toFixed()设置保留小数位的长度
1 | const price = 12.3654 |
编程思想
面向过程
分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候再依次调用即可
按照步骤划分
面向对象
把事务分解成一个个对象,然后对象之间相互合作
面向对象是以对象的功能来划分,而不是步骤
特性:
- 封装
- 继承
- 多态
构造函数
JS面向对象通过构造函数来实现封装性
构造函数可能会存在浪费内存的问题
1 | function Star(uname, age){ |
如果创建多个实例对象的话,则sing这个函数会存在多个
总结:
- 构造函数体现了面向对象封装的特性
- 构造函数实例创建的对象彼此相互独立互不影响
原型
原型
解决构造函数内存浪费的问题
- 构造函数通过原型分配的函数是所有对象所共享的
- JS规定,每一个对象都有一个prototype属性,指向另一个对象,所以我们也成为原型对象
- 这个对象可以挂载函数,对象实例化不会多次创建在原型上的函数,节约内存
- 可以将那些不变的方法,直接定义在prototype对象上,这样所有对象的实例就可以共享这些方法
- 构造函数和原型对象中的this都指向实例化对象
1 | //给数组定义自己的扩展方法 |
constructor属性
每个原型对象里面都存在constructor属性
作用:该属性指向该原型对象的构造函数
1 | function Star(){ |
在里面从新指回Star
1 | function Star(){ |
对象原型
每个对象都有一个属性__ proto __ ,指向构造函数的prototype原型对象,使用构造函数创建的对象,可以使用prototype原型对象的属性和方法,是因为对象有 __ proto __原型的存在
1 | function Star(){} |
原型继承
继承是面向对象的一个重要特征,通过继承进一步提升封装代码的程度,JS中大多数是借助原型对象实现继承特性
1 | function Woman(){ |
Woman 和 Man 都属于人类,所以可以提取出公共元素人,让后让Woman和Man继承Person
1 | function Person(){ |
但是这样有一个问题,如果想单独给女人增加一个生孩子的功能,可以尝试Woman.prototype.baby = function(){console.log(“生孩子”)}
如果使用上述方法的话,则男人的功能区也会出现baby的功能,因为男人女人都是用的一个原型
解决方法,使用new来创建继承
1 | function Person(){ |
原型链
基于原型对象的继承使得不同构造函数的原型对象关联在一起,并且这种关联关系是一种链状结构,称为原型链
原型链查找规则
- 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。
- 如果没有就查找它的原型 (也就是 __ proto __ 指向的 prototype 原型对象)
- 如果还没有就查找原型对象的原型 (object的原型对象)
- 依次类推一直找到 object 为止 (null)
- __ proto __ 对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线
- 可以使用 instanceof运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上
深浅拷贝
深浅拷贝只针对引用类型
浅拷贝
拷贝的是地址
方法:
- 拷贝对象:Object.assgin() / 展开运算符{…obj}拷贝
- 拷贝数组:Array.prototype.concat() / 展开运算符 […arr]
1 | const obj = { |
问题:浅拷贝中的引用数据类型拷贝的是地址
1 | const obj = { |
深拷贝
拷贝的是对象,不是地址
方法:
-
通过递归实现深拷贝
递归:函数自身调用自己
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24const obj = {
uname : "pink",
age : 18,
hobby : ["乒乓球", "篮球"],
family : {
name: "小pink"
}
}
// 深拷贝
function deepCopy(newObj, oldObj){
for(k in oldObj){
// 如果类型是数组的话则需要递归拷贝
if(oldObj[k] instanceof Array){
newObj[k] = []
deepCopy(newObj[k], oldObj[k])
} else if(oldObj[k] instanceof Object) {// 该语句一定要写在Array后面,因为Array instanceof Object = true
newObj[k] = {}
deepCopy(newObj[k], oldObj[k])
} else {
newObj[k] = oldObj[k]
}
}
} -
lodash/cloneDeep
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<!-- 先引用 -->
<script src="./lodash.min.js"></script>
<script>
const obj = {
uname : "pink",
age : 18,
hobby : ["乒乓球", "篮球"],
family : {
name: "小pink"
}
}
//调用
const o = _.cloneDeep(obj)
console.log(o)
</script> -
通过JSON.stringify()实现
1
2
3
4
5
6
7
8
9
10const obj = {
uname : "pink",
age : 18,
hobby : ["乒乓球", "篮球"],
family : {
name: "小pink"
}
}
// 先通过JSON.stringify将对象转换成字符串,在使用JSON.parse将字符串转换成对象
const o = JSON.parse(JSON.stringify(obj))
异常处理
throw抛异常
1 | function fn(x, y){ |
try/catch捕获异常
1 | function fn(x, y){ |
debugger
会在程序中添加一个断点,在执行的时候会暂停到这里
1 | function fn(x, y){ |
this问题
普通函数的this指向
谁调用普通函数,this就指向谁
当没有调用者的时候this指向window,严格模式下没有调用者时,this值为undefined
箭头函数的this指向
箭头函数中的 this 与普通函数完全不同,也不受调用方式的影响,事实上箭头函数中并不存在 this!
- 箭头函数会默认帮我们绑定外层 this 的值,所以在箭头函数中 this 的值和外层的 this 是一样的
- 箭头函数中的this引用的就是最近作用域中的this
- 向外层作用域中,一层一层查找this,直到有this的定义
注意
- 在开发中[使用箭头函数前需要考虑函数中 this 的值],事件回调函数使用箭头函数时,this 为全局的 window
因此DOM事件回调函数如果里面需要DOM对象的this,则不推荐使用箭头函数 - 同样由于箭头函数 this的原因,基于原型的面对象也不推荐采用箭头函数
改变this
-
call()
call调用函数,同时指定被调用函数中this的值
语法:fun.call(thisArg, arg1, arg2)
- thisArg: 在 fun 函数运行时指定的 this 值
- arg1,arg2: 传递的其他参数
- 返回值就是函数的返回值,因为它就是调用函数
1
2
3
4
5
6
7
8const obj = {
name:"张三"
}
function fn(x, y){
return x+y
}
// 让函数fn中的this指向obj
fn.call(obj,1,2) -
apply()
与call的区别是传递参数的方式不用
语法 fun.apply(thisArg, [argsArrays])
- thisArg:在fun函数运行时指定的 this 值
- argsArray:传递的值,必须包含在数组里面
- 返回值就是函数的返回值,因为它就是调用函数
- 因此apply 主要跟数组有关系,比如使用Math.max()求数组的最大值
1
2
3
4
5
6
7
8
9
10const obj = {
name:"张三"
}
function fn(x, y){
return x+y
}
// 让函数fn中的this指向obj
fn.call(obj,[1,2])
// 求最大值
const max = Math.max.apply(Math,[1,2,3]) -
bind()
bind方法不会调用函数,但是能改变函数内部this的指向
语法:fun.bind(thisArg, arg1, arg2)
- thisArg:在 fun 函数运行时指定的 this 值
- arg1,arg2:传递的其他参数
- 返回由指定的 this 值和初始化参数改造的 原函数拷贝 (新函数)
- 因此当我们只是想改变 this 指向,并且不想调用这个函数的时候,可以使用 bind,比如改变定时器内部的
this指向
防抖
单位时间内,频繁触发的事件,只执行最后一次
没有实现防抖时:鼠标每滑动1px,box中的内容就加一
1 | <div class="box"></div> |
实现方式
-
lodash(咯大师)提供的库 debounce
1
2
3
4
5
6
7
8
9
10
11
12<div class="box"></div>
<script src="./lodash.min.js"></script>
<script>
const box = document.querySelector(".box")
let i = 1
function mouseMove() {
box.innerHTML = i++
}
// box.addEventListener("mousemove", mouseMove)
// _.debounce(func, [wait=0], [options=])延迟 wait 毫秒后调用 func 方法
box.addEventListener("mousemove", _.debounce(mouseMove, 500))
</script> -
手写debounce函数
防抖的核心就是利用定时器(setTimeout)来实现
- 声明一个定时器变量
- 当鼠标每次滑动都先判断是否有定时器了,如果有定时器先清除以前的定时器
- 如果没有定时器则开启定时器,记得存到变量里面
- 在定时器里面调用要执行的函数
1
2
3
4
5
6
7
8
9
10
11function debounce(fn, t){
let timer
// 因为debounce需要传递参数过来,所以是立即调用,所以需要使用返回函数来进行业务
return function(){
if(timer) clearTimeout(timer)
timer = setTimeout(function(){
fn()
}, t)
}
}
box.addEventListener("mousemove", debounce(mouseMove, 500))
节流
单位时间内,频繁触发事件,只执行一次
使用场景:
高频事件:鼠标移动 mousemove,页面尺寸缩放 resize,滚动条滚动 scroll
实现方式
-
lodashi的节流函数
1
2//_.throttle(func, [wait=0], [options=]) 在 wait 秒内最多执行 func 一次的函数
box.addEventListener("mousemove", _.throttle(mouseMove, 500)) -
手写节流
节流的核心就是利用定时器(setTimeout)来实现
- 声明一个定时器变量
- 当鼠标每次滑动都先判断是否有定时器了,如果有定时器则不开启新定时器
- 如果没有定时器则开启定时器,记得存到变量里面
- 定时器里面调用执行的函数
- 定时器里面要把定时器清空
1
2
3
4
5
6
7
8
9
10
11
12
13function throttle(fn, t){
let timer = null
return function(){
// 没有定时器则创建
if(!timer){
timer = setTimeout(function(){
fn()
// 清空定时器
timer = null
}, t)
}
}
}
ontimeupdate 事件在视频/音频 (audio/video)当前的播放位置发送改变时触发
onloadeddata 事件在当前帧的数据加载完成且还没有足够的数据播放视频/音频 (audio/video)的下一帧时触发
由于ontimeupdate 触发频率特别高,所以可以采用节流
对视频操作
1 | const video = document.querySelector("video") |