JavaScript

JavaScript的简介

JavaScript(简称“JS”) 是一种具有函数优先的轻量级,解释型或即时编译型的编程语言。虽然它是作为开发Web页面的脚本语言而出名,但是它也被用到了很多非浏览器环境中,JavaScript 基于原型编程、多范式的动态脚本语言,并且支持面向对象、命令式、声明式、函数式编程范式。

js的三种使用方式

1.在浏览器控制台上直接运行js语言片段
2.在html文件的script标签中
3.使用.js文件书写js代码,然后再html中通过script标签的src属性引入js代码文件

变量

变量就是存放数据的一个容器 (盒子)
变量所保存的数据本质是存储在计算机的内存中的! 内存是通过硬件内存条所产生一块虚拟空间!通常称为内存空间!
内存中数据存储的特点:
1.读写速度快 2.临时数据的存储 3.内存的存储空间是比较小的

变量的声明

1.var var 关键字可以重复声明相同的变量
2.let let关键字在同一作用域下不能声明相同的变量
3.const const关键字是用于声明 常量的!在同一作用域下也不可以声明相同的变量,并且在声明时必须赋初值

变量的命名规则

js中的标识符命名规范:
1.标识符只能由字母 数字 下划线 以及$符号组成
2.标识符不能以数字进行开头
3.标识符严格区分大小写
4.不能采用关键字或者保留字进行标识符的定义
– 关键字:js语法规范中,提前规定好了一些单词!并且js也赋予其特殊的含有!这些单词称为关键字! 比如 if else break for var let const…
– 保留字:js语法规范中,以前收录了一些单词!但目前这些单词未真正的投入使用,测试阶段!并没有任何的含义! 这些单词称为保留字
注意:以上4条就是js标识符命名规范的硬性准则!
5.标识符如果由多个单词构成!应遵循 ‘小驼峰命名法’ : blackcolor ==> blackColor
6.标识符的命名应该遵循 ‘见名知义’ : name ,age ,sex 不要取这些名字: a1 b2 abc …

数据类型

值类型

  • Boolean 布尔型
  • Number 数字型
  • String 字符串
  • BigInt 长整数

引用类型

  • Object 对象类型
  • Symbol 符号类型

undefined 未定义

undefined 是一个单独的类型,用于给已经定义的变量设置的初始值

null 空引用

null 值的是空引用,是 js 的一个原始数据类型,用来指代引用类型数据的空值加粗样式

值类型和引用类型数据的区别

值类型:变量中直接存贮值本身
引用类型:变量中存储的是引用地址,而值是存在引用地址所指向的内存中的某个对应位置

json对象

json对象,花括号对象
json对象的创建利用{}进行创建
json对象中数据的存储采用键值对的方式, key:value ,其中key的数据类型必须是字符串,value可以是任何的合法数据类型!
大多数时候,js允许省略key的引号或者双引号,省略的前提是属性名的命名符合标识符的命名规则
// 1. 属性值的读取操作
// - 方式一:通过.语法 语法规则: 对象.属性 可以把.理解为语文上’的’
// - 方式二:通过[属性名]
// 获取person对象的name值 点语法
// console.log(person.name)
// console.log(person.age)
// console.log(person.sayHello)
// console.log(person.black@color)

  // 读取对象中不存在的属性
  // console.log(person.xxx) // undefined  读取对象中不存在的属性时其返回数据为 undefined

  //  []  语法规则 对象[属性名]
  // console.log(person['black@color']) //



  // 2.添加属性  利用赋值运算符,为一个不存在的属性进行赋值!就是在为该对象添加一个新的属性并且赋值!
  // console.log(person.xxxx)
  // person.xxxx = '我是xxxx属性值'
  // console.log(person.xxxx)
  // console.log(person)

  // person['xxxx']  = '我是xxx数据'
  // console.log(person)

  // 3.修改属性值  利用赋值运算符
  // person.age  = 300
  // console.log(person)


  // 4.对象类型中不允许存在两个同名属性!后一个会覆盖前面的属性值!
  // 注意:以上这些操作,适用于任何的Obeject数据类型!

json数据的系列化和反序列化

序列化:将一个合法的json对象,转换为一段标准的json格式的数据! 利用js提供的JSON对象上的方法进行操作 JSON.StringIfy
反序列化:将一段标准的json格式的数据,字符串转化为一个合法的json对象!反序列化 利用js提供的JSON对象上的方法进行操作 JSON.parse()

数据类型检测

// js中的数据类型有8种
// 原始数据类型(7) 和 对象类型(1)
// 口诀: 四基两空双一
// 四基: Number、String、 Boolean 、 BigInt
// 两空: undefined 、 null
// 双一: 一个符号 Symbol 一个对象 Object

    语法: typeof 数据  

数据类型的转换

数据的类型转换:将某个数据的类型通过某种方式转换为另一种数据类型! 比如: number ==》 string
数据转换通过方式不同可以分为:强制转换、隐式转换
强制转换:人为的通过手段去改变一个数据的类型
隐式转换:没有人为的参与,是程序解析自动进行转换
Number(x)函数 该函数可以将其他的数据类型强制转换为Number类型的数据
除了Number()函数可以强制转换其他数据为Number类型外,还有两种手段
全局函数: parseInt() 、parseFloat
parseInt() 将其他数据类型转换为number的整数值
parseFloat() 将其他数据类型转换为number的浮点数
String() 该函数是将其他类型强制转换为字符串类型
Boolean() 该函数是将其他类型强制转换为布尔类型
js中的假值,假值就是通过强制转换或者隐式转换该数据为布尔类型后,其结果为false的数据称为假值!
js中的假值: false 、 0 、 -0 、 +0 、 null 、 undefined 、 ‘’

运算符

运算符的作用,利用各种运算符,对已有数据进行运算然后得到新的数据!

js中的运算符分类:
算术运算符
赋值运算符
比较运算符
逻辑运算符
三元运算符
单目运算符

算术运算符

算术运算符:+ 、 - 、 * 、 / 、%(模运算,取余)、**(幂运算)
算数运算符主要用于两个number数据的计算!
如果算术运算符一侧数据类型不为number则js将进行隐式转换!转换为numnber类型然后进行运算!
注意:如果+号的一侧数据类型为字符串类型,则+号就自动变成字符的拼接运算

赋值运算符

‘=’ 强调赋值运算符,不是数学意义上的等于符号!它是赋值运算!
运算流程: 将赋值运算符的右侧表达式的结果,赋值给左边的变量! 从右往左
注意:赋值运算符可以改变变量或者对象属性的具体值!

复合运算符

复合赋值运算符:该运算符是 赋值运算符 与 算数运算符的结合书写!
注意:复合赋值运算符也具备赋值运算的功能!

+= 、 -= 、 /= 、 %= 、 **= 、*=

比较运算符

用于对两个数据进行数据的比较,其比较结果为布尔值!true 或 false
> 、< 、 >= 、<=、 ==、 ===、 != 、!==

逻辑运算符

逻辑运算符:用于对两个逻辑值的运算!
js中的逻辑运算符: &&(与) ||(或) !(非,取反)
逻辑运算表达式的返回结果是什么类型?结果:可以是任何数据类型!

&& 与运算
运算语法: 表达式1 && 表达式2 如果&&运算两侧的数据类型不是布尔类型,则先进行隐式转换! Boolean()
与运算口诀: 全真为真,一假即假
短路与
特点在运算时,从左往右计算,如果碰到其中一个表达式的值为,false,那么后续的表达式将不再进行计算!并且返回当前表达式的原始值作为整个与运算的结果!如果从左往右计算,都没有遇到false,那么将最后一个表达式的原始值作为整个与运算的结果!

