笔记在这里的

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()
  1. 作用域 + 一个变量(变量名 和 函数名)的使用范围 + 作用域的分类 => 全局作用域: 打开页面就是一个全局作用域 => 私有作用域: 只有函数生成私有作用域 + 变量定义机制 => 在哪一个作用域内定义的变量, 就是哪一个作用域的私有变量 + 变量使用机制 => 当你需要访问一个变量的值的时候 => 首先在自己作用域内查找, 如果自己作用域有, 直接使用 => 如果没有, 去父级作用域查找 => 如果还没有, 再去父级作用域查找 => 以此类推, 直到全局作用域都没有, 那么就报错, xxx is not defined + 变量赋值机制 => 当你需要给一个变量进行赋值的时候 => 首先在自己作用域内查找, 如果有, 直接赋值 => 如果没有, 给父级作用域的变量赋值 => 如果还没有, 就给再父级作用域的变量赋值 => 以此类推, 直到全局作用域都没有, 会把这个变量定义为全局变量再进行赋值

    1. 递归函数(了解)
    + 一个函数调用了自身, 并且设置了结束条件
    + 我们管这种函数的调用方式叫做递归函数
    + 递归函数的书写原则
      1. 写函数
      2. 先写结束条件
      3. 书写未到达终点时的状态
    1. 对象数据类型
    + 是一个 JS 中的复杂数据类型
    + 是一个键值对的集合
    + 对象的创建
      1. 字面量方式创建
        => var obj = {}
      2. 内置构造函数创建
        => var obj = new Object()
      3. 创建带有键值对的对象
        => var obj = { 键值对, 键值对, ... }
        => 键值对:   键: 值
    1. 对象的基本操作 => 增 -> 对象名.键名 = 值 -> 对象名['键名'] = 值 => 删 -> delete 对象名.键名 -> delete 对象名['键名'] => 改 -> 对象名.键名 = 值 -> 对象名['键名'] = 值 -> 因为对象的键名不重名特点 -> 原先有就是修改, 原先没有就是增加 => 查 -> 对象名.键名 -> 对象名['键名']

    2. 两套操作语法的区别

    + 操作符合变量定义规则和规范的 key
      => 可以使用点语法
      => 可以使用数组关联语法
    + 操作纯数字的 key
      => 不能使用点语法
      => 只能使用数组关联语法
    + 操作带有符号的 key
      => 不能使用点语法
      => 只能使用数组关联语法
    + 和变量相关的时候
      => 点语法只能操作准确的某一个 键名, 和变量没有任何关系
      => 数组关联语法, 中括号内书写字符串的时候, 是操作准确的某一个 键名
      => 数组关联语法, 中括号内书写变量的时候, 会把变量解析访问
    1. 遍历对象数据类型
    + 因为 键名 没有规则
    + 使用 for in 循环遍历
    + 语法: for (var 变量 in 对象名) { ... }
      => 在循环中, 变量分别表示对象内的每一个键名
    1. 数据类型之间存储的区别
    + 基本数据类型
      => 直接存储在栈内存里面
    + 复杂数据类型
      => 数据存储在堆内存里面
      => 把地址存储在栈内存的变量名里面
    1. 数据类型之间赋值的区别
    + 基本数据类型
      => 赋值以后, 两个变量没有关系, 操作任何一个变量, 另一个不会发生变化
    + 复杂数据类型
      => 因为赋值的是 地址
      => 所以赋值以后, 两个变量操作同一个地址空间
      => 使用任何一个变量修改空间内的数据, 另一个变量看到的也是修改后的

    */

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

  1. 创建节点 => createElement() => createTextNode() => createDocumentFragment() 文档碎片
  2. 插入节点 => appendChild() => insertBefore()
  3. 删除节点 => removeChild() => remove()
  4. 替换节点 => replaceChild(换上节点, 换下节点)
  5. 克隆节点 => cloneNode() => 参数默认是 false, 表示不克隆后代节点 => 参数选填是 true, 表示克隆后代节点
  6. 获取元素尺寸(占地面积) => 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-1. 字面量方式
         => var reg = /abcd/ig
       1-2. 内置构造函数创建方式
         => var reg = new RegExp('abcd', 'ig')
    1. 创建正则表达式的区别
    2-1. 标识符的书写
       => 字面量方式是直接书写在正则表达式的后面
       => 内置构造函数是在第二个参数的位置书数写
     2-2. 拼接变量
       => 字面量方式不能拼接变量
       => 内置构造函数可以拼接变量
     2-3. 书写基本元字符的方式
       => 字面量内书写的时候 \s\d\w
       => 在内置构造函数方式书写的时候, \\s\\d\\w
    1. 元字符
    3-1. 基本元字符
       => \s
       => \S
       => \d
       => \D
       => \w
       => \W
       => .
       => \
     3-2. 边界元字符
       => ^
       => $
       => 当两个符号一起使用的时候, 表示从开头到结尾
     3-3. 修饰符
       => 修饰符只修饰前面一个内容
       => *
       => +
       => ?
       => {n}
       => {n,}
       => {n,m}
     3-4. 特殊符号
       => ()
       => (?:)
       => |
       => []
       => [^]
       => -
     3-5. 非贪婪修饰符
       => *?
       => +?
       => ??
       => {n,}?
       => {n,m}?
    1. 标识符 4-1. i 4-2. g
    2. 正则的两个常用方法 5-1. 匹配 : test() 5-2. 捕获 : exec()
    3. 字符串常用方法和正则合作的 6-1. replace() 6-2. search() 6-3. match()

