2day
// 1-1. 函数定义阶段
// 语法1: 声明式函数
function fn() {
console.log('我是 fn 函数')
}
console.log(fn)
// 语法2: 赋值式函数
var fun = function () {
console.log('我是 fun 函数')
}
console.log(fun)
// 2. 函数调用阶段
// 我想执行 fn 这个盒子里面存储的代码
fn()
// 我想执行 fun 这个盒子里面的代码
fun()
/*
函数调用方式上的区别
+ 声明式函数, 可以先调用, 可以后调用
+ 赋值式函数, 只能后调用, 先调用会报错
*/
// 先调用
fn1()
// 声明式函数
function fn1() {
console.log('我是 fn1 函数')
}
// 后调用
fn1()
// 先调用
fn2()
// 赋值式函数
var fn2 = function () {
console.log('我是 fn2 函数')
}
fn2()
3day
/*
函数的参数
+ 形参
=> 书写在函数定义阶段的 () 里面
=> 就是一个只能在函数内部使用的变量
=> 可以书写多个, 中间使用逗号(,) 分隔
=> 值是由函数调用时候的实参决定
+ 实参
=> 书写在函数调用阶段的 () 里面
=> 就是一个准确的值, 或者一个表达式的结果
=> 作用: 按照顺序依次给形参进行赋值的
*/
/* 函数参数的个数关系 + 一样多: 按照从左到右的顺序依次赋值 + 形参多: 前面的按照顺序依次赋值, 多出来的形参没有实参赋值, 使用的时候就是 undefined + 实参多: 前面的按照顺序依次赋值, 多出来的实参因为没有形参接受, 不能在函数内直接使用 */
4day
/*
arguments
+ 是一个在函数内部使用的天生的变量
+ 存储了一个数据的集合(存储了一堆数据)
+ 函数所有实参的集合
arguments 的基本操作
1. 有一个 length 属性
=> 语法: arguments.length
=> 作用: 表示该集合的长度(里面有多少个数据), 是一个 number 类名
2. 有一个 索引 属性
=> arguments 集合里面的所有数据排列是按照 "序号" 进行排列的
=> "序号" 是从 0 开始, 依次 +1
=> 计算机编程语言里面管 "序号" 叫做 索引 或者 下标
=> 语法: arguments[索引]
=> 作用: 获取 arguments 中该索引位置的数据
+ 特点:
=> 索引 和 length 的关系
=> 最后一位的索引一定是 length - 1
+ 遍历 arguments:
=> 把所有数据从头到尾过一遍, 每一个拿出来去做你需要的操作
=> 循环进行遍历
-> 因为循环可以给我们提供一组有规律的数字
-> arguments 的索引也是一组有规律的数字
-> 在循环中, 使用循环控制变量来充当 arguments 的索引
*/
// function fn() {
// // 直接使用天生的变量 arguments
// console.log(arguments)
// // console.log('长度 : ', arguments.length)
// // console.log(arguments[0])
// // console.log(arguments[1])
// // console.log('=========================')
// // 遍历 arguments
// // arguments.length === 3, 需要的索引是 0 1 2
// // arguments.length === 5, 需要的索引是 0 1 2 3 4
// // 循环的开始: 0
// // 循环的结束: length - 1
// // 循环的步长: 1
// for (var i = 0; i < arguments.length; i++) {
// console.log(i)
// // 直接使用循环控制变量 i 来当做 arguments 的索引
// console.log(arguments[i])
// }
// }
// 本次调用没有传递实参
// fn()
// 本次调用传递一个实参
// fn(10)
// 本次调用传递两个实参
// fn(100, 200, 300)
/*
return 返回值
+ 是一个使用在函数内部的关键字
+ 写在 return 后面的内容就是这个函数的结果
*/
// function fn(a, b) {
// // 求和
// var res = a + b
// // 给 fn 函数添加一个调用后的结果
// // 把 res 的值当做 fn 函数调用后的结果
// return res
// }
// // result 接受的就是 fn 函数调用后的结果
// // 语法: fn(数字1, 数字2)
// // 作用: 求两个数字的和
// var result = fn(10, 20)
// console.log(result)
// 语法: Number(数据)
// 作用: 把数据转换成数值类型
// var n = Number('123')
// console.log(n)
/* 打断函数 + 使用 return 关键字 + 第二个作用就是打断函数 => 写在 return 后面行的代码不在执行了 */
/*
函数
+ 是一个 JS 内的复杂数据类型(一等公民)
+ 函数的定义阶段
=> 声明式函数
-> function 函数名() { ... }
=> 赋值式函数
-> var 函数名 = function () { ... }
+ 函数调用阶段
=> 函数名()
+ 两种调用方式的区别
=> 声明式函数, 可以先调用, 可以后调用
=> 赋值式函数, 只能后调用
+ 函数的参数
=> 形参:
-> 书写在函数定义阶段的小括号内部
-> 就是一个只能在函数内部使用的变量
-> 可以书写多个, 多个之间使用逗号(,) 分隔
-> 值由函数调用时的实参决定
=> 实参:
-> 书写在函数调用阶段的小括号内
-> 就是按照顺序依次给形参进行赋值的
=> arguments:
-> 函数内天生自带的变量
-> 表示的该函数所有实参的集合
-> arguments.length 表示该集合内有多少个数据
-> 索引: arguments 内所有数据按照索引进行排列的
-> 索引排列: 从 0 开始, 依次 +1
+ 函数的 return
=> 返回值:
-> 你想把什么内容放到函数外部去使用
-> 就直接书写 return xxx
-> 是一个函数内的关键字, 用来给函数定义返回值
=> 打断函数:
-> 书写在函数内部, return 后面行的内容不再执行了
*/
/*
预解析:
=> 预: 在 xxx 之前, 在所有代码执行之前
=> 解析: 解释一些内容
预解析解析了哪些内容(熟读并背诵全文)
1. var 关键字声明的变量, 只声明不赋值
2. 声明式函数, 声明函数名的同时赋值为一个函数
*/
// 1. var 的预解析
/*
打开浏览器
预解析:
1. var num
=> 告诉浏览器, 我声明了一个叫做 num 的变量
代码执行:
1. console.log(num)
=> 拿到 num 变量保存的值在控制台输出
2. num = 100
=> 给 num 变量赋值为 100
*/
// console.log(num)
// // 声明 num 变量, 给 num 变量赋值为 100
// var num = 100
// 2. 声明式函数的预解析
/*
打开浏览器
预解析:
1. function fn() { ... }
=> 告诉浏览器, 我定义了一个叫做 fn 的变量, 并且给 fn 赋值为一个函数
代码执行:
1. 上面的 fn()
2. 下面的 fn()
*/
// fn()
// // 声明式函数, 定义 fn 变量的同时赋值为一个函数
// function fn() {
// console.log('我是 fn 函数')
// }
// fn()
// 3. 赋值式函数, 按照 var 的规则进行预解析
/*
打开浏览器
预解析:
1. var fn
=> 告诉浏览器, 我定义了一个叫做 fn 的变量
代码执行:
1. 上面的 fn()
=> 此时, fn 是 undefined
=> 把 udnefined 当做函数来调用
2. fn = function () { ... }
=> 给 fn 变量赋值为一个 函数
3. 下面的 fn()
=> 可以调用了
*/
// fn()
// 按照 var 的规则进行预解析, 预解析只声明不赋值
var fn = function () { console.log(123) }
fn()
/*
预解析的函数和变量重名
+ 在预解析的过程中, 如果出现了函数名和变量名重名, 以函数为准
预解析的学习目的: 为了不要怎么写代码
1. 变量不要先使用后定义
2. 函数名和变量名不要重名
3. 出现了错误, 知道如何查询
*/
/*
打开浏览器
预解析:
1. var num
=> 告诉浏览器, 我定义了一个叫做 num 的变量
2. function num() { ... }
=> 告诉浏览器, 我定义了一个叫做 num 的变量, 并且赋值为一个函数
代码执行:
1. num()
=> 把 num 当做一个函数数据类型调用一下
2. num = 100
=> 给 num 赋值为 100
=> 一个变量只能保存一个值, 使用 100 把 函数数据类型 覆盖了
=> 从此以后, num 保存的就是 100 这个数据了
3. num()
=> 把 num 当做一个函数数据类型调用一下
=> 报错: num is not a function
*/
// num()
// var num = 100
// num()
// function num() { console.log('我是一个函数') }
// num()
/*
打开浏览器
预解析:
1. function num() { ... }
=> 告诉浏览器, 我定义了一个叫做 num 的变量, 并且赋值为一个函数
2. var num
=> 告诉浏览器, 我定义了一个叫做 num 的变量
代码执行:
1. num()
=> 可以执行
2. num()
=> 可以执行
3. num = 100
=> 给 num 变量赋值为 100 这个数据
=> 把 函数数据类型 覆盖了
4. num()
=> 把 num 当做函数来调用一下
=> 报错: num is not a function
*/
// num()
// function num() { console.log('我是一个函数') }
// num()
// var num = 100
// num()
-
作用域 + 一个变量(变量名 和 函数名)的使用范围 + 作用域的分类 => 全局作用域: 打开页面就是一个全局作用域 => 私有作用域: 只有函数生成私有作用域 + 变量定义机制 => 在哪一个作用域内定义的变量, 就是哪一个作用域的私有变量 + 变量使用机制 => 当你需要访问一个变量的值的时候 => 首先在自己作用域内查找, 如果自己作用域有, 直接使用 => 如果没有, 去父级作用域查找 => 如果还没有, 再去父级作用域查找 => 以此类推, 直到全局作用域都没有, 那么就报错, xxx is not defined + 变量赋值机制 => 当你需要给一个变量进行赋值的时候 => 首先在自己作用域内查找, 如果有, 直接赋值 => 如果没有, 给父级作用域的变量赋值 => 如果还没有, 就给再父级作用域的变量赋值 => 以此类推, 直到全局作用域都没有, 会把这个变量定义为全局变量再进行赋值
- 递归函数(了解)
+ 一个函数调用了自身, 并且设置了结束条件 + 我们管这种函数的调用方式叫做递归函数 + 递归函数的书写原则 1. 写函数 2. 先写结束条件 3. 书写未到达终点时的状态
- 对象数据类型
+ 是一个 JS 中的复杂数据类型 + 是一个键值对的集合 + 对象的创建 1. 字面量方式创建 => var obj = {} 2. 内置构造函数创建 => var obj = new Object() 3. 创建带有键值对的对象 => var obj = { 键值对, 键值对, ... } => 键值对: 键: 值
-
对象的基本操作 => 增 -> 对象名.键名 = 值 -> 对象名['键名'] = 值 => 删 -> delete 对象名.键名 -> delete 对象名['键名'] => 改 -> 对象名.键名 = 值 -> 对象名['键名'] = 值 -> 因为对象的键名不重名特点 -> 原先有就是修改, 原先没有就是增加 => 查 -> 对象名.键名 -> 对象名['键名']
-
两套操作语法的区别
+ 操作符合变量定义规则和规范的 key => 可以使用点语法 => 可以使用数组关联语法 + 操作纯数字的 key => 不能使用点语法 => 只能使用数组关联语法 + 操作带有符号的 key => 不能使用点语法 => 只能使用数组关联语法 + 和变量相关的时候 => 点语法只能操作准确的某一个 键名, 和变量没有任何关系 => 数组关联语法, 中括号内书写字符串的时候, 是操作准确的某一个 键名 => 数组关联语法, 中括号内书写变量的时候, 会把变量解析访问
- 遍历对象数据类型
+ 因为 键名 没有规则 + 使用 for in 循环遍历 + 语法: for (var 变量 in 对象名) { ... } => 在循环中, 变量分别表示对象内的每一个键名
- 数据类型之间存储的区别
+ 基本数据类型 => 直接存储在栈内存里面 + 复杂数据类型 => 数据存储在堆内存里面 => 把地址存储在栈内存的变量名里面
- 数据类型之间赋值的区别
+ 基本数据类型 => 赋值以后, 两个变量没有关系, 操作任何一个变量, 另一个不会发生变化 + 复杂数据类型 => 因为赋值的是 地址 => 所以赋值以后, 两个变量操作同一个地址空间 => 使用任何一个变量修改空间内的数据, 另一个变量看到的也是修改后的
*/
5day
数组数据类型
+ 数组是一个 JS 中的复杂数据类型
+ 是一个有序的数据集合
+ 按照 索引 进行数据的排列
1. 创建数组
1-1. 字面量创建
+ 创建空数组: var arr = []
+ 创建带有数据的数组: var arr = [ 数据1, 数据2, 数据3, ... ]
1-2. 内置构造函数创建
+ 创建空数组: var arr = new Array()
+ 创建指定长度的数组: var arr = new Array( 数字 )
+ 创建带有数据的数组: var arr = new Array( 数据1, 数据2, 数据3, ... )
2. 数组的基本操作
2-1. 数组的 length 属性
+ 是一个读写的属性
+ 读: 获取
=> 语法: 数组.length
=> 得到的就是数组的长度, 也就是数组中有多少个数据
+ 写: 设置
=> 语法: 数组.length = 数字
=> 作用: 设置数组的长度
=> 结果
-> 当你设置的数字比本身的 length 小的时候, 那么从 后面 开始删除
-> 当你设置的数字和本身的 length 一样的时候, 那么就是没有设置
-> 当你设置的数字比本身的 length 大的时候, 那么多出来的位置使用 empty 补齐
2-2. 数组的 索引 属性
+ 是一个读写的属性
+ 读: 获取
=> 语法: 数组[索引]
=> 得到的就是数组该索引位置的数据
-> 如果数组中有该索引位置, 那么就是该索引位置的数据
-> 如果数组中没有该索引位置, 那么就是 undefined
+ 写: 设置
=> 语法: 数组[索引] = 值
=> 作用: 设置数组某一个索引位置的数据
=> 结果:
-> 如果数组中有该索引位置, 那么就是修改该索引位置的数据
-> 如果设置的索引和 length 一样, 那么就是在数组的后面追加一条数据
-> 如果设置的索引比 length 大, 那么中间空出来的位置使用 empty 补齐
2-3. 数组的 遍历
+ 使用 for 循环进行遍历
+ 因为数组的索引是一组有规律的数字(从 0 开始, 依次 +1)
+ for 循环可以提供一组有规律的数字
+ 我们可以使用 循环控制变量 当做数组的索引进行遍历
for (var i = 0; i < xxx.length; i++) {
// 数组中的每一个就是 xxx[i]
}
3. 两个排序算法
3-1. 冒泡排序
for (var i = 0; i < arr.length - 1; i++) {
for (var j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
var tmp = arr[j]
arr[j] = arr[j + 1]
arr[j + 1] = tmp
}
}
}
3-2. 选择排序
for (var i = 0; i < arr.length - 1; i++) {
var minIndex = i
for (var j = i + 1; j < arr.length; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j
}
}
var tmp = arr[i]
arr[i] = arr[minIndex]
arr[minIndex] = tmp
}
4. 数组常用方法
4-1. push()
=> 在数组的后面插入数据
4-2. pop()
=> 删除数组的最后一个
4-3. unshift()
=> 在数组的前面插入数据
4-4. shift()
=> 删除数组的第一个
4-5. reverse()
=> 反转数组
4-6. sort()
=> 数组排序
=> xxx.sort()
=> xxx.sort(function (a, b) { return a - b })
=> xxx.sort(function (a, b) { return b - a })
4-7. splice()
=> 截取数组并选择性插入数据
=> xxx.splice(开始索引, 多少个)
=> xxx.splice(开始索引, 多少个, 数据)
=> 注意: 插入数据的时候, 从哪里删除, 从哪里插入
================= 以上七个方法会直接改变原始数组 =================
4-8. concat()
=> 进行数组拼接
4-9. join()
=> 使用连接符进行数组连接, 返回值是一个字符串类型
=> xxx.join(连接符)
=> 连接符不写默认是 逗号(,)
4-10. slice()
=> 进行数组截取
=> xxx.slice(开始索引, 结束索引)
=> 特点: 包前不包后
4-11. indexOf()
=> 查找某一个数据在该数组中的索引位置, 从前向后查找
=> xxx.indexOf(数据)
=> xxx.indexOf(数据, 开始索引)
4-12. lastIndexOf()
=> 查找某一个数据在该数组中的索引位置, 从后向前查找
=> xxx.lastIndexOf(数据)
=> xxx.lastIndexOf(数据, 开始索引)
4-13. forEach()
=> 遍历数组
=> 没有返回值
4-14. map()
=> 映射数组
=> 对原始数组中的每一个进行操作, 放在新数组里面返回
=> 返回值是一个新数组
4-15. filter()
=> 过滤数组
=> 把原始数组中满足条件的项放在新数组里面返回
4-16, find()
=> 查找数据
=> 查找原始数组中满足条件的数据
4-17. every()
=> 判断数组中是不是每一项都满足条件
=> 返回值是 布尔值
=> 当数组中所有数据都满足条件的时候, 返回值是 true
=> 只要数组中有任何一个项不满足条件的时候, 返回值是 false
4-18. some()
=> 判断数组中是不是有某一个满足条件
=> 返回值是 布尔值
=> 只要数组中有任何一个满足条件, 那么返回值就是 true
=> 只有数组中所有都不满足条件的时候, 返回值是 false
/*
6day
回顾
1. 字符串的常用方法
1-1. toLowerCase()
=> 转小写
1-2. toUpperCase()
=> 转大写
1-3. charAt()
=> 根据索引获取字符串中某一个索引的字符
1-4. charCodeAt()
=> 根据索引找到对应字符的 编码
1-5. split()
=> 把字符串按照分隔符切割成数组
=> 注意: 返回值是一个数组
1-6. replace()
=> 进行字符串替换
=> xxx.replace('换下', '换上')
=> 注意:
-> 不改变原始字符串
-> 只能替换一个内容
1-7. substr()
=> 截取字符串
=> xxx.substr(开始索引, 多少个)
1-8. substring()
=> 截取字符串
=> xxx.substring(开始索引, 结束索引)
=> 特点: 包前不包后
1-9. slice()
=> 截取字符串
=> xxx.slice(开始索引, 结束索引)
=> 特点:
-> 包前不包后
-> 可以填写负整数
1-10. concat()
=> 拼接字符串
1-11. indexOf()
=> 从前向后找到该字符片段在原始字符串中第一次出现的位置
1-12. lastIndexOf()
=> 从后向前找到该字符串片段在原始字符串中第一次出现的位置
1-13. trim()
=> 去除收尾空白
1-14. trimStart() / trimLeft()
=> 去除前面空白
1-15. trimEnd() / trimRight()
=> 去除后面空白
2. 操作数字的方法
2-1. Math.random()
=> 获取 0 ~ 1 之间的随机小数, 包含 0 不包含 1
2-2. Math.round()
=> 四舍五入取整
2-3. Math.ceil()
=> 向上取整
2-4. Math.floor()
=> 向下取整
2-5. Math.pow()
=> 取幂
2-6. Math.sqrt()
=> 计算算数平方根
2-7. Math.abs()
=> 取绝对值
2-8. Math.max(数字1, 数字2, ...)
=> 取到若干个数字的最大值
2-9. Math.min(数字1, 数字2, ....)
=> 取到若干个数字的最小值
2-10. Math.PI
=> 是属性不是方法, 使用不需要 ()
=> 取到的是一个近似 π 的值
3. 保留小数位
3-1. toFixed()
=> 返回值是一个字符串类型
=> 保留小数位的时候, 不够的时候使用 0 补齐
4. 转换进制
4-1. toString()
=> 十进制转换成其他进制
=> 参数: 取值范围 2 ~ 36
4-2. parseInt()
=> 其他进制转化成十进制
=> 语法: parseInt(数字, 把数字当做几进制)
=> 返回值: 数值类型
5. 范围内随机整数的封装
function randomNum(min, max) {
// 1. 确定两个数字的大小
var a = Math.min(min, max)
var b = Math.max(min, max)
// 2. 计算随机整数
var res = Math.floor(Math.random() * (b - a + 1)) + a
// 3. 把计算结果返回
return res
}
*/
7day
/*
1. 创建时间对象
+ 语法: var time = new Date()
+ 创建当前时间: new Date()
+ 创建指定时间:
=> new Date(年, 月, 日, 时, 分, 秒, 毫秒)
=> 注意:
1. 至少传递两个参数
2. 月份信息 0 表示 1 月, 11 表示 12 月
3. 每一个参数位置, 可以自动进位
=> new Date('YYYY-MM-DD hh:mm:ss')
=> new Date('YYYY/MM/DD hh:mm:ss')
=> 注意:
1. 年月日 和 时分秒 之间有一个空格
2. 月份信息 1 表示 1 月, 12 表示 12 月
2. 时间对象的常用方法
2-1. 获取
=> getFullYear()
=> getMonth()
=> getDate()
=> getHours()
=> getMinutes()
=> getSeconds()
=> getMilliSeconds()
=> getDay()
=> getTime()
2-2. 设置
=> setFullYear(年份信息)
=> setMonth(月份信息)
=> setDate(日期信息)
=> setHours(小时信息)
=> setMinutes(分钟信息)
=> setSeconds(秒钟信息)
=> setMilliSeconds(毫秒信息)
=> setTime(时间戳)
3. BOM
+ Browser Object Model 浏览器对象模型
+ 一整套操作浏览器相关信息的属性和方法
3-1. 获取浏览器可视窗口尺寸
=> window.innerWidth
=> window.innerHeight
=> 获取到的是包含滚动条的尺寸
3-2. 浏览器的弹出层
=> window.alert()
=> window.confirm()
=> window.prompt()
=> 共同点: 都会阻断程序的继续执行, 知道用户操作为止
3-3. 浏览器的历史记录
=> 历史回退: window.history.back()
=> 历史前进: window.history.forward()
=> 历史跳转: window.history.go(整数)
-> 正整数: 前进
-> 0: 从新当大当前页面
-> 负整数: 回退
3-4. 浏览器的地址栏
=> window.location.href
=> 读: window.location.href
-> 获取到的就是当前页面的地址栏完整地址
=> 写: window.location.href = '地址'
-> 在当前页面进行地址跳转
=> window.location.reload()
=> 重新打开当前页面
3-5. 浏览器的信息
=> 型号及版本信息: window.navigator.userAgent
=> 浏览器名称: window.navigator.appName
=> 浏览器版本信息: window.navigator.apppVersion
=> 操作系统信息: window.navigator.platform
3-6. 浏览器常见事件
=> 所有资源加载完毕 : window.onload = function () { ... }
=> 可视窗口尺寸改变 : window.onresize = function () { ... }
=> 滚动条位置改变 : window.onscroll = function () { ... }
3-7. 浏览器卷去的尺寸
=> 高度:
-> document.documentElement.scrollTop
-> document.body.scrollTop
=> 宽度
-> document.documentElement.scrollLeft
-> document.body.scrollLeft
3-8. 浏览器滚动到
=> 语法: window.scrollTo()
=> 参数:
-> 方案1: 传递两个数字
-> window.scrollTo(x, y)
-> 注意: 必须传递两个参数, 只能进行瞬间定位
-> 方案2: 传递一个对象
-> window.scrollTo({ top: xx, left: xx, behavior: 'smooth' })
-> 可以只传递一个 top 或者 left
3-9. 浏览器的标签页
=> 打开新的标签页开启地址: window.open('地址')
=> 关闭当前标签页: window.close()
4. 定时器
4-1. 开启定时器
=> 延时定时器: setTimeout(函数, 数字)
=> 间隔定时器: setInterval(函数, 数字)
=> 数字: 单位是 ms, 表示多少时间以后
4-2. 定时器返回值
=> 不区分定时器种类
=> 只是表示你也页面上的第几个定时器
=> 作用: 用来关闭定时器的时候使用
4-3. 关闭定时器
=> cleatTimeout(定时器返回值)
=> clearInterval(定时器返回值)
=> 不区分定时器种类, 只要给的定时器返回值对, 就能关闭定时器
5. 异步代码执行机制
=> 目前只有定时器算是 异步代码
=> 当代码从上到下的之后, 遇到异步代码的时候
=> 不会执行, 会把异步代码放在队列里面等待
=> 等到所有同步代码执行完毕, 在回来到队里里面去执行异步代码
=> 队列执行机制: 先进先出
=> 定时器: 先执行定时器外面的代码, 后执行定时器里面的代码
*/
8day
/* DOM + 页面文档流里面的内容进行操作
1. 获取 DOM 元素
+ 目的: 为了确定我要操作哪一个元素或者哪一些元素
+ 作用: 更灵活的捕获到各种我要操作的元素
1-1. 通过 id 获取
=> 语法: document.getElementbyId('id名称')
=> 返回值:
-> 如果有 id 对应的元素, 那么就是这个元素
-> 如果没有 id 对应的元素, 那么就是 null
1-2. 通过 类名 获取
=> 语法: document.getElementsByClassName('类名')
=> 返回值: 必然是一个伪数组
-> 如果有 类名 对应的元素, 那么有多少获取多少
-> 如果没有 类名 对应的元素, 那么就是一个空的伪数组
1-3. 通过 标签名 获取
=> 语法: document.getElementsByTagName('标签名')
=> 返回值: 必然是一个伪数组
-> 如果有 标签名 对应的元素, 那么有多少获取多少
-> 如果没有 标签名 对应的元素, 那么就是一个空的伪数组
1-4. 通过 name 获取
=> 语法: document.getElementsByName('name 属性的值')
=> 返回值: 必然是一个伪数组
-> 如果有 name 对应的元素, 那么有多少获取多少
-> 如果没有 name 对应的元素, 那么就是一个空的伪数组
1-5. 通过 选择器 获取一个元素
=> 语法: document.querySelector('选择器')
=> 返回值:
-> 如果有 选择器 对应的元素, 那么是满足条件的 第一个
-> 如果没有 选择器 对应的元素, 那么就是 null
1-6. 通过 选择器 获取一组元素
=> 语法: document.querySelectorAll('选择器')
=> 返回值: 必然是一个伪数组
-> 如果有 选择器 对应的元素, 那么有多少获取多少
-> 如果没有 选择器 对应的元素, 那么就是一个空的伪数组
2. 操作元素属性
2-1. 操作原生属性
=> 获取: 元素.属性名
=> 设置: 元素.属性名 = '值'
2-2. 操作自定义属性
=> 获取: 元素.getAttribute('属性名')
=> 设置: 元素.setAttribute('属性名', '属性值')
=> 删除: 元素.removeAttribute('属性名')
2-3. 操作 H5 自定义属性
=> 元素身上有一个叫做 dataset 的属性, 记录的是元素身上所有 data- 开头的自定义属性
=> 对于 H5 自定义属性的操作, 就是对这个 dataset 的操作
=> 获取: 元素.dataset.属性名
=> 设置: 元素.dataset.属性名 = '值'
=> 删除: delete 元素.dataset.属性名
=> 注意: H5 自定义的属性名是不包含 data- 的部分
3. 操作元素类名
3-1. className
=> 获取: 元素.className
=> 设置: 元素.className = '值'
=> 追加: 元素.className += ' 值'
3-2. classList
=> 每一个元素身上有一个叫做 classList 的属性, 记录的是所有的类名
=> 添加: 元素.classList.add('新类名')
=> 删除: 元素.classList.remove('类名')
=> 切换: 元素.classList.toggle('类名')
+ 一般都是用于切换元素的样式
4. 操作元素样式
4-1. 获取元素行内样式
=> 元素.style.样式名
=> 注意:
-> 只能获取到元素的行内样式
-> 带有中划线的样式需要修改为驼峰或者使用数组关联语法
4-2. 设置元素行内样式
=> 元素.style.样式名 = '样式值'
=> 注意:
-> 带有中划线的样式需要修改为驼峰或者使用数组关联语法
-> 一次只能设置一个样式
4-3. 获取元素非行内样式
=> 标准浏览器
-> 语法: window.getComputedStyle(元素).样式名
=> IE 低版本
-> 语法: 元素.currentStyle.样式名
5. 操作元素内容
5-1. 操作超文本内容
=> 获取: 元素.innerHTML
=> 设置: 元素.innerHTML = '值'
=> 注意:
-> 设置的时候是完全覆盖式的设置
-> 会解析 html 结构的字符串
5-2. 操作文本内容
=> 获取: 元素.inenrText
=> 设置: 元素.innerText = '值'
=> 注意:
-> 设置的时候是完全覆盖式的设置
-> 不会解析 html 结构的字符串
5-3. 操作 value 值
=> 获取: 元素.value
=> 设置: 元素.value = '值'
=> 注意:
-> 设置的时候是完全覆盖式的设置
-> select 的 value 是选中的那个 option 的 value
*/
9day
回顾
1.获取节点
1-1.专门获取元素节点
=>getElelementById()
=> getElementsByClassName()
=> getElementsByTagName()
=> getElementsByName()
=> querySelector()
=> querySelectorAll()
1-2. 专门获取节点(包含但不限于元素节点) => children => childNodes => firstChild => firstElementChild => lastChild => lastElementChild => previousSibling => previousElementSibling => nextSibling => nextElementSibling => parentNode => parentElement => attributes
- 创建节点 => createElement() => createTextNode() => createDocumentFragment() 文档碎片
- 插入节点 => appendChild() => insertBefore()
- 删除节点 => removeChild() => remove()
- 替换节点 => replaceChild(换上节点, 换下节点)
- 克隆节点 => cloneNode() => 参数默认是 false, 表示不克隆后代节点 => 参数选填是 true, 表示克隆后代节点
- 获取元素尺寸(占地面积) => offsetWidth 和 offsetHeight -> 获取到的是元素 内容 + padding + border 的尺寸 -> 不管盒子模型是什么样, 获取到的区域不变 -> 当元素在文档流不占位的时候, 获取不到尺寸 => clientWidth 和 clientHeight -> 获取到的是元素 内容 + padding 区域的尺寸 -> 不管盒子模型是什么样, 获取到的区域不变 -> 当元素在文档流不占位的时候, 获取不到尺寸
8. 获取元素偏移量
=> offsetLeft 和 offsetTop
-> 获取的是相对于 参考元素 的左上角的偏移量
-> 参考元素: 该元素的定位父级
=> clientLeft 和 clientTop
-> 获取的是自己本身 padding + 内容区域 相对于 自己本身 border 左上角的尺寸
-> 实际上就是 上边框 和 左边框 的宽度
9. DOM 级别获取可视窗口尺寸
=> 宽度: document.documentElement.clientWidth
=> 高度: document.documentElement.clientHeight
*/
// var box = document.querySelector('box')
// 报错信息 : Cannot set property 'onclick' of null
// 不能给 null 设置 onclick
// 代码 : 给 box 设置 onclick
// 问题 : box 是 null
// box.onclick = function () {
// console.log('我被点击了')
// }
// 报错信息 : Cannot read property 'innerHTML' of null
// 不能从 null 里面读取 innerHTML
// 代码 : 从 box 内读取 innerHTML 内容
// 问题 : box 是 null
// console.log(box.innerHTML)
/*
总结:
Cannot set property 'onclick' of null
Cannot set property 'onclick' of undefined
Cannot read property 'innerHTML' of null
Cannot read property 'innerHTML' of undefined
代码:
xxx.yyy = zzz
或者
xxx.yyy
问题:
xxx 一定是 null 或者 undefined
*/
/* 认识事件 + 由 前端 和 页面中的内容做一个约定, 就叫做事件绑定 + 由 浏览 网页的人进行行为的触发 => 例子: box.onclick = function () {} 和 box 这个元素约定好了一个 点击 行为 当 用户 点击这个 box 元素的时候, 就会触发对应的函数
事件三要素
1. 事件源: 谁身上的事件
2. 事件类型: 什么事件
3. 事件处理函数: 当行为发生的时候, 执行的函数
绑定事件的方式
1. DOM 0级 事件
=> 语法: 事件源.on事件类型 = 事件处理函数
=> 特点:
1. 只能给同一个事件源同一个事件类型绑定一个事件处理函数
-> 因为他使用的是 赋值符号(=), 所以当你给他第二次赋值的时候, 会把第一次覆盖
2. DOM 2级 事件 (事件侦听器 / 事件监听器)
=> 标准浏览器
-> 语法: 事件源.addEventListener('事件类型', 事件处理函数)
-> 特点:
1. 可以给同一个事件源同一个事件类型绑定多个事件处理函数
2. 当有多个事件处理函数的时候, 顺序绑定顺序执行
3. 事件类型位置没有 on
=> IE 低版本
-> 语法: 事件源.attachEvent('on事件类型', 事件处理函数)
-> 特点:
1. 可以给同一个事件源同一个事件类型绑定多个事件处理函数
2. 当有多个事件处理函数的时候, 顺序绑定倒序执行
3. 事件类型位置需要书写 on
*/
// 0. 获取元素
// var box = document.querySelector('div')
var box = document.getElementsByTagName('div')[0]
// 1. 绑定事件
// 事件绑定阶段, 函数内的代码是不执行的
// 事件源: box, 事件是绑定在 box 身上的
// 事件类型: click, 点击行为
// 事件处理函数: a 函数, 当点击行为发生在 box 身上的时候, 会执行 a 函数
// box.onclick = function a() {
// console.log('你好 世界')
// }
// 之前的代码. 给 onclick 赋值为 a 函数
// 现在的代码, 给 onclick 赋值为 b 函数, 就会把之间赋值的 a 函数覆盖
// box.onclick = function b() {
// console.log('我是 第二个 事件处理函数')
// }
// 2. 标准浏览器的 DOM2级 事件(事件侦听器)
// box.addEventListener('click', function () { console.log('第一个事件处理函数') })
// box.addEventListener('click', function () { console.log('第二个事件处理函数222222') })
// 3. IE 低版本的 DOM2级 事件(事件侦听器) box.attachEvent('onclick', function () { console.log('事件处理函数 1111111') }) box.attachEvent('onclick', function () { console.log('事件处理函数 22222222') }) /* 事件解绑 + DOM 0级 解绑事件 => 因为绑定是使用的 赋值符号(=) => 当你给他赋值为 null 的时候, 就会把事件处理函数覆盖 => 相当于你触发行为的时候, 没有事件处理函数执行, 就相当于没有绑定事件 + DOM 2级 解绑事件 => 标准浏览器: -> 语法: 事件源.removeEventListener('事件类型', 要解绑的事件处理函数) -> 注意: 如果你想进行事件解绑, 那么在绑定的时候一定要把事件处理函数单独书写出来 以函数名的形式进行绑定 => IE 低版本: -> 语法: 事件源.detachEvent('on事件类型', 要解绑的事件处理函数) -> 注意: 如果你想进行事件解绑, 那么在绑定的时候一定要把事件处理函数单独书写出来 以函数名的形式进行绑定 */
// 获取元素
var box = document.getElementsByTagName('div')[0]
var btn = document.getElementsByTagName('button')[0]
// 1. DOM 0级 事件绑定
// box.onclick = function () { console.log('我被点击了') }
// btn.onclick = function () {
// console.log('我要解绑事件')
// // 解绑事件
// box.onclick = null
// console.log('解绑事件的代码执行完毕了')
// }
// 2-1. 标准浏览器 // function handlerA() { console.log('111111111111') } // function handlerB() { console.log('222222222') } // box.addEventListener('click', handlerA) // box.addEventListener('click', handlerB)
// btn.onclick = function () {
// console.log('我要解绑事件')
// // 解绑事件
// box.removeEventListener('click', handlerB)
// console.log('解绑事件的代码执行完毕了')
// }
// 2-2. IE 低版本
function handlerA() { console.log('11111') }
function handlerB() { console.log('222222222222') }
box.attachEvent('onclick', handlerA)
box.attachEvent('onclick', handlerB)
btn.onclick = function () {
console.log('我要解绑事件')
// 解绑事件
box.detachEvent('onclick', handlerB)
console.log('解绑事件的代码执行完毕了')
}
/*
鼠标事件:
+ 依赖鼠标行为触发的事件
+ 两套鼠标移入移出事件的区别
=> over 和 out 一套, 当你移入后代元素的时候, 一样会触发
=> enter 和 leave 一套, 当你移入后代元素的时候, 不会触发
1. click: 鼠标左键单击
2. dblclick: 鼠标左键双击
3. contextmenu: 鼠标右键单击
4. mousedown: 鼠标按下(任何一个按键按下都会触发)
5. mouseup: 鼠标抬起
6. mousemove: 鼠标移动
7. mouseover: 鼠标移入
8. mouseout: 鼠标移出
9. mouseenter: 鼠标移入
10. mouseleave: 鼠标移出
*/
// 0. 获取元素
var box = document.querySelector('div')
// 1. click
// 约定好只要有单击行为就会触发
// box.onclick = function () { console.log('左键单击') }
// 2. dblclick
// 约定好只要有双击行为就会触发
// 但是一个双击行为需要由两个单击行为组成
// box.ondblclick = function () { console.log("左键双击") }
// 3. contextmenu
// box.oncontextmenu = function () { console.log('右键单击') }
// 4. mousedown
// box.onmousedown = function () { console.log('鼠标按下了') }
// 5. mouseup
// box.onmouseup = function () { console.log('鼠标抬起') }
// 6. mousemove
// box.onmousemove = function () { console.log('鼠标移动') }
// 7. mouseover
// box.onmouseover = function () { console.log('鼠标移入') }
// 8. mouseout
// box.onmouseout = function () { console.log('鼠标移出') }
// 9. mouseenter
box.onmouseenter = function () { console.log('鼠标移入222') }
// 10. mouseleave
box.onmouseleave = function () { console.log('鼠标移出222') }
/*
键盘事件 + 注意: 任何元素都可以绑定, 但是不是所有元素都能触发 => window / document / 可选中元素(表单元素) + 注意: 键盘按下事件, 不要去识别中文输入法
1. keydown: 键盘按下(任何一个按键按下都会触发)
2. keyup: 键盘抬起
3. keypress: 键盘键入
=> 需要按下可键入按键, 或者 回车 按键, 才会触发
*/
// 0. 获取元素
var inp = document.querySelector('input')
// 1. keydown
inp.onkeydown = function () { console.log('键盘按下了') }
// 2. keyup
// inp.onkeyup = function () { console.log('键盘抬起了') }
// 3. keypress
inp.onkeypress = function () { console.log('键盘键入') }
/*
表单事件:
+ 绑定给表单元素的事件
=> form / input / textarea / select / ...
1. focus: 表单聚焦
2. blur: 表单失焦
3. change: 表单改变
=> 在失焦的时候判断, 如果和聚焦的时候不一样, 就会触发
4. input: 表单输入
=> 只要你在表单内输入内容或者删除内容都会触发
=> 随着你的操作, 只要文本内容改变了就会触发
5. reset: 表单重置事件
=> 事件需要绑定在 form 标签身上
=> 当你点击 reset 按钮的时候, 会触发 form 的表单重置行为, 此时触发事件
6. submit: 表单提交事件
=> 事件需要绑定在 form 标签身上
=> 当你点击 submit 按钮的时候, 会触发 form 的表单提交行为, 此时触发事件
*/
// 0. 获取元素
var inp = document.querySelector('input')
var form = document.querySelector('form')
// 1. focus
// inp.onfocus = function () { console.log('聚焦') }
// 2. blur
// inp.onblur = function () { console.log('失焦') }
// 3. change
// inp.onchange = function () { console.log('表单改变了') }
// 4. input
// inp.oninput = function () { console.log('表单在输入内容') }
// 5. reset
// form.onreset = function () { console.log('表单重置了') }
// 6. submit
// form.onsubmit = function () { console.log('表单提交了') }
/*
触摸事件
+ 依赖触摸行为发生的事件
+ 注意: 触控板不算, 一定是直接可页面元素发生触摸行为
1. touchstart: 触摸开始
=> 当你的手指接触到屏幕的瞬间
2. touchmove: 触摸移动
=> 当你的手指在屏幕上移动
3. touchend: 触摸结束
=> 当你的手指离开屏幕的瞬间
*/
// 0. 获取元素
var div = document.querySelector('div')
// 1. touchstart
div.ontouchstart = function () { console.log('触摸开始') }
// 2. touchmove
div.ontouchmove = function () { console.log('触摸移动') }
// 3. touchend
div.ontouchend = function () { console.log('触摸结束') }
/*
其他事件
1. selectstart
+ 当你开始需要选中文本的时候触发
2. transitionend
+ 过渡结束的时候触发
+ 过渡多少个属性, 就触发多少回
*/
// 1. selectstart
// document.onselectstart = function () {
// alert('请登录后复制')
// return false
// }
// 2. transitionend
var box = document.querySelector('div')
box.ontransitionend = function () { console.log('过渡结束了') }
/*
常见的事件类型
+ 注意: JS 的原生事件里面没有大写字母
+ JS 里面把事件分成几个大类
1. 鼠标事件
=> click
=> dblclick
=> contextmenu
=> mousedown
=> mouseup
=> mousemove
=> mouseover
=> mouseout
=> mouseenter
=> mouseleave
2. 键盘事件
=> keydown
=> keyup
=> keypress
3. 浏览器事件
=> load
=> resize
=> scroll
4. 表单事件
=> focus
=> blur
=> change
=> input
=> reset
=> submit
5. 触摸事件
=> touchstart
=> touchmove
=> touchend
6. 其他事件
=> selectstart
=> transitionend
=> transitionstart
=> animationend
=> animationstart
=> ...
*/
10day
事件的名词
1. 事件源: 给谁绑定事件
2. 事件类型: 绑定什么事件
3. 事件处理函数: 当行为发生的时候, 执行的函数
4. 事件侦听器(事件监听器): DOM2级 事件
=> DOM0级 事件
-> 语法: 事件源.on事件类型 = 事件处理函数
-> 特点: 只能给同一个事件源的同一个事件类型绑定一个事件处理函数
=> DOM2级 事件
-> 标准浏览器: 事件源.addEventListener('事件类型', 事件处理函数)
+ 特点: 可以给同一个事件源的同一个事件类型绑定多个事件处理函数
绑定多个事件处理函数的时候, 顺序绑定顺序执行
-> IE 低版本: 事件源.attachEvent('on事件类型', 事件处理函数)
+ 特点: 可以给同一个事件源的同一个事件类型绑定多个事件处理函数
绑定多个事件处理函数逇时候, 顺序绑定倒序执行
5. 事件解绑: 取消事件绑定
=> DOM0级 事件解绑:
-> 语法: 事件源.on事件类型 = null
=> DOM2级 事件解绑:
-> 标准浏览器: 事件源.removeEventListener('事件类型', 要解绑的事件处理函数)
-> IE 低版本: 事件源.detachEvent('on事件类型', 要解绑的事件处理函数)
-> 注意: 如果你需要解绑事件, 那么绑定的时候, 需要把事件处理函数单独书写出来
以函数名的形式进行绑定和解绑
6. 事件对象: 一个对象数据类型, 存储的都是和本次事件相关的信息
=> 由浏览器自动记录
=> 获取事件对象
-> 标准浏览器: 直接在事件处理函数位置书写形参, 会在事件触发的时候由浏览器自动传递实参
-> IE 低版本: 直接使用 window.event
=> 事件对象里面的一些信息
-> 鼠标事件
+ clientX 和 clientY: 相对浏览器可视窗口左上角
+ pageX 和 pageY: 相对于页面文档流左上角
+ offsetX 和 offsetY: 相对触发事件的元素的左上角
-> 键盘事件
+ keyCode 表示的是键盘编码
+ 组合按键
=> shiftKey
=> ctrlKey
=> sltKey
=> metaKey
offset 家族
1. offsetWidth 和 offsetHeight
=> 获取的元素的 内容 + padding + border 的尺寸
=> 注意: 元素.offsetWidth 和 元素.offsetHeight
2. offsetLeft 和 offsetTop
=> 获取的元素相对于 参考元素 的 偏移量
=> 注意: 元素.offsetLeft 和 元素.offsetTop
3. offsetX 和 offsetY
=> 获取的光标相对于触发事件的元素的左上角的坐标位置
=> 注意: 事件对象.offsetX 和 事件对象.offsetY
client 家族
1. clientWidth 和 clientHeight
=> 获取元素的 内容 + padding 的尺寸
=> 注意: 元素.clientWidth 和 元素.clientHeight
2. clientLeft 和 clientTop
=> 获取元素 padding + 内容 区域相对于自己的 border 左上角的尺寸
=> 实际上就是 左边框 和 上边框 的宽度
=> 注意: 元素.clientLeft 和 元素.clientTop
3. clientX 和 clientY
=> 获取的是光标相对于可视窗口左上角的尺寸
=> 注意: 事件对象.clientX 和 事件对象.clientY
10day
名词解释:
1. 事件源: 谁身上的事件
2. 事件类型: 什么事件
3. 事件处理函数: 当行为发生在 事件源 的时候, 所执行的函数
4. 事件侦听器(事件监听器): 另一种绑定事件的方式
=> DOM 0级 事件
-> 语法: 事件源.on事件类型 = 事件处理函数
-> 只能给同一个事件源的同一个事件类型绑定一个事件处理函数
=> DOM 2级 事件
-> 标准浏览器: 事件源.addEventListener('事件类型', 事件处理函数)
+ 可以给同一个事件源的同一个事件类型绑定多个事件处理函数
+ 顺序绑定顺序执行
-> IE 低版本: 事件源.attachEvent('on事件类型', 事件处理函数)
+ 可以给同一个事件源的同一个事件类型绑定多个事件处理函数
+ 顺序绑定倒序执行
5. 事件解绑
=> DOM 0级 事件
-> 语法: 事件源.on事件类型 = null
=> DOM 2级 事件
-> 标准浏览器: 事件源.removeEventListener('事件类型', 要解绑的事件处理函数)
-> IE 低版本: 事件源.detachEvent('on事件类型', 要解绑的事件处理函数)
-> 注意: 如果你需要解绑事件, 那么在绑定的时候, 需要单独书写事件处理函数, 以函数名的形式进行绑定和解绑
6. 事件对象
=> 一个对象数据类型, 用来描述本次事件的所有相关信息
=> 获取:
-> 标准浏览器: 在事件处理函数位置书写一个形参, 会在事件触发的时候, 由浏览器自动传递实参
-> IE 低版本: 直接使用 window.event
=> 兼容:
-> e = e || window.event
7. 事件传播
=> 当事件触发的时候
=> 会按照结构父级的顺序, 传递事件的行为
=> 过程: 从 window 到你准确触发事件的元素 到 window
=> 标准浏览器下: 事件默认是在 从里到外 的阶段触发
=> IE 低版本下: 事件只能在 从里到外 的阶段触发
8. 事件目标
=> 当事件触发的时候, 那个准确触发事件的元素
9. 事件捕获
=> 在事件传播的过程中
=> 从外到里 的过程叫做 事件捕获
=> 从 window 到 事件目标 的传播过程
10. 事件冒泡
=> 在事件传播的过程中
=> 从里到外 的过程叫做 事件冒泡
=> 从 事件目标 到 window 的传播过程
11. 阻止事件传播
=> 标准浏览器: 事件对象.stopPropagation()
=> IE 低版本: 事件对象.cancelBubble = true
=> 兼容: try { 事件对象.stopPropagation() } catch(err) { 事件对象.cancelBubble = true }
12. 事件委托
=> 把自己的事件, 绑定在结构父级身上
=> 在结构父级的事件内, 通过事件目标判断准确触发事件的元素
=> 例子: ul > li 的结构
ul.onclick = function (e) {
// 处理事件对象兼容
e = e || window.event
// 处理事件目标兼容
var target = e.target || e.srcElement
// 判断你准确点击的是 li
if (target.tagName === 'LI') {
// 书写本身应该绑定在 li 身上的事件逻辑代码
// target 就是你准确点击的那一个 li
}
}
13. 默认事件
=> 不需要绑定, 本身就带有的事件行为
14. 阻止默认事件
=> 标准浏览器: 事件对象.preventDefault()
=> IE 低版本: 事件对象.returnValue = false
=> 兼容语法: try { 事件对象.preventDefault() } catch(err) { 事件对象.returnValue = false }
=> 通用语法: return false
-> 注意写在事件处理函数的最后一行
-> 前面的代码注意不要出错
注意:
+ 分清 事件源 和 事件目标
11day
-
正则表达
+ 是一个验证字符串的规则 + 创建正则表达式的两种方式 1-1. 字面量方式 => var reg = /abcd/ig 1-2. 内置构造函数创建方式 => var reg = new RegExp('abcd', 'ig')
- 创建正则表达式的区别
2-1. 标识符的书写 => 字面量方式是直接书写在正则表达式的后面 => 内置构造函数是在第二个参数的位置书数写 2-2. 拼接变量 => 字面量方式不能拼接变量 => 内置构造函数可以拼接变量 2-3. 书写基本元字符的方式 => 字面量内书写的时候 \s\d\w => 在内置构造函数方式书写的时候, \\s\\d\\w
- 元字符
3-1. 基本元字符 => \s => \S => \d => \D => \w => \W => . => \ 3-2. 边界元字符 => ^ => $ => 当两个符号一起使用的时候, 表示从开头到结尾 3-3. 修饰符 => 修饰符只修饰前面一个内容 => * => + => ? => {n} => {n,} => {n,m} 3-4. 特殊符号 => () => (?:) => | => [] => [^] => - 3-5. 非贪婪修饰符 => *? => +? => ?? => {n,}? => {n,m}?
- 标识符 4-1. i 4-2. g
- 正则的两个常用方法 5-1. 匹配 : test() 5-2. 捕获 : exec()
- 字符串常用方法和正则合作的 6-1. replace() 6-2. search() 6-3. match()
13day
-
自执行函数
+ 一个定义完毕马上把自己调用的函数 + 语法: => (function () { ... })() => ~function () { ... }() => !function () { ... }()
- json 格式的字符串
+ 一种字符串的特殊格式, 用于前后端交互的时候使用 + 语法: => 把 JS 的数据格式转换成 json 格式的数据 -> JSON.stringify(JS的数据格式) => 把 json 格式的字符串转换成 JS 格式的数据 -> JSON.parse(json格式字符串)
- this 指向
+ this 是一个使用在作用域内部的关键字 + 当你使用在函数内的时候 + 不管函数怎么定义, 不管函数在哪定义, 只看函数的调用方式(箭头函数除外) => 普通调用 -> 函数名() -> 函数内的 this 指向 window => 对象调用 -> 对象名.函数名() -> 函数内的 this 指向 点前面是谁就是谁 => 定时器处理函数 -> setTimeout(函数, 数字) -> setInterval(函数, 数字) -> 函数内的 this 指向 window => 事件处理函数 -> xxx.onclick = function () {} -> xxx.addEvenListener(事件类型, function () {}) -> 函数内的 this 指向 事件源(谁身上的事件) => 自执行函数 -> (函数)() -> ~函数() -> !函数() -> 函数内的 this 指向 window => 箭头函数 -> () => {} -> 没有 this -> 函数内的 this 指向 外部函数的 this => 未完待续... 4. 强行改变 this 指向 4-1. call() => 语法: -> 函数名.call() -> 对象名.函数名.call() => 参数: -> 第一个参数是改变的函数内的 this 指向 -> 第二个参数开始依次是给函数的形参赋值 => 特点: -> 会立即调用函数 4-2. apply() => 语法: -> 函数名.apply() -> 对象名.函数名.apply() => 参数: -> 第一个参数是改变的函数内的 this 指向 -> 第二个参数是一个数组或者伪数组, 内部的每一项是给函数的形参赋值 => 特点: -> 会立即调用函数 4-3. bind() => 语法: -> 函数名.bind() -> 对象名.函数名.bind() => 参数: -> 第一个参数是改变的函数内的 this 指向 -> 第二个参数开始依次是给函数的形参赋值 => 特点: -> 不会立即调用函数 -> 会返回一个新的函数, 和原始函数一模一样, 只不过 this 是被改变好的内容 5. ES6 的 语法 5-1. 定义变量的关键字 let 和 const => let/const 和 var 的区别 -> var 会进行预解析 -> let 和 const 不会进行预解析 -> var 可以声明重复变量名 -> let 和 const 不能声明重复变量名 -> var 没有块级作用域 -> let 和 const 有块级作用域 => let 和 const 的区别 -> let 可以声明时不赋值 -> const 声明的时候必须赋值 -> let 声明的变量可以被修改 -> const 声明的变量不可以被修改 5-2. 箭头函数 => 对函数表达式的一种新的书写方式 => 语法: () => {} => 区别: -> 箭头函数内没有 arguments -> 箭头函数内没有 this => 特点: -> 当你只有一个形参的时候, 可以省略小括号不写 -> 当你的函数体只有一句话的时候, 可以省略大括号不写, 并且会自动 return 这一句话的结果 5-3. 函数的参数默认值 => 给函数的形参设置一个默认值, 当你没有传递实参的时候, 使用 => 直接在函数形参位置以 赋值符号(=) 的方式给形参赋值 => function fn(a = 10, b = 20) {} => 箭头函数也可以使用函数的参数默认值 => 箭头函数使用的时候, 不管多少个形参都需要书写 小括号 5-4. 模板字符串 => ES6 新增的一种定义字符串的方式 => 使用 反引号(``) 定义字符串 => 特点: -> 可以换行书写内容 -> 可以在字符串内直接解析变量, 当你需要解析变量的时候, 书写 ${ 变量 } 5-5. 解构赋值 => 快速从 对象 或者 数组 中获取一些数据 => 解构数组 -> 使用 [] 解构数组 -> let [ 变量1, 变量2, ... ] = 数组 => 解构对象 -> 使用 {} 解构对象 -> let { 键名1, 键名2, ... } = 对象 -> 在解构的时候, 起一个别名 -> let { 键名1: 别名, 键名2: 别名, ... } = 对象 5-6. 扩展运算符 => 展开运算符 -> 使用在函数的实参位置或者对象或者数组中 -> 把本身的数据结构展开 => 合并运算符 -> 使用在函数的形参位置, 或者解构的位置 -> 把当前位置开始到最后的所有数据合并在一起, 放在一个数组里面返回
14day
-
面向对象 + 是一个开发思想, 书写代码的方式 + 面向对象: 当你需要完成某一个功能的时候, 找到一个对象帮你完成功能 + 核心: 高内聚低耦合
- 面向对象开发
+ 选项卡 2-1. 找到一个能完成选项卡的对象, 如果有, 直接使用 2-2. 如果没有这个对象, 我们需要书写一个 构造函数(机器), 能制造完成选项卡的对象 2-3. 使用 构造函数(机器) 制造一个完成选项卡的对象 2-4. 使用这个对象完成选项卡功能
- 构造函数的书写
3-1. 就是一个普通函数, 只不过在调用的时候和 new 关键字连用 => 就有了创建对象的能力, 所以我们叫做 构造函数 3-2. 首字母大写 => 为了和普通函数做一个区分 => 看到首字母大写的函数, 不需要看到函数内容, 就知道是要和 new 关键字连用 3-3. 构造函数内不要写 return => 如果你 return 了一个基本数据类型, 写了没有意义 => 如果你 return 了一个复杂数据类型, 那么构造函数白写 3-4. 规则: 构造函数的使用必须要和 new 关键字连用 => 如果不和 new 关键字连用, 那么没有创建对象的能力 => 我们之所以书写构造函数, 就是为了创建对象 3-5. 构造函数内的 this => 指向被创建出来的对象 => 因为这个对象会被自动返回 => 所以 this 指向 当前实例
- 构造函数的不合理
+ 当方法书写在构造函数体内的时候 + 你创建的实例对象越多, 就会造成更多的资源浪费 + 解决: => 书写构造函数的时候 => 属性书写在构造函数体内 => 方法书写在构造函数逇 prototype(原型) 上
- 原型
+ 概念: 为了解决构造函数的实例可以使用方法, 而出现的对象数据类型 + 私人: 为了解决构造函数体内书写方法的不合理 5-1. prototype + 每一个函数天生自带一个 prototype, 是一个对象数据类型 + 构造函数也是函数, 所以构造函数也有 prototype + 我们就可以通过 构造函数.prototype 向里面添加一些成员(方法) 5-2. __proto__ + 每一个对象天生自带一个 __proto__, 指向所属构造函数的 prototype + 所属: 实例对象是由哪一个构造函数实例化出来的, 那么这个实例对象所属的构造函数就是谁 5-3. 原型访问机制(对象访问机制) + 当你访问一个对象的成员的时候 + 首先在自己身上查找, 有的话直接使用, 停止查找 + 如果没有, 那么会自动去到 __proto__ 上找 (其实就是去 所属构造函数的 prototype 上找) + 未完待续... + 作用: 由 构造函数 去向 prototype 上添加方法 由 该构造函数的 所有实例 去调用
- 构造函数内相关的 this
6-1. 构造函数体内的 this => 因为 构造函数 在调用的时候, 会和 new 关键字连用 => 所以, 构造函数体内的 this 指向 当前实例(自动创建出来的对象/new 关键字前面的变量) 6-2. 构造函数原型中的方法里面的 this => 因为原型上的方法都是依靠 实例对象 来调用 => 是标准的对象调用方式, 内部的 this 指向当前实例对象
15day
AJAX
ajax
全名async javascript and XML
- 是前后台交互的能力
- 也就是我们客户端给服务端发送消息的工具,以及接受响应的工具
- 是一个 默认异步 执行机制的功能
AJAX 的优势
- 不需要插件的支持,原生 js 就可以使用
- 用户体验好(不需要刷新页面就可以更新数据)
- 减轻服务端和带宽的负担
- 缺点: 搜索引擎的支持度不够,因为数据都不在页面上,搜索引擎搜索不到
AJAX 的使用
- 在 js 中有内置的构造函数来创建 ajax 对象
- 创建 ajax 对象以后,我们就使用 ajax 对象的方法去发送请求和接受响应
创建一个 ajax 对象
// IE9及以上
const xhr = new XMLHttpRequest()
// IE9以下
const xhr = new ActiveXObject('Mricosoft.XMLHTTP')
- 上面就是有了一个 ajax 对象
- 我们就可以使用这个
xhr
对象来发送 ajax 请求了
配置链接信息
const xhr = new XMLHttpRequest()
// xhr 对象中的 open 方法是来配置请求信息的
// 第一个参数是本次请求的请求方式 get / post / put / ...
// 第二个参数是本次请求的 url
// 第三个参数是本次请求是否异步,默认 true 表示异步,false 表示同步
// xhr.open('请求方式', '请求地址', 是否异步)
xhr.open('get', './data.php')
- 上面的代码执行完毕以后,本次请求的基本配置信息就写完了
发送请求
const xhr = new XMLHttpRequest()
xhr.open('get', './data.php')
// 使用 xhr 对象中的 send 方法来发送请求
xhr.send()
- 上面代码是把配置好信息的 ajax 对象发送到服务端
一个基本的 ajax 请求
- 一个最基本的 ajax 请求就是上面三步
- 但是光有上面的三个步骤,我们确实能把请求发送的到服务端
- 如果服务端正常的话,响应也能回到客户端
- 但是我们拿不到响应
- 如果想拿到响应,我们有两个前提条件
- 本次 HTTP 请求是成功的,也就是我们之前说的 http 状态码为 200 ~ 299
- ajax 对象也有自己的状态码,用来表示本次 ajax 请求中各个阶段
ajax 状态码
- ajax 状态码 -
xhr.readyState
- 是用来表示一个 ajax 请求的全部过程中的某一个状态
readyState === 0
: 表示未初始化完成,也就是open
方法还没有执行readyState === 1
: 表示配置信息已经完成,也就是执行完open
之后readyState === 2
: 表示send
方法已经执行完成readyState === 3
: 表示正在解析响应内容readyState === 4
: 表示响应内容已经解析完毕,可以在客户端使用了
- 这个时候我们就会发现,当一个 ajax 请求的全部过程中,只有当
readyState === 4
的时候,我们才可以正常使用服务端给我们的数据 - 所以,配合 http 状态码为 200 ~ 299
- 一个 ajax 对象中有一个成员叫做
xhr.status
- 这个成员就是记录本次请求的 http 状态码的
- 一个 ajax 对象中有一个成员叫做
- 两个条件都满足的时候,才是本次请求正常完成
readyStateChange
-
在 ajax 对象中有一个事件,叫做
readyStateChange
事件 -
这个事件是专门用来监听 ajax 对象的
readyState
值改变的的行为 -
也就是说只要
readyState
的值发生变化了,那么就会触发该事件 -
所以我们就在这个事件中来监听 ajax 的
readyState
是不是到 4 了const xhr = new XMLHttpRequest() xhr.open('get', './data.php') xhr.send() xhr.onreadyStateChange = function () { // 每次 readyState 改变的时候都会触发该事件 // 我们就在这里判断 readyState 的值是不是到 4 // 并且 http 的状态码是不是 200 ~ 299 if (xhr.readyState === 4 && /^2\d{2|$/.test(xhr.status)) { // 这里表示验证通过 // 我们就可以获取服务端给我们响应的内容了 } }
responseText
-
ajax 对象中的
responseText
成员 -
就是用来记录服务端给我们的响应体内容的
-
所以我们就用这个成员来获取响应体内容就可以
const xhr = new XMLHttpRequest() xhr.open('get', './data.php') xhr.send() xhr.onreadyStateChange = function () { if (xhr.readyState === 4 && /^2\d{2|$/.test(xhr.status)) { // 我们在这里直接打印 xhr.responseText 来查看服务端给我们返回的内容 console.log(xhr.responseText) } }
使用 ajax 发送请求时携带参数
- 我们使用 ajax 发送请求也是可以携带参数的
- 参数就是和后台交互的时候给他的一些信息
- 但是携带参数 get 和 post 两个方式还是有区别的
发送一个带有参数的 get 请求
-
get 请求的参数就直接在 url 后面进行拼接就可以
const xhr = new XMLHttpRequest() // 直接在地址后面加一个 ?,然后以 key=value 的形式传递 // 两个数据之间以 & 分割 xhr.open('get', './data.php?a=100&b=200') xhr.send()
- 这样服务端就能接受到两个参数
- 一个是 a,值是 100
- 一个是 b,值是 200
发送一个带有参数的 post 请求
-
post 请求的参数是携带在请求体中的,所以不需要再 url 后面拼接
const xhr = new XMLHttpRequest() xhr.open('get', './data.php') // 如果是用 ajax 对象发送 post 请求,必须要先设置一下请求头中的 content-type // 告诉一下服务端我给你的是一个什么样子的数据格式 xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded') // 请求体直接再 send 的时候写在 () 里面就行 // 不需要问号,直接就是 'key=value&key=value' 的形式 xhr.send('a=100&b=200')
application/x-www-form-urlencoded
表示的数据格式就是key=value&key=value
18day
1. ajax
+ 是一个前端和后端交互的技术手段
2. ajax 的基本步骤
2-1. 创建 ajax 对象
=> const xhr = new XMLHttpRequest()
2-2. 配置本次的请求信息
=> xhr.open('请求方式', '请求地址', 是否异步)
2-3. 绑定一个请求完成的事件
=> xhr.onload = function () {}
=> 事件内拿到响应体 xhr.responseText
=> 根据响应体格式决定是否进行 json 格式解析
2-4. 发送请求
=> xhr.send()
3. 发送一个带有参数的 get 请求
const xhr = new XMLHttpRequest()
xhr.open('GET', '请求地址?key=value&key2=value2')
xhr.onload = function () { ... }
xhr.send()
4. 发送一个带有参数的 post 请求
const xhr = new XMLHttpRequest()
xhr.open('GET', '请求地址')
xhr.onload = function () { ... }
xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')
xhr.send('key=value&key2=value2')
5. GET 和 POST 的区别
+ GET
1. 偏向于获取的语义
2. 在请求地址后面以 查询字符串 的形式携带参数
3. 参数大小限制大概 2KB 左右
4. 参数只能是 查询字符串 格式
5. 相对不安全
+ POST
1. 偏向于提交的语义
2. 在请求体 内携带参数
3. 参数大小被服务器限制
4. 参数可以是很多格式, 但是要在请求头内特殊说明
5. 相对安全
6. 本地存储
+ localStorage (本地存储, 永久存储)
=> 存: window.localStorage.setItem('key', 'value)
=> 取: window.localStorage.getItem('key')
=> 删: window.localStorage.removeItem('key')
+ sessionStorage (会话存储, 临时存储)
=> 存: window.sessionStorage.setItem('key', 'value)
=> 取: window.sessionStorage.getItem('key')
=> 删: window.sessionStorage.removeItem('key')
+ 共同点:
1. API 基本一致
2. 只能存储字符串类型的数据, 如果你需要存储复杂数据类型, 转换成 json 格式存储
23day
-
闭包
-
-
是一个函数的高阶应用
- 官方: 函数内的函数
- 私人: => 需要一个不会销毁的函数作用域 => 外部函数内直接或者间接的返回一个函数 => 内部函数使用着外部函数的变量 => 内部函数是外部函数的 闭包函数
- 作用:
- 保持变量私有化
- 延长变量的生命周期
- 函数外部访问函数内部的变量 1-1. 函数的两个阶段 => 函数定义阶段 -> 在堆内存中开辟了一个函数存储空间 -> 把函数体内的代码一模一样的放在存储空间内, 此时不解析变量 -> 把空间地址赋值给变量名 => 函数调用阶段 -> 按照地址找到指定的存储空间 -> 在调用栈内开辟一个函数的运行空间 -> 在运行空间内进行形参赋值 -> 在运行空间内进行预解析 -> 在运行空间内执行代码, 此时才解析变量 -> 函数体内的代码执行完毕, 运行空间销毁 1-2. 不会销毁的运行空间 => 当函数内返回一个复杂数据类型的时候 => 并且在函数外部有变量接受的时候 => 此时函数执行完毕的运行空间不会销毁 1-3. 如何销毁空间 => 只需要让外部接受的变量指向其他位置 1-4. 闭包 - 语法糖 => 以 getter 和 setter 的形式来返回函数内的函数 => 可以把返回值直接当做一个对象来看待使用
- 继承
- 一个构造函数的高阶应用
- 出现在两个构造函数之间的关系
- 构造函数 A 的实例使用了 构造函数B 的属性的方法
- 我们就说 构造函数A 是构造函数B 的子类
2-1. 原型继承
=> 让子类的 prototype 指向父类的实例 => 子类.prototype = new 父类()
2-2. 借用继承
=> 利用父类构造函数体和 call 方法来实现继承 => 在子类构造函数体内 父类.call(this)
2-3. 组合继承
=> 组合了借用继承和原型继承
2-4. ES6 的继承语法
1. 在书写类的时候, 直接书写 class 子类 extends 父类 {} 2. 在 constructor 内书写 super() => 注意: -> super 必须写在 constructor 内的最前面
- 模块化语法
-
把每一个 js 文件当做一个独立的模块
=> 每一个 js 文件内书写一类内容
=> 在准备一个整合的 js 文件, 作用就是整合该页面的所有需要用到的模块
=> 在 html 文件内只引入这个整合的文件
-
导出
=> 在 js 文件内书写
=> export default { ... }
=> 该 js 文件内可以被其他文件使用的内容, 书写在 {} 内部
-
导入
=> 在 js 文件内书写
=> import 变量 from 'js文件地址'
=> 变量得到的就是js文件内导出的内容
-
注意:
=> 使用 模块化语法 必须要在服务器上开启页面
=> script 标签需要添加一个 type="module" 的属性
-
26day
-
node
+ 是一个基于 Chrome V8 解析引擎的 javascript 运行时环境 + 其实是一个 "软件", 专门用来执行 js 文件的 + 可以利用 js 语法来实现后端开发 => 操作文件 => 操作电脑系统 => 操作数据库 => ...
- node 的模块化语法
+ 因为 node 的开发, 是独立的 js 文件 => 所以必须模块化语法开发 + node 的模块分类 => 内置模块 => 自定义模块 => 第三方模块 + 自定义模块 => 自己书写的每一个 js 文件都是一个独立的模块 => 导出: + 语法: module.exports = { ... } + 在对象内书写导出的内容 => 导入: + 语法: const 变量 = require('js 文件') + 当文件名后缀是 js 的时候, 可以省略后缀不写 + 得到的就是该 js 文件内导出的内容 + 内置模块 => nodejs 自带的模块 => fs: 操作文件的模块 + fs.readFile() + fs.readFileSync() + fs.writeFile() + fs.writeFileSync() => path: 操作路径的模块 + path.join() => http: 创建服务的模块 + http.createServer(函数) + 用来创建服务, 每一个前端的请求都会触发一次函数 => 函数内接受两个参数 => request(req) 请求报文的所有内容 => response(res) 响应报文的所有内容 + 第三方 => 下载, 导入, 按照规则使用 => moment
- npm
+ 一个 js 的包管理器 + 用来下载第三方包用的 + 伴随 node 安装和卸载
- npm 的基本使用
4-1. 下载包 => 指令: $ npm install 包名 4-2. 下载指定版本的包 => 指令: $ npm install 包名@版本号 4-3. 初始化 => 指令: $ npm init 4-4. 卸载包 => 指令: $ npm uninstall 包名 4-5. 一次性下载 => 指令: $ npm install 4-6. 清除缓存 => 指令: $ npm cache clear -f => 手动清除: 删除 C:/users/你的账户/appdata/roaming/npm-cache 文件夹