逻辑或(短路或)
运算语法: 表达式1 || 表达式2 如果||运算两侧的数据类型不是布尔类型,则先进行隐式转换! Boolean()
或运算口诀: 全假为假,一真即真
短路或
特点在运算时,从左往右计算,如果碰到其中一个表达式的值为,true,那么后续的表达式将不再进行计算!并且返回当前表达式的原始值作为整个或运算的结果!如果从左往右计算,都没有遇到true,那么将最后一个表达式的原始值作为整个或运算的结果!

!取反运算 非运算
口诀: 真变假,假变真

流程控制语句

js的代码如果没有人为的干预,那么js的执行顺序为从上往下,顺序执行!
作用:流程控制语句后,可以对js的代码执行顺序进行干预,完成更复杂的程序逻辑!

js中的三大流程控制结构:
顺序结构 选择结构 循环结构

顺序结构: 整体代码的解析执行是按照从上往下!的规律进行执行!也是最基础的控制结构
选择结构: 为代码的执行提供可能的路径!影响代码的走向!
循环结构: 重复的执行某一段代码!

多分支语句

js多分支语句,if…else的嵌套
// 双分支,是两条路径选择!
// 多分支,是多条路径进行选择!
// 多分支的本质就是利用if和else嵌套!

  // 语法:
  // if(表达式){
  //     路径1
  // }else if(表达式){
  //     路径2
  // } else {
  //     路径3
  // }

条件分支语句

js的条件分支语句 switch语句

  // 语法:
  //   switch (表达式) {
  //     case '值':
  //       语句块
  //     case '值':
  //       语句块
  //     case '值':
  //       语句块
  //     case '值':
  //       语句块
  //     case '值':
  //       语句块
  //     case '值':
  //       语句块
  //     ....
  //     default:
  //         不满足其他case分支时,进行default!
  //   }

while与do while

while循环
语法:
while (表达式) {
循环体
}
while循环的注意事项:
1.必须设置循环控制变量
2.必须为循环控制变量赋初始值
3.每一次的循环体结束前应该更新循环控制变量

执行流程,首先判断表达式的true或者false,如果为true则执行循环体的代码,否则结束while循环
如果判断为true则执行循环体的代码,当循环体代码执行完毕时,再次判断表达式的真假!重复以上操作!直到表达式为false,退出while语句

do…while循环
语法:
do {
循环体
}while(表达式)
do…while循环的注意事项:
1.必须设置循环控制变量
2.必须为循环控制变量赋初始值
3.每一次的循环体结束前应该更新循环控制变量

执行流程,do…while循环,一开始先进行一次循环体代码的执行!然后进行表达式的判断!
如果为true 则继续执行循环体内容,重复操作!
如果为false 则结束do…while循环

for循环

for 循环
语法:
for(语句1;语句2;语句3){
循环体
}

执行流程,
for循环执行开始,先执行语句1,然后执行语句2,进行判断!
根据语句2的判读结果,true or false
如果为true,则执行循环体的内容,循环体内容执行完毕,跳到语句3并执行语句3的内容,语句3执行完毕后,又回到语句2再次进行判断!
直到语句2的结果为false,才会结束for循环

break与continue

continue 和 break关键字
两个关键字可以使得循环提前结束!

  // break关键字
  // 特点:直接结束当前包含break的循环语句!进入下一个步骤!

  // continue关键字
  // 特点:该关键字也可以结束循环,但是它只是结束该循环的本次内容!后续的循环继续执行!

API

API 是 Application Programming Interface 的缩写,翻译过来就是 “应用程序编程接口”

API 是提供一些用于编程工具,对于 js 来说,API 可以是某框架提供的变量或函数,也可以是网络上的一个可访问的 url 地址,称为网络接口

API 既然是编程工具,那么其作用是通过调用 API 来实现一个功能,例如:排序,查询,添加数据等操作

alert 弹窗提示 浏览器提供的 api 弹窗提示
alert 它会阻塞页面的渲染和执行
confirm 确认模态 弹出框 浏览器提供的 还具备返回值
prompt输入模态prompt(‘请输入姓名’)
上述api多用于调试

获取文档元素

// 浏览器为程序员提供了一个接口!
// 该接口可以访问页面中的所有元素节点!
// 该接口是一个对象!浏览器提供! document
// document是对象,那么对应的对象上是存在 属性或者方法的!

// console.log(document, typeof document)

// 利用document身上的方法可以获取到页面中的元素!

//  1.document.querySelector()
// 方法中的参数:是字符串类型,css的合法选择器
//  css的选择器书写:  .box  div  #01  div>span  div span .....
//  该方法的返回值是符合css选择器下的第一个页面元素对象
// let elment = document.querySelector('div')
// let elment = document.querySelector('div>span')
// console.log(elment)

//  2.document.querySelectorAll()
// 方法中的参数:是字符串类型,css的合法选择器
//  css的选择器书写:  .box  div  #01  div>span  div span .....
//  该方法的返回值是符合css选择器的所有页面元素对象,不管元素有多少个始终以 NodeList,伪数组的形式返回
// let arr = document.querySelectorAll('.box')
// console.log(arr)

// 3.document.getElementById()  通过元素的id属性值进行获取!
// let elment = document.getElementById('span01')
// console.log(elment)

// 4.document.getElementsByClassName() 通过元素的class属性值进行获取! 以 HTMLCollection 伪数组形式返回
// let arr = document.getElementsByClassName('box')
// console.log(arr)



// 5. document.getElementsByTagName()  通过元素的标签名进行获取!   div  span  p  h1.....
// let arr = document.getElementsByTagName('span')

修改页面元素属性

注意:利用点语法或者[]是可以获取元素对象上所有已知或未知属性的值!除了class属性的值不能正常获取!
通过 class ==》 className来获取元素的class值
修改页面元素的属性值
div.title = ‘xxxxxxxxxxxxxxxxxxx’
div.className = ‘box2’
# 元素对象的标签体属性
innerHTML是用于更改元素的标签体的内容,合法的字符会被浏览器自动解析为标签!
innerText是用于更改元素的文本信息,该文本信息是不会被浏览器当作标签来正常解析的

// innerHTML
// box.innerHTML = '<span>我是div</span>'

// innerText
// box.innerText = '<span>我是div</span>'

数组

数组,是存储一组数据的一个容器!
数组,是属于Object类型,通过typeof 检测是 ‘Object’
数组中可以同时存储不同类型的数据!只要是合法的js数据即可!多个数据之间使用’,’ 分隔!
数据中的每个数据可以称为 元素!数组的存储是有序存储的!利用元素的下标值进行访问!

  //    1. 创建一个数组
  // 方式一: 利用直接量进行创建, []   推荐使用!
  //   let arr = ['a', 'b', true, 100]

  //   console.log(arr, typeof arr)

  //   方式二: 利用构造函数 new Array()
  // let arr = new Array(100, 200, 'HELLO', true)
  // console.log(arr, typeof arr)

  //  2. 获取数组中对应元素的值, 利用元素的下标!注意下标值是从 0 开始的!
  //    语法: 数组[下标值]
  
        如何判断一个变量是否为数组!

  //利用js提供的api通过 构造函数对象 Array的静态方法 isArray() 进行判断  返回值true或false

数组的常用操作