13day

  1. 自执行函数

    + 一个定义完毕马上把自己调用的函数
    + 语法:
      => (function () { ... })()
      => ~function () { ... }()
      => !function () { ... }()
    1. json 格式的字符串
    + 一种字符串的特殊格式, 用于前后端交互的时候使用
    + 语法:
      => 把 JS 的数据格式转换成 json 格式的数据
        -> JSON.stringify(JS的数据格式)
      => 把 json 格式的字符串转换成 JS 格式的数据
        -> JSON.parse(json格式字符串)
    1. 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

  1. 面向对象 + 是一个开发思想, 书写代码的方式 + 面向对象: 当你需要完成某一个功能的时候, 找到一个对象帮你完成功能 + 核心: 高内聚低耦合

    1. 面向对象开发
    + 选项卡
     2-1. 找到一个能完成选项卡的对象, 如果有, 直接使用
     2-2. 如果没有这个对象, 我们需要书写一个 构造函数(机器), 能制造完成选项卡的对象
     2-3. 使用 构造函数(机器) 制造一个完成选项卡的对象
     2-4. 使用这个对象完成选项卡功能
    1. 构造函数的书写
    3-1. 就是一个普通函数, 只不过在调用的时候和 new 关键字连用
       => 就有了创建对象的能力, 所以我们叫做 构造函数
     3-2. 首字母大写
       => 为了和普通函数做一个区分
       => 看到首字母大写的函数, 不需要看到函数内容, 就知道是要和 new 关键字连用
     3-3. 构造函数内不要写 return
       => 如果你 return 了一个基本数据类型, 写了没有意义
       => 如果你 return 了一个复杂数据类型, 那么构造函数白写
     3-4. 规则: 构造函数的使用必须要和 new 关键字连用
       => 如果不和 new 关键字连用, 那么没有创建对象的能力
       => 我们之所以书写构造函数, 就是为了创建对象
     3-5. 构造函数内的 this
       => 指向被创建出来的对象
       => 因为这个对象会被自动返回
       => 所以 this 指向 当前实例
    1. 构造函数的不合理
    + 当方法书写在构造函数体内的时候
     + 你创建的实例对象越多, 就会造成更多的资源浪费
     + 解决:
       => 书写构造函数的时候
       => 属性书写在构造函数体内
       => 方法书写在构造函数逇 prototype(原型) 上
    1. 原型
    + 概念: 为了解决构造函数的实例可以使用方法, 而出现的对象数据类型
     + 私人: 为了解决构造函数体内书写方法的不合理
     5-1. prototype
       + 每一个函数天生自带一个 prototype, 是一个对象数据类型
       + 构造函数也是函数, 所以构造函数也有 prototype
       + 我们就可以通过 构造函数.prototype 向里面添加一些成员(方法)
     5-2. __proto__
       + 每一个对象天生自带一个 __proto__, 指向所属构造函数的 prototype
       + 所属: 实例对象是由哪一个构造函数实例化出来的, 那么这个实例对象所属的构造函数就是谁
     5-3. 原型访问机制(对象访问机制)
       + 当你访问一个对象的成员的时候
       + 首先在自己身上查找, 有的话直接使用, 停止查找
       + 如果没有, 那么会自动去到 __proto__ 上找 (其实就是去 所属构造函数的 prototype 上找)
       + 未完待续...
     + 作用: 由 构造函数 去向 prototype 上添加方法
            由 该构造函数的 所有实例 去调用
    1. 构造函数内相关的 this
    6-1. 构造函数体内的 this
       => 因为 构造函数 在调用的时候, 会和 new 关键字连用
       => 所以, 构造函数体内的 this 指向 当前实例(自动创建出来的对象/new 关键字前面的变量)
     6-2. 构造函数原型中的方法里面的 this
       => 因为原型上的方法都是依靠 实例对象 来调用
       => 是标准的对象调用方式, 内部的 this 指向当前实例对象

