JavaScript基础
输入输出语法
输出:
document.write('要输出的内容')
alert('页面弹出警告窗')
console.log('控制台打印')
输入:
let value = prompt('用户输入的内容')
变量的本质
是程序在内存中申请的一块用来存放数据的空间
变量命名规范
不能用关键字
关键字:有特殊含义的字符,JavaScript 内置的一些英语词汇。例如:let、var、if、for等 Ø
只能用下划线、字母、数字、$组成,且数字不能开头
字母严格区分大小写,如 Age 和 age 是不同的变量
let、var 、const
var 现在开发中一般不再使用它,只是我们可能再老版程序中看到它。
let 为了解决 var 的一些问题。
var 声明:
-
可以先使用 在声明 (不合理)
-
var 声明过的变量可以重复声明(不合理)
-
比如变量提升、全局变量、没有块级作用域等等
使用 const 声明常量
当某个变量永远不会改变的时候,就可以使用 const 来声明,而不是let。
常量不允许重新赋值,声明的时候必须赋值(初始化)
不需要重新赋值的数据使用const
数据类型
基本数据类型:number、string、Boolean、undefined(未定义)、null(空)、NaN(也是一个数字类型)
引用数据类型:对象、数组、函数
-
NaN:not a number(不是一个数字,代表一个计算错误。它是一个不正确的或者一个未定义的数学操作所得到的结果)
-
undefined:只声明变量,不赋值的情况下,变量的默认值为 undefined,一般很少【直接】为某个变量赋值为 undefined
我们开发中经常声明一个变量,等待传送过来的数据。 如果我们不知道这个数据是否传递过来,此时我们可以通过检测这个变量是不是undefined,就判断用户是否有数据传递过来
像函数的形参,没有传递过来数据的时候就是undefined
-
null:仅仅是一个代表“空”或“值未知”的特殊值
-
null 和 undefined 区别: undefined 表示没有赋值; null 表示赋值了,但是内容为空
将来有个变量里面存放的是一个对象,但是对象还没创建好,可以先给个null
类型转换
JavaScript是弱数据类型
隐式转换:
- + 号两边只要有一个是字符串,都会把另外一个转成字符串
- 除了+以外的算术运算符 比如 - * / 等都会把数据转成数字类型(转换为数字类型发生错误就会得到一个NaN)
小技巧:
-
+号作为正号解析可以转换成数字型
-
任何数据和字符串相加结果都是字符串
显示转换:
Number(数据)
转成数字类型
如果字符串内容里有非数字,转换失败时结果为 NaN(Not a Number)即不是一个数字
NaN也是number类型的数据,代表非数字
parseInt(数据) 只保留整数
parseFloat(数据) 可以保留小数
一元运算符
自增运算符:
- 前置自增 ++ num
- 后置自增 num++
二者单独使用没有区别
参与计算的时候,
前置自增:先自加再使用(记忆口诀:++在前 先加)
后置自增:先使用再自加(记忆口诀:++在后 后加)
let i = 1
console.log(i++ + ++i + i)
// i++ 数值为1参与运算
// 此时i++ i为2
// ++i 数值为3参与运算
// 此时i为3
// +i
// 最终结果为
// i + 3 + 3 = 7
// 输出结果为:7
双等号()和三等号(=)
== 号比较值,比较时会发生隐式转换,隐式转换为number类型进行比较
=== 比较类型也比较值,没有隐式转换,开发中推荐使用 ===
从性能上来说,== 走了隐式转换那一层效率更低一些相较于 ===
Switch语句:
找到跟小括号里数据全等的case值,并执行里面对应的代码
若没有全等 === 的则执行default里的代
switch case语句一般用于等值判断,不适合于区间判断
switch case一般需要配合break关键字使用 没有break会造成case
不同类型的数据在内存中的分配情况
对象的增删改查
字符串遍历:for(let key of string) {console.log(key)}
对象的遍历:for(let key in obj) {console.log(key, obj[key])}
// 属性名, 属性值
JavaScript包括:ECMAJavaScript(欧洲计算机制造者协会) + web APIs(DOM + BOM)
DOM基础
使用js操作DOM
根据CSS选择器获取DOM元素(重要)
择匹配到的第一个元素,如果没有匹配到,则返回null
document.querySelector('css选择器')
选择匹配的多个元素,返回的是一个伪数组
获取到的集合没有pop和push等方法,要是用for循环来获取每个元素对象
document.querySelectorAll('css选择器')
其他获取DOM元素的方法(了解)
document.getElementById('id名')通过id获取元素
document.getElementsBytagName('标签名')通过标签名来获取元素集合
document.getElementsByClassName('类名')通过类名获取元素集合
操作元素内容
元素.innerText = ''
将文本内容添加/更新到任意标签位置;
显示纯文本,不解析标签
元素.innerHTML = ''
会解析标签,多标签建议使用模板字符
操作元素普通属性
对象.属性 = '值'
操作元素样式属性
obj.style.color = '' 如果属性有使用 - 连接的使用小驼峰命名法
obj.className = '' 设置一个类名会覆盖先前的类名
obj.classList.append('') 添加一个类名,不影响已存在的类名
obj.classList.remove('') 移除一个类名,不影响其他类名
obj.classList.toggle('') 切换一个类名,覆盖之前的类名
操作表单元素属性
获取:DOM对象.属性
设置:DOM对象.属性 = '新值'
自定义属性H5推出
在标签上一律以data-开头
在DOM对象上面一律以dataset对象方式获取
定义:<div data-id></div>
获取:document.querySelector('div').dataset.id
循环定时器:
let timer = setInterval(function() {}, 1000) 回调函数、循环间隔时间
clearInterval(timer)
单次定时器:
let timer = setTimeout(function() {}, 1000)
clearTimeout(timer)
事件监听
on方式会被覆盖,addEventListener方式可绑定多次,拥有事件更多特性,推荐使用
元素对象.on事件类型 = function() {}
元素对象.addEventListener('事件类型', function(e) {})
时间类型:
- 鼠标单击事件:click
- 鼠标经过:mouseenter(mouseenter 和 mouseleave 没有冒泡效果 (推荐))
- 鼠标离开:mouseleave
- 获取焦点:focus
- 失去焦点:blur
- 键盘按下触发:keydown
- 键盘抬起触发:keyup
- 用户输入事件:input
- 鼠标经过:mouseover(mouseover 和 mouseout 会有冒泡效果)
- 鼠标离开:mouseout
- 手方法腿上:touchstart
- 手在大腿上来回摸:touchmove
- 手从大腿上挪开:touchleave
DOM进阶
事件流
假设页面里有个div,当触发事件时,会经历两个阶段,分别是捕获阶段、冒泡阶段
捕获阶段是 从父到子 冒泡阶段是从子到父
实际工作都是使用事件冒泡为主
document.addEventListener('事件类型', 回调函数, '是否使用捕获机制(默认为false)')
addEventListener第三个参数传入 true 代表是捕获阶段触发(很少使用)
若传入false代表冒泡阶段触发,默认就是false
若是用 on 事件监听,则只有冒泡阶段,没有捕获
当一个元素的事件被触发时,同样的事件将会在该元素的所有祖先元素中依次被触发。这一过程被称为事件冒泡
当一个元素触发事件后,会依次向上调用所有父级元素的 同名事件,事件冒泡是默认存在的
使用事件对象 阻止冒泡 / 阻止默认行为(a连接的点击跳转,表单域跳转均为默认事件)
元素对象.addEventListener(‘事件类型’, function(e) {
e.stopPropagation()阻止冒泡
e.stopDefault()阻止默认行为
})
解绑事件
btn.onClick = function() {}
btn.onClikc = null
btn.addEventListener('click', fn)
btn.removeEventListener('click', fn)
两种注册事件的区别
传统on注册(L0)
Ø 同一个对象,后面注册的事件会覆盖前面注册(同一个事件)
Ø 直接使用null覆盖偶就可以实现事件的解绑
Ø 都是冒泡阶段执行的
事件监听注册(L2)
Ø 语法: addEventListener(事件类型, 事件处理函数, 是否使用捕获)
Ø 后面注册的事件不会覆盖前面注册的事件(同一个事件)
Ø 可以通过第三个参数去确定是在冒泡或者捕获阶段执行
Ø 必须使用removeEventListener(事件类型, 事件处理函数, 获取捕获或者冒泡阶段)
Ø 匿名函数无法被解绑
事件委托
事件委托是利用事件流的特征解决一些开发需求的知识技巧
Ø 优点:减少注册次数,可以提高程序性能
Ø 原理:事件委托其实是利用事件冒泡的特点
Ø 给父元素注册事件,当我们触发子元素的时候,会冒泡到父元素身上,从而触发父元素的事件
Ø 实现:事件对象.target. tagName 可以获得真正触发事件的元素
页面加载事件、元素滚动事件、页面尺寸事件
页面加载事件
加载外部资源(如图片、外联CSS和JavaScript等)加载完毕时触发的事件
有些时候需要等页面资源全部处理完了做一些事情
Ø 老代码喜欢把 script 写在 head 中,这时候直接找 dom 元素找不到
事件名:load
监听页面所有资源加载完毕:window.addEventListener('load', function() {})
不光可以监听整个页面资源加载完毕,也可以针对某个资源绑定load事件
当初始的 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发
而无需等待样式表、图像等完全加载
事件名:DOMContentLoaded
监听页面DOM加载完毕:
Ø 给 document 添加 DOMContentLoaded 事件
document.addEventListener('DOMContentLoaded', function() {})
页面滚动事件
滚动条在滚动的时候持续触发的事件
Ø 很多网页需要检测用户把页面滚动到某个区域后做一些处理, 比如固定导航栏,比如返回顶部
事件名:scroll
监听整个页面滚动:
获取到整个页面上卷去的距离
window.addEventListener('scroll', function(e) {console.log(document.documentElement.scrollTop)})
scrollLeft和scrollTop (属性)
Ø 获取被卷去的大小
Ø 获取元素内容往左、往上滚出去看不到的距离
Ø 这两个值是可读写的
scrollTo(X, Y) 方法可把内容滚动到指定的坐标
window.scrollTo(0, 0)
页面尺寸事件
会在窗口尺寸改变的时候触发事件
检测屏幕宽度
window.addEventListener('resize', function(e) {console.log(docuemnt.documentElement.clientWidth)})
获取元素的可见部分宽高(不包含边框,margin,滚动条等)
Ø clientWidth和clientHeight
offsetWidth和offsetHeight是得到元素什么的宽高?
Ø 内容 + padding + border
offsetTop和offsetLeft 得到位置以谁为准?
Ø 带有定位的父级
Ø 如果都没有则以 文档左上角 为准
日期对象
const date = new Date()
时间戳,常用语计算倒计时
指1970年01月01日00时00分00秒起至现在的毫秒数,它是一种特殊的计量时间的方式
将来的时间戳 - 现在的时间戳 = 剩余时间毫秒数
Ø 剩余时间毫秒数 转换为 剩余时间的 年月日时分秒 就是 倒计时时间
获取时间戳:new Date().getTime() +new Date() Date.now()
转换公式:
Ø d = parseInt(总秒数/ 60/60 /24); // 计算天数
Ø h = parseInt(总秒数/ 60/60 %24) // 计算小时
Ø m = parseInt(总秒数 /60 %60 ); // 计算分数
Ø s = parseInt(总秒数%60); // 计算当前秒数
节点操作
查找节点:
子元素.parentNode: 查找父节点:
父元素.childNodes: 获得所有子节点、包括文本节点(空格、换行)、注释节点等
父元素.children: 仅获得所有元素节点, 返回的还是一个伪数组
元素节点.nextElementSibling: 下一个兄弟节点
元素节点.previousElementSibling: 上一个兄弟节点
添加节点:
父元素.appendChild(document.createElement('标签名')): 插入到父元素的最后
父元素.insertBefore(要插入的元素, 在哪个元素前面)
元素节点.cloneNode(boolean)
cloneNode会克隆出一个跟原标签一样的元素,括号内传入布尔值
Ø 若为true,则代表克隆时会包含后代节点一起克隆
Ø 若为false,则代表克隆时不包含后代节点
Ø 默认为false
删除节点:
父元素.removeChild(要删除的节点)
删除节点和隐藏节点(display:none) 有区别的: 隐藏节点还是存在的,但是删除,则从html中删除节点
BOM操作
window对象
JS执行机制
location对象
常用属性和方法:
Ø href 属性获取完整的 URL 地址,对其赋值时用于地址的跳转
Ø search 属性获取地址中携带的参数,符号 ?后面部分
Ø hash 属性获取地址中的啥希值,符号 # 后面部分(配合<a href="#home"></a>可实现局部刷新)
后期vue路由的铺垫,经常用于不刷新页面,显示不同页面,比如 网易云音乐
Ø reload 方法用来刷新当前页面,传入参数 true 时表示强制刷新
navigator对象
navigator的数据类型是对象,该对象下记录了浏览器自身的相关信息
通过 userAgent 检测浏览器的版本及平台
/ 检测 userAgent(浏览器信息)
!(function () {
const userAgent = navigator.userAgent
// 验证是否为Android或iPhone
const android = userAgent.match(/(Android);?[\s\/]+([\d.]+)?/)
const iphone = userAgent.match(/(iPhone\sOS)\s([\d_]+)/)
// 如果是Android或iPhone,则跳转至移动站点
if (android || iphone) {
location.href = 'https://www.baidu.com'
}
})()
history对象
history 的数据类型是对象,主要管理历史记录, 该对象与浏览器地址栏的操作相对应,如前进、后退、历史记录等
history.forward() == history.go(1)前进
history.back() == history.go(-1)后退
本地存储
1、数据存储在用户浏览器中
2、设置、读取方便、甚至页面刷新不丢失数据
3、容量较大,sessionStorage和localStorage约 5M 左右
localStorage:
作用: 可以将数据永久存储在本地(用户的电脑), 除非手动删除,否则关闭页面也会存在
Ø 可以多窗口(页面)共享(同一浏览器可以共享)
Ø 以键值对的形式存储使用
localStorage.setItem('key', 'value')
localStorage.getItem('key')
localStorage.removeItem('key')
localStorage.clear()
sessionStorage:
生命周期为关闭浏览器窗口
Ø 在同一个窗口(页面)下数据可以共享
Ø 以键值对的形式存储使用
Ø 用法跟localStorage 基本相同
二者存储复杂数据类型时需要对value进行处理,转换为字符串存储,使用
JSON.stringify(对象)
JSON.parse(对象字符串)
正则表达式
正则表达式(Regular Expression)是用于匹配字符串中字符组合的模式。在 JavaScript中,正则表达式也是对象
使用场景:
1. 例如验证表单(匹配)
2. 过滤掉页面内容中的一些敏感词(替换)
3. 从字符串中获取我们想要的特定部分(提取)
语法:const 变量名 = /表达式/
其中 / / 是正则表达式字面量
test() 方法 用来查看正则表达式与指定的字符串是否匹配
exec() 方法 在一个指定字符串中执行一个搜索匹配
元字符:
边界符
^:表示匹配行首的文本(已谁开头)
$:表示匹配行尾的文本(已谁结束)
如果 ^ 和 $ 在一起,表示必须是精确匹配
量词:
元字符:
Ø [a-z] 表示 a 到 z 26个英文字母都可以
Ø [a-zA-Z] 表示大小写都可以
Ø [0-9] 表示 0~9 的数字都可以
(1) [ ] 里面加上 ^ 取反符号
比如:
Ø [^a-z] 匹配除了小写字母以外的字符
Ø 注意要写到中括号里面
(2) . 匹配除换行符之外的任何单个字符
修饰符:
Ø i 是单词 ignore 的缩写,正则匹配时字母不区分大小写
Ø g 是单词 global 的缩写,匹配所有满足正则表达式的结果(使用replaceAll的时候必须要添加修饰符g)
str.replace(正则表达式, '要替换的内容')