数组的常见操作
// 所有的数组实例对象,都来自于Array构造函数! 所以所有的数组实例对象都具备相同的操作方法和属性

  //   let arr = [100, 200, 300, 'hello', true]

  //   1.获取数组的长度 length属性
  //   console.log(arr.length) //返回当前数组的长度 元素的个数  数组的下标值范围:0  ---  (arr.length-1)

  //   2.添加元素到数组的末尾  push方法
  //    push方法是改变原数组的操作!
  //   arr.push('world!')
  //   console.log(arr)

  //   arr.push('xxx')
  //   console.log(arr)

  //   3.删除数组末尾的元素  pop方法
  //    pop方法具备返回值,返回的就是被移除的末尾元素
  //   let res = arr.pop()
  //   console.log(res, arr)
  //   res = arr.pop()
  //   console.log(res, arr)

  //     4.添加元素到数组的头部  unshift方法 原数组上操作数据! 无返回值
  //   arr.unshift('xxxx')
  //   console.log(arr)
  //   arr.unshift('yyyy')
  //   console.log(arr)

  //     5. 删除数组头部的元素 shift方法  原数组上操作数据! 有返回值,被删除的元素
  //   let res = arr.shift()
  //   console.log(res, arr)

  //    6. 在数组的任意位置实现,元素的添加,修改,删除! splice方法  在原数组上操作数据!
  //    有返回值,返回值默认是一个空数组,如果有其他被删除的元素统一添加到该数组中
  //   splice(x,y,args...)
  //  x : 确定在数组的那个位置进行操作
  //  y : 是确实从对应位置开始删除的元素个数
  //  args: 用于更新的新元素列表
  //   let arr = [100, 200, 300, 'hello', true]

  //   需求,我想在1索引的位置,删除2个元素,并用 新的元素进行替换
  //   arr.splice(1, 2, 'x', 'y', 'z')
  //   console.log(arr)

  //   需求,我想在2索引的位置,删除1个元素,没有新元素替换
  //   arr.splice(2, 1)
  //   console.log(arr)

  //    需求,我想替换索引3位置元素的值,更新
  //   arr.splice(3, 1, 'world!')
  //   console.log(arr)

  //  需求,我想在索引0的位置,添加两个新元素
  //   let res = arr.splice(0, 0, 'x', 'y', 'z')
  //   console.log(arr, res)

  //    7. concat 连接多个数组,并返回连接后的新数组,没有操作原数组!
  //   let arr1 = [100, 200]
  //   let arr2 = ['hello']

  //   [100,200,'hello']
  //   let arr3 = arr1.concat(arr2)
  //   console.log(arr3, arr1, arr2)

  //   let arr3 = arr1.concat(['a', 'b'], [1, 2], 'xxxxx')
  //   console.log(arr3)

  // 利用concat方法实现数组浅拷贝
  //   let arr3 = arr1.concat([])
  //   console.log(arr3, arr1, arr3 === arr1)

  //   以下方式为深拷贝
  //   let arr3 = arr1
  //   console.log(arr3, arr1, arr3 === arr1)

  //  8. join方法  将数组中的各元素分散通过指定的字符进行连接,返回一个字符串数据!
  //   let arr = [100, 200, 300, 'hello', true]
  //   let str = arr.join('*&^*(^*&*&(')
  //   console.log(str)

  //  9. includes  判断一个元素是否存在于当前数组中,存在则返回 true  不存在返回 false
  // let arr = [100, 200, 'hello']
  // let res = arr.includes(100)
  // console.log(res)

  //  10.判断元素是否存在,如果存在则返回第一个匹配的元素值的下标!  如果不存在则返回 -1
  //  indexOf  从左往右依次进行匹配!
  // let arr = [100, 200, 'a', '3000', 'a']

  // let res = arr.indexOf('a')
  // console.log(res)

  //  11. 判断元素是否存在,如果存在则返回第一个匹配的元素值的下标!  如果不存在则返回 -1
  //  lastindexOf  从右往左进行匹配
  // let arr = [100, 200, 'a', '3000', 'a']
  // let res = arr.lastIndexOf('a')
  // console.log(res)

  // 12. 数组的切片,获取数组的子数组   返回值,一个子数组!
  //  slice(开始下标,结束下标)   左闭右开的区间

  // let arr = [100, 200, 300, 'a', 'b']
  // let res = arr.slice(2, 3) // 0 1
  // console.log(res)

  // 总结: 注意以上的方法或者属性全都是数组的实例对象才能使用的!

数组遍历

// 遍历: 就是去一个容器中,将该容器中的所有元素,访问一遍! 这种行为叫做遍历!
例如:
let arr = [‘a’, ‘b’, ‘c’, ‘d’, ‘f’]

  // 需求遍历 arr
  // 利用for循环来进行遍历 最传统的方式
  for (let i = 0; i < arr.length; i++) {
    // console.log(i)
    console.log(arr[i])
  }

冒泡和选择

let arr = [100, 2, 4, 56, 88, 91, 77]

  //   冒泡排序:元素两两之间进行比较,根据大小的判断交换位置!最终实现数组的排序
  //   双重循环

  //   for (let i = 0; i < arr.length; i++) {
  //     for (let j = 0; j < arr.length - i; j++) {
  //       if (arr[j] > arr[j + 1]) {
  //         let temp = arr[j]
  //         arr[j] = arr[j + 1]
  //         arr[j + 1] = temp
  //       }
  //     }
  //   }
  //   console.log(arr)

  //   选择排序
  //   for (let i = 0; i < arr.length; i++) {
  //     for (let j = i + 1; j < arr.length; j++) {
  //       if (arr[i] < arr[j]) {
  //         let temp = arr[i]
  //         arr[i] = arr[j]
  //         arr[j] = temp
  //       }
  //     }
  //   }
  //   console.log(arr)

数组的倒置和去重

倒置:
let arr = [‘a’, ‘b’, ‘c’, ‘d’]

  //  利用一个空数组
  // let arr2 = []
  // let len = arr.length
  // for (let i = 0; i < len; i++) {
  //   arr2.push(arr.pop())
  // }

  // console.log(arr2)
  去重:

let arr = [‘a’, ‘b’, ‘c’, ‘a’, ‘y’, ‘b’] // [‘a’,‘b’,‘c’,‘y’,‘b’]

  // 利用空数组
  // let arr2 = []
  // for (let i = 0; i < arr.length; i++) {
  //   if (!arr2.includes(arr[i])) {
  //     arr2.push(arr[i])
  //   }
  // }
  // console.log(arr2)

获取页面元素样式属性值

// 需求,获取该元素的样式属性 比如 获取它的高度值!

// className title id .....value name ....  style

// 1. 利用 elment.style 获取元素的样式对象!
// console.log(box.style, typeof box.style)

// //  利用样式对象 去获取 当前元素的属性值!
// console.log(box.style.width)
// console.log(box.style.height)
// console.log(box.style.backgroundColor) //注意:如果样式属性名是-连接的,则采用小驼峰方式获取!

// // 注意:利用element.style这种方式只能用于获取元素的 style属性中设置的样式值!
// console.log(box.style.border)

// 2.利用全局函数 getComputedStyle(elment) 返回 对象
// let res = getComputedStyle(box)
// console.log(res, typeof res)

// 利用 getComputedStyle(elment) 返回 对象 去获取当前元素正在应用的样式属性值
// console.log(res.width)
// console.log(res.height)
// console.log(res.backgroundColor)
// console.log(res.border)