15day

AJAX

  • ajax 全名 async javascript and XML
  • 是前后台交互的能力
  • 也就是我们客户端给服务端发送消息的工具,以及接受响应的工具
  • 是一个 默认异步 执行机制的功能

AJAX 的优势

  1. 不需要插件的支持,原生 js 就可以使用
  2. 用户体验好(不需要刷新页面就可以更新数据)
  3. 减轻服务端和带宽的负担
  4. 缺点: 搜索引擎的支持度不够,因为数据都不在页面上,搜索引擎搜索不到

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 请求就是上面三步
  • 但是光有上面的三个步骤,我们确实能把请求发送的到服务端
  • 如果服务端正常的话,响应也能回到客户端
  • 但是我们拿不到响应
  • 如果想拿到响应,我们有两个前提条件
    1. 本次 HTTP 请求是成功的,也就是我们之前说的 http 状态码为 200 ~ 299
    2. 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 状态码的
  • 两个条件都满足的时候,才是本次请求正常完成

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. 保持变量私有化
        2. 延长变量的生命周期
        3. 函数外部访问函数内部的变量 1-1. 函数的两个阶段 => 函数定义阶段 -> 在堆内存中开辟了一个函数存储空间 -> 把函数体内的代码一模一样的放在存储空间内, 此时不解析变量 -> 把空间地址赋值给变量名 => 函数调用阶段 -> 按照地址找到指定的存储空间 -> 在调用栈内开辟一个函数的运行空间 -> 在运行空间内进行形参赋值 -> 在运行空间内进行预解析 -> 在运行空间内执行代码, 此时才解析变量 -> 函数体内的代码执行完毕, 运行空间销毁 1-2. 不会销毁的运行空间 => 当函数内返回一个复杂数据类型的时候 => 并且在函数外部有变量接受的时候 => 此时函数执行完毕的运行空间不会销毁 1-3. 如何销毁空间 => 只需要让外部接受的变量指向其他位置 1-4. 闭包 - 语法糖 => 以 getter 和 setter 的形式来返回函数内的函数 => 可以把返回值直接当做一个对象来看待使用
      1. 继承
      • 一个构造函数的高阶应用
      • 出现在两个构造函数之间的关系
      • 构造函数 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 内的最前面
      1. 模块化语法
      • 把每一个 js 文件当做一个独立的模块

        => 每一个 js 文件内书写一类内容

        => 在准备一个整合的 js 文件, 作用就是整合该页面的所有需要用到的模块

        => 在 html 文件内只引入这个整合的文件

      • 导出

        => 在 js 文件内书写

        => export default { ... }

        => 该 js 文件内可以被其他文件使用的内容, 书写在 {} 内部

      • 导入

        => 在 js 文件内书写

        => import 变量 from 'js文件地址'

        => 变量得到的就是js文件内导出的内容

      • 注意:

        => 使用 模块化语法 必须要在服务器上开启页面

        => script 标签需要添加一个 type="module" 的属性

26day

  1. node

    + 是一个基于 Chrome V8 解析引擎的 javascript 运行时环境
    + 其实是一个 "软件", 专门用来执行 js 文件的
    + 可以利用 js 语法来实现后端开发
      => 操作文件
      => 操作电脑系统
      => 操作数据库
      => ...
    1. 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
    1. npm
    + 一个 js 的包管理器
    + 用来下载第三方包用的
    + 伴随 node 安装和卸载
    1. 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 文件夹
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值