// 总结: style属性的方式 和  getComputedStyle(elment)区别
//  1. style属性的方式只能去获取元素自身的style属性所设置的样式值
//  2.  getComputedStyle(elment) 获取元素正在应用的样式属性值!
//  3. style属性是可读 可写  而   getComputedStyle(elment)是只读的不能重新赋值

为元素绑定点击事件

let box = document.querySelector(‘.box’)

box.addEventListener('click', function () {

})

文档树

文档树

浏览器会将html文档中的标签,解析并转换为文档树
文档树是一个树形结构!html根标签,最外层的节点!其余的标签(节点)都是挂载于根节点上!

文档树中,由很多的节点类型!不只元素节点(标签节点)! 除了元素节点之外,还存在 一些其他的节点类型! 注释节点 文本节点 …
注意:学习的重点以及操作是在元素节点!对元素节点的 操作: 创建 增 删 查 改

创建节点并添加插入

  1. 创建一个 div 元素节点 document.createElement()

    let mydiv = document.createElement(‘div’)
    console.log(mydiv, typeof mydiv)

    注意: 被创建出来的元素节点,它是不存在于文档树中! 需要把它插入或者添加到文档树中!

插入:
获取body元素 document.body
方式一: appendChild(elment)
特点:该方法只会将元素添加到当前元素节点的末尾!

// 在挂载后 初始化 元素节点
// document.body.appendChild(mydiv)
// mydiv.id = 'div01'
// mydiv.className = 'box'
// mydiv.innerHTML = '我是div元素'

// 方式二:  insertBefore(新节点元素,旧节点元素)
// 特点: 插入新的元素节点 到指定旧节点元素的前面
let box = document.querySelector('.box')
// document.body.insertBefore(mydiv, box)

//  如果insertBefore的第二个参数为 null  则将新元素节点添加到该父节点的末尾 等价于  appendChild
document.body.insertBefore(mydiv, null)

替换节点和删除节点

需求:创建一个新的li元素把旧的li元素给替换掉!

// 1.创建一个新的li元素
let newli = document.createElement('li')
// 2.获取即将被替换的旧元素
// let oldli = document.querySelector('.first-li')
// 3.获取父节点,由父节点来完成替换操作!  ul
let ul = document.querySelector('ul')
// 进行替换操作
// replaceChild(newnode,oldnode)
// ul.replaceChild(newli, oldli)

删除:
// 删除操作
// 方式一:元素自删除!
let firstli = document.querySelector(‘.first-li’)

// firstli.remove() // 元素自我删除

// 方式二: 利用父节点进行删除指定的子元素节点

// let ul = document.querySelector('ul')
// ul.removeChild(firstli)

查询:
// 查询1: 通过指定元素,查询该元素的父节点

// let firstli = document.querySelector('.first-li')

//  通过元素节点的属性查询自己的父元素节点
// let res = firstli.parentNode   // 节点
// console.log(res)
// console.log(firstli.parentElement === res)

// 查询2: 通过父元素查询它的所有子元素节点
let ul = document.querySelector('ul')

// 元素的属性  children 属性返回的是一个 伪数组
console.log(ul.children)

快速获取表单数据

// 通过js动态获取 input的数据  value
// 1.获取所有的input元素
// 2.遍历input元素 拿到每一个input的value值
// let btn = document.querySelector('.btn')
// btn.addEventListener('click', function () {
//   //   console.log(666)
//   let inputs = document.querySelectorAll('input[name]')
//   for (let i = 0; i < inputs.length; i++) {
//     console.log(inputs[i].value)
//   }
// })

//  快速的方式  new  FormData(表单对象)
// let btn = document.querySelector('.btn')
// btn.addEventListener('click', function () {
//   //   console.log(666)
//   let formdata = new FormData(document.querySelector('form'))
//   console.log(formdata.get('id'))
//   console.log(formdata.get('name'))
//   console.log(formdata.get('sex'))
//   console.log(formdata.get('age'))
// }

函数的声明

函数:一段被封装好的可重复使用的代码段!并且可以实现某种功能!
js中可以通过关键字 function进行函数的声明创建

  //  语法结构
  //  1.声明创建一个函数
  // function 函数名(形参列表){
  //     函数体
  // }

  //   函数的声明,在声明时,函数体内部的代码是不会执行的!
  function sayHello() {
    console.log('hello world!')
  }

  //   2.调用函数\执行函数
  //  语法:  函数名()
  //  注意:函数名 + () 才能执行对应的函数!

函数的返回值

函数的返回值,大部分函数都是具备返回值!
返回值代表的是该函数执行后,对数据的处理结果! 然后利用 return语句 进行返回!外部可以使用函数的返回值!
如果函数,没有return语句,默认该函数的返回值是 undefined
注意: return语句的特点
1.return语句后可以是任何合法的js数据类型!
2.return语句具有中断函数的功能,函数的执行过程中如果碰到return 那么直接结束该函数的执行!

函数的值传递和引用传递

值传递,内部函数的数据操作不会影响外部传入的数据!
let num = 100

  //   function change(mynum) {
  //     mynum += 10
  //   }

  //   change(num)
  //   console.log(num)

  //   ---------------------------------------------

  //   引用传递,实参和形参的改变会相互影响!
  //   let obj = {
  //     num: 100,
  //   }

  //   function change(myobj) {
  //     myobj.num += 100
  //   }

  //   //   调用 函数  change
  //   change(obj)
  //   console.log(obj.num)

箭头函数

// 箭头函数: 书面称呼, lamda表达式 ,俗称是箭头函数
// 箭头函数是在es6中新加入的一种特殊的函数形式!

  // 与function函数的不同
  // 1. 创建方式不同 不需要function关键字进行声明修饰!
  // 箭头函数的创建 语法
  // (形参列表)=>{
  //     函数体
  // }

  // 2.箭头函数,通常不能像function函数那样,直接进行声明然后利用函数名进行调用
  //    箭头函数通常是依附于某个变量或者某个对象上的属性

  //   2.1 作为某个变量的值,保存箭头函数
  //   let fun = () => {
  //     console.log(666)
  //   }

  //   fun()

  //   //   2.2 作为某个对象的方法
  //   let obj = {
  //     say: () => {
  //       console.log('say...')
  //     },
  //   }

  //   obj.say()

  //   //    2.3 作为一个callback进行 函数的传递使用
  //   btn.addEventLisener('click', () => {})

  //   function fun() {}

  //   ;() => {}
  //   ;(() => {
  //     console.log(666)
  //   })()

  //   3. 箭头函数中不具备自己的this关键字

  //   箭头函数的书写小知识:

  //   ;() => {
  //     console.log(6666)
  //   }

  //  第一个: 当形参个数有且只有一个时,()是可以省略的

  // let fun = num => {
  //   console.log('fun....', num)
  // }

  // fun(50)



  // 第二个: 当函数体内部只有 一条语句时, {} 是可以省略的
  
  // let fun = num => console.log('fun....', num)
  
  // fun(5000000)


  // 第三个: 当函数体内部只有 一条语句时,该函数的返回值默认就是 该语句的结果
        
  // let fun = num => num+200

  // let fun = (num)=>{
  //   return num+200
  // }
  
  // let res = fun(100)
  // console.log(res)

作用域 和 作用域链

作用域: 指变量或者函数的作用范围!
js中目前存在三种作用域
1. 全局作用域 es6之前
2. 函数作用域 es6之前 只能通过 let 或者 const 进行声明 才会存在块级作用域
3. 块级作用域 {} es6之后才有 块级作用域

作用域链:通过作用域的链式关系,进行查找对应的 变量 和 函数

如果沿着作用域链一直寻找,直到在全局作用域下都没有找到对应的变量或者函数 就会报错!
注意:作用域链的查找规则是 从内到外!查找!

预解析

预解析: js代码在真正的执行前,会先进行一个操作!该操作称为 预解析!

预解析主要涉及两个内容 当前作用域下的var变量 和 function 函数进行提升!
函数的提升高于var变量

let 和 const 所修饰的变量不具备提升操作!但是存在一个’暂时性死区’

var、let、const三者的区别

var 、 let 、const 三者的区别
1. var存在变量提升操作,var不具备块级作用域,var可以在同一作用域重复声明同名的变量或者函数
2. let不存在变量提升操作,let具备块级作用域,let存在暂时性死区,let不允许在同一作用域声明同名的变量和函数
3. const不存在变量提升操作,const具备块级作用域,const存在暂时性死区,const不允许在同一作用域声明同名的变量和函数,const声明的同时必须赋值!

BOM

BOM (浏览器对象)对象 ==》 代表整个浏览器
浏览器环境中,为js提供了两个对象!这两个对象是浏览器提供的,也称为宿主对象!

window

window对象 BOM的核心对象 windonw指向的是 浏览器的窗口!
windo对象除了指向浏览器窗口,它还代表着js在浏览器环境下的全局对象!也称为顶层对象!
console.log(window)
window作为顶层对象,它的作用!在全局环境下所声明的全局var变量或者函数都是作为window对象的属性存在!

location

// location 代表浏览器地址栏
// 文档:https://developer.mozilla.org/zh-CN/docs/Web/API/Location

// 跳转网页
// location.href = 'https://www.baidu.com'

// 跳转网页不计入历史,更新地址栏,不计入历史操作
// location.replace('https://www.bilibili.com')

// 刷新页面
// location.reload()

// 地址栏参数  ?后的数据  key=value 键值对的形式
// location.search
// console.log(location.search, location)

history

// history 浏览器浏览记录(历史记录)

// 文档:https://developer.mozilla.org/zh-CN/docs/Web/API/History

// 前进
// history.forward()

// 后退
// history.back()

// 转到指定位置
// history.go(delta)
// history.go(1) 等价于 history.forward()
// history.go(-1) 等价于 history.back()

navigator

// navigator 用于查看设备信息,查询当前浏览器的信息、版本、名称等
// 文档:https://developer.mozilla.org/zh-CN/docs/Web/API/Navigator

localStorage

// localStorage 数据持久化到浏览器中,关闭窗口或浏览器,都不会消失

//   localStroage 将数据永久性的存储到 浏览器中! 以键值对的形式

// 设置数据, key 和 value 数据类型必须是字符串类型
localStorage.setItem('name', '张三')

// 设置数据 []
localStorage['age'] = 18

// 读取数据
console.log(localStorage.getItem('name'))
console.log(localStorage['age'])

sessionStorage

// sessionStorage 将数据临时性的存储到 浏览器中! 以键值对的形式 ! 窗口关闭 数据就消失

// 设置数据, key 和 value 数据类型必须是字符串类型
sessionStorage.setItem('name', '张三')

// 设置数据 []
sessionStorage['age'] = 18

// 读取数据
console.log(sessionStorage.getItem('name'))
console.log(sessionStorage['age'])

函数的封装

将某段重复执行代码利用进行封装,方便以后的执行
编程的思想 思维!代码的冗余问题!高内聚,低耦合原则! 经验的积累!项目的累积!错误叠加!
高内聚: 代码语句不是零散,散落!而是高度集中的! 函数封装!
低耦合: 耦合功能快之间是否连接的特别缜密!低耦合就是要求你不要连接的特别缜密!

执行上下文

// 执行上下文环境:js代码在执行的过程中,会存在一个环境!js引擎会将js代码,分别设置一个执行环境!
执行上下文环境的分类:三大类
1. 全局执行上下文
2. 函数执行上下文
3. eval()执行上下文 (忽略,了解!)

this

this关键字,可以理解为 语文的 ‘这’ 代词! 是一个变化的东西!
// this的变化是有规律的!

  // 寻找this,判断this

  // 1.在浏览器环境中的全局上下文中,this永远指向的是 顶层对象 window
  // 2.在浏览器环境中函数执行上下文中,this指向的也是 顶层对象  window , 严格模式( 'use strict')除外! 函数执行上下文,设置了严格模式,那么this指向的 undefined
  // 3.如果函数是被某个对象进行调用时,那么该函数(方法)中的this指向的是,它的调用对象(调用者)!而非持有者!
  // 4.构造函数中this,指向的是新创建出来的一个该构造函数类型的 实例 {} 空对象!
  // 5.事件对象的事件处理函数中的this,指向的是 当前被绑定的元素对象,仅适用于 function函数
  // 6.箭头函数,它不存在自己的this,它的this是该箭头函数被创建时,当时的执行上下文环境中的this!并且永不改变包括this的三大劫持手段!(类似于‘印随效应’)

构造函数

构造函数:构造函数也是函数!构造函数的本义是用于构造一个实例对象!并不是像普通函数一样为了实现某种功能!

任何函数都可以作为构造函数使用!前提是 它是否被 new 关键字调用!

构造函数的命名:软性规定,建议构造函数的首字母大写
例: var obj = new Object()

构造函数和普通函数的区别

构造函数和普通函数的区别:
1.构造函数中默认返回值已经构造完成的对象
2.普通函数默认返回值是 undefined
3.构造函数需要搭配new关键字进行使用
4.构造函数的目的不是为了实现某种功能,而是去快速构造某一类型的实例对象
5.构造函数中的this指向的是new关键字所创建的该构造函数类型的对象实例! {}空对象

    // 注意:构造函数的返回值问题
    //  1.构造函数中默认是省略 return语句  ,并且默认返回的是构建完成的实例对象 {}
    //  2.如果存在return语句,则返回的内容分情况讨论:
    //   情况一: return 返回的 数据类型是 基本值数据类型 Number、Boolean 、Sring...,则完全无视这个return,
    //   情况二: return 返回的 数据类型是 引用数据类型 则正常的将该数据进行返回

    // 为了避免上述问题的存在,建议大家构造函数中的return就不要写了!

new关键字

**new关键字是配合构造函数使用:**
     new关键字,做了几件事情:
     1.new关键字会创建一个该构造函数的实例对象,一开始是空的{}
     2.new关键字会将刚才创建的实例对象的__proto__属性指向为 构造函数所保存的 prototype指向的对象
     3.new关键字会将构造函数中的this 指向为 该实例对象
     4.最终返回这个 实例对象

this的劫持

正常情况下,this的指向都是符合 六大规则!

  // 非正常情况下,人为可以将this强行的改变!

  // 强行改变this的手段,我们称为对this的劫持!

  // this的劫持方法: call() 、 apply() 、 bind()
  // 以上的三个方法都属于,Function实例对象身上的方法!

总结:
call和apply使用方式基本一致,唯一的不同在于实参的传递方式
call是将多个实参以逗号分隔,依次传入函数中
apply是将多个实参以数组的形式,一次性传入函数中
bind劫持是利用bind方法返回一个新的函数!
劫持该函数中的this,相对于call和apply来说,它们是操作自身的函数!bind的操作新的函数!

js的垃圾回收机制

垃圾回收:JavaScript程序在运行的过程中,随着运行时间的增加,那么会相应的产生一些垃圾数据,垃圾回收机制主要是
        定时的去清理这些垃圾数据,避免内存溢出、泄露导致程序崩溃!
        
        内存的溢出:
        内存的泄露:

    注意:垃圾回收这个动作不需要人为的去管控,它是由js引擎垃圾回收的模块负责


    如何定义垃圾:
        - 标记清除:假设所有的变量或者函数等其他数据,一开始就认为他们不是垃圾!当他们产生了某种变化后,就会被打上标记,标记为垃圾
        - 引用计数:当引用型数据,没有再被任何引用时,引用链条为0的时候!就自动判定为垃圾数据
    

        正常情况下:
            - 全局作用域下的变量、函数在程序执行完毕后才会销毁
            - 局部作用域下的变量、函数,当该局部作用域执行完了!结束后,就销毁对应的变量以及函数
            - 引用数据当引用链条数量为0的时候,也会被销毁
    
    
    小提示:
        垃圾回收机制并不是JavaScript语言独有,很多编程语言都具备
        - java、python、JavaScript
        - c c++  人为的控制,人为的定期去是释放内存

闭包

闭包,这个东西! 道可道,非常道!名可名,非常名!

  // 闭包:把一些数据进行封装!包裹!形成一个独立的空间,该空间只会被能访问到该空间的‘人’使用

  // 如何才会产生一个闭包:
  // 1.假设有两个函数,A函数,B函数,并且B函数是在A函数的内部进行声明的!B函数是被嵌套声明的!
  // 2.B函数内部,使用了一些A函数中才会存在的数据!通过作用域链找到了A函数中的一些数据!
  // 3.最终当A函数执行完毕后,把B函数 ‘交’出去了! 交出去的方式有多种:1.return 2.直接把它赋值给外部的变量
  // 这个时候,就产生了闭包!

  // 什么是闭包?
  // 闭包就是一个函数在其他函数的内部嵌套声明,并且该函数内部使用了上级函数的数据!并且该函数被返回出去了!

  // 闭包的优点:
  // 1.使用闭包可以形成对立的空间,避免变量名污染问题
  // 2.利用闭包,可以在函数外,也能访问到函数内部的数据!
  // 闭包的缺点:
  // 1.闭包的产生有很多时候是隐式产生的,最终会造成内存泄漏

定时器

js中的定时器、计时器:
作用:规定一段时间,然后执行某一段代码!

  // js提供了两种创建定时器的方式:
  // 全局函数:setTimeout(一次性的)  setInerval(永久性的)
  //  这两个方法都是同步方法!而传入的callback是异步的,不会阻塞主线程
  // 以上两个函数都需要传入两个参数:
  // 参数一:规定时间后,需要执行的函数 callback
  // 参数二:规定多少时间开始执行代码 单位是ms 是忽略!

计时器被创建后都会产生一个唯一的计时器编号,可以利用对应的编号关闭计时器
例如:

 1.关闭setTimeout所创建的计时器
         let timer = setTimeout(() => {
          console.log(666)
        }, 1000)
    clearInterval(timer)
2.关闭setInerval所创建的计时器
         let timer = setInterval(() => {
           console.log(666)
         }, 1000)

元素的自定义属性

<!-- 如何创建自定义属性 -->
<!-- 1. 直接在元素的开始标签中,书写自定义的属性名以及赋值操作 -->
<!-- 2. 利用data-* 形式创建自定义属性  -->

<!-- 如何读取自定义属性的值 -->
<script>
  // 如何读取官方的元素属性?
  let box = document.querySelector('.box')
  // 需求:读取class的属性值
  console.log(box.className)
  //   需求:读取id的属性值
  console.log(box.id)

  //   读取自定义的元素属性值
  // 需求:读取add自定义属性的值
  //   注意:自定义属性的值,不能通过点语法进行获取,需要使用元素对象的方法进行获取!
  console.log(box.getAttribute('add'))

  //   需求:读取data-reduce自定义属性的值
  console.log(box.getAttribute('data-reduce'))

  console.log(box.getAttribute('class'))
  console.log(box.getAttribute('id'))

  //   修改、设置一个元素的自定义属性
  //   利用setAttribute会将数据,隐式的转换为string类型
  box.setAttribute('add', true)
  //   box.getAttribute('add')
  //   console.log(typeof box.getAttribute('add'))
  box.setAttribute('class', 'boxxxxx')
  box.setAttribute('data-reduce', '700')

  //   利用setAttribute为元素添加新的自定义属性
  box.setAttribute('mydata', 100)

  //   特别的data-属性的读取方式
  console.log('------------------------')
  console.log(box.dataset.reduce)
  console.log(box.dataset.a)
  console.log(box.dataset.b)

时间对象

// 创建一个时间对象 利用 JS提供的 Date(构造函数、类) ===》 new Date类 实例化一个时间对象
// 四种创建方式
// 方式一:无任何构造参数
// let date = new Date() // 返回一个当前系统时间的,时间对象
// console.log(date, typeof date) // Tue Jan 31 2023 11:11:54 GMT+0800 (中国标准时间)
// // 注意:不要过多的关注,浏览器所展示的时间对象的样式!

  //   方式二: value  时间戳 返回一个由当前时间戳与格林威治时间(标准时间的插值)所代表的一个时间对象
  //   let date = new Date(59000)
  //   console.log(date, typeof date) // 1970-1-1-8:00:59

  // 时间戳:当前时间与标准的格林威治时间的毫秒差值,称为时间戳!
  // 格林威治:英国的小镇   1970-1-1-00:00:00    之间的差值     1970-1-1-00:00:58     58秒==》58000毫秒  这个58000毫秒就是我们说的时间戳
  //    1970-1-1-00:00:00        1970-1-1-00:00:01  08:00:01

  //   方式三: dataString 时间字符串  该方式不推荐使用!各浏览器之间对时间字符串的定义有些差入!
  // 时间字符串的参考:https://www.w3.org/TR/NOTE-datetime
  //   let date = new Date('1997-10-19')
  //   console.log(date)

  //  方式四: 依次传入  年  月 日  时  分  秒 毫秒 进行构造时间对象
  //   let date = new Date(2023, 1, 31, 11, 34, 48, 1500)
  //   let date = new Date(2023, 10)
  //   console.log(date)

  // 特殊的使用方式 不使用 new Date()
  //   Date()函数 返回的是当前时间对象的字符串形式!
  //   let date1 = Date()
  //   let date2 = new Date()
  //   console.log(date1, typeof date1, date2, typeof date2)

  // 操作时间对象
  // 1.获取对应的时间数据
  let date = new Date() // 14:23:1:578
  console.log(date)
  // 1- 获取时间对象的年份
  console.log(date.getFullYear())

  //   2- 获取时间对象的月份, 注意月份是从 0开始计算的  0代表1月
  console.log(date.getMonth() + 1)

  //    3- 获取时间对象的日 一个月的第几天
  console.log(date.getDate())

  //    4-  获取时间对象的  星期数 注意:范围是0-6  0代表星期天
  console.log(date.getDay())

  //   5- 获取时间对象的 小时数
  console.log(date.getHours())

  //    6- 获取时间对象的 分钟数
  console.log(date.getMinutes())

  //    7- 获取时间对象的  秒数
  console.log(date.getSeconds())

  //    8- 获取时间对象的 毫秒数
  console.log(date.getMilliseconds())

  // 2.设置对应的时间数据
  //   将以上的所有方法的 get 替换为 set
  //   date.setFullYear(2000)
  //   console.log(date)

  //   获取时间对象的时间戳
  //   console.log(Date.now()) //获取当前系统时间的时间戳    14:23:1:804
  console.log(date.getTime()) // 获取当前时间对象的时间戳 

数学函数

注意:Math函数不能作为构造函数使用! 所有是无法实例化一个数学对象!

  console.log(Math)

  abs()  求一个数的绝对值
 
     floor 地板数,对一个数向下取整

     ceil 天花板数, 对一个数向上取整
  
     max 返回当前参数列表中最大值

     min 返回当前参数列表中最小值

     pow 求一个数的幂
  console.log(Math.pow(2, 5))

    sqrt 开平方根
    
  console.log(Math.sqrt(9))
  
     round 对一个数四舍五入
 
    random 随机数, 随机返回一个 0-1之间的小数  包括0,不包括1  伪随机!
  console.log(Math.random())   

element元素的offset和client

let box = document.querySelector(‘.box’)
box ==> 是一个dom元素 elment元素

  //   offset系列的属性   5个   获取当前元素的相关的偏移数据
  //   注意:offset属性具体的内容! 首先明确,该元素的 offsetParent 是谁?
  //  1. offsetParent
  console.log(box.offsetParent) // 默认情况下,元素是相对于 body元素进行偏移的!
  //   注意:offsetParent 指向的是距离当前元素最近的并且开启了定位的祖先元素!如果没有任何的元素符合这一条件那么,offsetParent默认指向body元素

  //   2. offsetTop  当前元素的顶部距离offsetParent元素的距离  返回值是 number类型
  console.log(box.offsetTop)

  //   3. offsetLeft  当前元素的左侧部分距离offsetParent元素的距离 返回值是 number 类型
  console.log(box.offsetLeft)

  //    4. offsetWidth 当前元素的可见框的  宽度大小    width + padding  + border
  console.log(box.offsetWidth) // 200 + 2 + 10

  //    5. offsetHeight 当前元素的可见框的  高度大小    height + padding  + border
  console.log(box.offsetHeight) // 200 + 2 + 10

  console.log('--------------------')

  //   client系列属性  4个  当前元素自身的一些数据值
  //   1. clientTop   当前元素的顶部边框大小  number类型  元素的padding 到 边框的之间 间距
  console.log(box.clientTop)

  //   2. clientLeft   当前元素的左侧边框大小  number类型
  console.log(box.clientLeft)

  //   3. clientWidth  当前元素的除border属性外的可见框宽度大小  width + padding
  console.log(box.clientWidth)

  //    4. clientHeight  当前元素的除border属性外的可见框高度大小  height + padding
  console.log(box.clientHeight)

  // 特殊情况:一个元素 只设置了 宽和高
  // box.offsetWidth   ===  box.clientWidth

事件

事件:某个事情,特殊的一种情况!

  // js中可以利用某个事件的触发!去相应的执行某一断代码!

  //   事件的三要素:
  //   1. 事件源
  //   2. 事件类型
  //   3. 事件处理函数

  //   JS中如何为一个元素绑定事件
  //  绑定事件的三种方式:
  //  1. 利用 元素标签 自身的 on* 属性(事件属性) 进行事件的绑定  完全不建议使用
  //    语法:  onclick  = '函数形式的字符串' ==》  onclick = 'add()'
  function test(num) {
    console.log('html标签的事件属性')
  }

  //   2. 在js脚本中利用元素对象的事件属性进行,数据的绑定 偶尔用!
  //   let btn = document.querySelector('button')

  //   //   btn元素对象上自身的事件属性进行绑定事件
  //   console.dir(btn)
  //   btn.onclick = function () {
  //     console.log('事件属性方式')
  //   }

  //    3. 通过事件监听器,进行元素的事件绑定  强烈推荐的!
  // let btn = document.querySelector('button')
  // btn.addEventListener('click', () => {
  //   console.log('监听器方式')
  // })

事件的解绑

// 解绑一:

// let count = 1
// let btn = document.querySelector(‘button’)
// function test() {
// // 需求:button点击事件只能 有效的点击5次
// if (count === 5) {
// // 解绑事件, 对button按钮进行事件的解绑
// btn.onclick = null
// }
// console.log(‘按钮一’, count++)
// }

// 解绑二:
// let btn2 = document.querySelector(‘.btn2’)
// let count = 1
// // 为btn2绑定事件
// btn2.onclick = function () {
// console.log(this)
// // 需求:button点击事件只能 有效的点击5次
// if (count === 5) {
// // 解绑事件
// this.onclick = null
// }
// console.log(‘按钮二’, count++)
// }

// 解绑三:
let btn3 = document.querySelector(‘.btn3’)
let count = 1
btn3.addEventListener(‘click’, function test() {
// console.log(this)
if (count === 5) {
// 解绑事件 监听移除函数
btn3.removeEventListener(‘click’, test)
}

console.log('按钮三', count++)

})
注意:如果用事件属性给一个元素绑定多个事件 那么后面的事件会覆盖前面的事件 ,如果是用事件监听器则可以为同一个元素设置多个事件

事件分类

// 函数 获取页面的 元素 通过选择器的方式
function $(selector) {
return document.querySelector(selector)
}

// 资源事件
// load: 资源加载完成后就会触发
// $('img').addEventListener('load', () => {
//   console.log('图片加载完成')
// })

// // error: 资源加载失败时触发
// $('img').addEventListener('error', () => {
//   console.log('图片加载失败')
// })

// // 焦点事件
// // 焦点事件只用于表单元素

// focus : 获取焦点事件
let inp = $('form input[name=name]')
// inp.addEventListener('focus', () => {
//   console.log('获取到焦点了')
// })

// // blur: 失去焦点事件
// inp.addEventListener('blur', () => {
//   console.log('失去焦点了')
// })

// // 鼠标事件
// // click:鼠标左键点击事件
// let btn1 = $('.btn1')
// btn1.addEventListener('click', () => {
//   console.log('点击事件触发了')
// })

// // contextmenu: 鼠标右键点击事件,右键点击改元素是触发的事件
let box = $('.box')
let box2 = $('.box2')
// box.addEventListener('contextmenu', () => {
//   console.log('鼠标右键被点击了')
// })

// // dblclick: 双击事件
// box.addEventListener('dblclick', () => {
//   console.log('双击事件触发了')
// })

// // mousedown: 鼠标按下事件
// box.addEventListener('mousedown', () => {
//   console.log('mousedown')
// })

// // mouseup: 鼠标松开事件
// box.addEventListener('mouseup', () => {
//   console.log('mouseup')
// })

// // mouseenter\mouseover 鼠标移入事件
// box2.addEventListener('mouseenter', () => {
//   console.log('mouseenter')
// })

// box2.addEventListener('mouseover', () => {
//   console.log('mouseover')
// })

// // mouseleave\mouseout 鼠标移出事件
// box2.addEventListener('mouseleave', () => {
//   console.log('mouseleave')
// })

// box2.addEventListener('mouseout', () => {
//   console.log('mouseout')
// })

// // mousemove: 鼠标移动事件
// box.addEventListener('mousemove', () => {
//   console.log('mousemove')
// })

// // wheel : 鼠标滚轮事件
// box.addEventListener('wheel', () => {
//   console.log('wheel')
// })

// change:当值发生变化时触发,多用于表单元素
// let select = document.querySelector('form select')
// select.addEventListener('change', () => {
//   console.log('change')
// })

// inp.addEventListener('change', () => {
//   console.log('input change')
// })

// // input: 输入框输入字符时触发该事件
// inp.addEventListener('input', () => {
//   console.log('正在输入....')
// })

// // 按键事件

// // keydown: 按钮按下事件
// document.body.addEventListener('keydown', () => {
//   console.log('keydown')
// })

box.addEventListener('keydown', () => {
  console.log('keydown')
}) 

// inp.addEventListener('keydown', () => {
//   console.log('keydown')
// })

// keyup:按钮抬起事件
// document.body.addEventListener('keyup', () => {
//   console.log('keyup')
// })

// // keypress: 按钮按住不放事件
// document.body.addEventListener('keypress', () => {
//   console.log('keypress')
// })

事件对象

事件对象:一个事件被触发后!浏览器对应的会自动产生一个事件对象!并且该事件对象是具备类型的!
鼠标事件、键盘事件、资源事件…
事件对象的作用:事件对象上存放了一些与该事件产生时的一些数据或者方法!

  //   事件对象如何使用?
  //   事件对象在事件函数被执行时,浏览器会自动的向该事件函数传入对应的事件对象!只需要利用一个形参变量来接受即可!
  //   一般这个形参变量,命名为:  event ==> ev

  //   注意:不同类型的事件对象,所保存的数据的不一样的!有些属性是任何事件对象都具备的,比如: type
  //    也有很多的属性是该事件对象所独有的!

  //  事件函数调用执行时,一般不会传入其他的参数!
  //  因为事件函数的第一个实参是传入的事件对象!

事件执行机制 ——冒泡

  // 事件的冒泡:事件的传递过程! 事件是可以进行传递的!
  // father 盒子  son 盒子  绑定了点击事件
  // son盒子在father盒子的内部    点击son时候   son点击会触发  father触发  事件会传递!传递的过程是 由内到外 !  冒泡!
  //   事件的冒泡是建立在统一个事件类型上的! 比如  click...bdlclick...等

事件的执行机制——捕获

// 事件的捕获:事件的传递过程! 事件的传递过程分为 捕获阶段和冒泡阶段
// 默认情况下所有的事件都是的冒泡阶段触发的,但也有例外可以让事件提前在捕获阶段触发!
// 冒泡过程: 从内到外
// 捕获过程: 从外到内
// 一个完整的事件触发,必定经历两个阶段,1.捕获阶段 2.冒泡阶段

  //   如果想实现某个元素的事件处理函数在捕获阶段就执行,需要利用 addEventListenter 方法的第三个参数
  //   第三个参数是一个布尔值,默认情况是 false  代表不在捕获阶段执行!  true 代表在捕获阶段执行!

event对象 target 、currentTarget

    let box = document.querySelector('.box')
    box.addEventListener('click', (ev) => {
    console.log(this) // box  自身  box
    console.log(ev.target)
    console.log((ev.currentTarget === this) === box)
    console.log('---------------')
    // this ==>  当前处理函数的事件源   this指向是被绑定事件的元素
    // ev.target ==> 触发该事件产生的对象元素
    // ev.currentTarget ==》 正在处理该事件的元素对象

阻止冒泡

// 事件默认是允许冒泡的!冒泡的过程会传递给上层的元素,导致上层元素不得不触发该事件,并且执行事件函数
通过ev.stopPropagation()
let father = document.querySelector(‘.father’)
let son = document.querySelector(‘.son’)

  father.addEventListener('click', (ev) => {
    ev.stopPropagation()
    console.log('father-click')
  })
  son.addEventListener('click', (ev) => {
    // 阻止当前的事件继续向上冒泡
    ev.stopPropagation()
    console.log('son-click')**加粗样式**
  })

  document.body.addEventListener('click', (ev) => {
    console.log('body-click')
  })

显示原型、隐式原型

JS中任何的一个实例对象都具备一个 隐式原型属性 proto
JS中所有的function函数身上都具备一个 显示原型属性 prototype

因为function也是一个对象所以function身上同时具备 protoprototype

prtotype 和 proto 是两个属性!存储的是 对象类型的数据! Obeject类

原型链

实例对象身上__proto__ 存储的是什么数据类型? Object

  原型链
  每一个实例对象上都具备  __proto__ 原型对象
  当一个对象在自身上找不到对应的属性或者方法时,会沿着__proto__原型对象身上去寻找!  obj {}
  如果往上一级的__proto__身上还是找不到想要的属性或者方法 obj.__proto__
  那么它会继续沿着当前这一级__proto__继续寻找!  obj.__proto__.__proto__
  ....  obj.__proto__.__proto__.__proto__
  沿着原型链最终找到 null  就结束! 如果已经访问到null 都还没有找到想要的属性或者方法 则放回 undefined
  以上描述寻找的过程就称为  原型链!

ES5类的写法

类:抽象的概念! 类中会定义属性和方法,实例化的对象会拥有该类的属性和方法

// ES5中
  // 类的定义方式
  // 函数式定义方式  function

  // 定义一个 Person 类
  // 属性: 姓名  性别 年龄....
  // 方法: 吃饭  睡觉 打豆豆...

  function Person(name, sex, age) {
    this.name = name
    this.sex = sex
    this.age = age
    this.country = '中国'
  }

  Person.prototype.eat = function () {
    console.log('eat...')
    console.log(this, '@')
  }

  Person.prototype.sleep = function () {
    console.log('sleep...')
  }

  Person.prototype.play_dd = function () {
    console.log('play_dd...')
  }

  //   实例化:创建一个person类的实例对象
  let p1 = new Person('张三', '男', 20)
  let p2 = new Person('小明', '男', 25)
  console.log(p1, p2)
  // p1.eat()
  // p1.sleep()
  // p1.play_dd()

ES6 类的写法

class Person {
        country = '中国'
        // 构造器,构造函数  必须的!
        constructor(name, sex, age) {
          this.name = name
          this.sex = sex
          this.age = age
        }

        // Person类中 {}
        // 所定义的方法直接就挂载到 Person.prototype对象上
        eat() {
          console.log('eat...')
        }

        sleep() {
          console.log('sleep...')
        }

        play_dd() {
          console.log('play_dd...')
        }
      }

      //    实例化一个Person类的对象
      let p1 = new Person('张三', '男', 20)
      let p2 = new Person('张三', '男', 20)
      console.log(p1, p2)
      //   p1.eat()
      //   p1.sleep()
      //   p1.play_dd()

私有属性和方法、静态属性和方法

私有属性或者私有方法,指的是该属性和方法只能在类中使用,不能够通过实例化的方式进行点语法的获取由#属性名、#方法名 创建。
静态属性和静态方法,指的是该属性和方法只能由类本身进行调用!由static 属性名、static 方法名创建

super

super 关键字 它在js中特用于!class的情况!

  //   super关键字有点类似于this  this==》指代某个对象!
  //   super也有指代的意思,也是指代某种东西!
  //   super的指代,或者使用的三种情况
  //    1. constructor 构造函数中使用时  super 就是指代了 父类的constructor函数本身
  //    2. 在子类的'普通'方法中(除静态方法外) super 指代的是 父类的 prototype属性指向的对象 Student extents Person  ==》  super  ==》 Person.prototype
  //    3. 在子类的静态方法中, super 指代的是 父类 本身    Student extents Person  super ==》 Person

  // 类中有那些方法?  静态方法 static 私有方法 # 普通方法 无任何修饰
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值