JavaScript基础
JavaScript的组成部分
文档对象模型
DOM:document(页面,文档) object(对象) model(模型)
文档对象模型就是咱们页面中的一系列标签,元素,隐藏元素
浏览器对象模型
BOM:browser(浏览器) object(对象) model(模型)
浏览器对象模型就是浏览器窗口中的一系列的操作:弹窗,地址栏,浏览器的所有的相关信息
ECMAscript
js一个开发语法的规范,规定了js语法到底是如何编写,如何执行的
js的编写位置
-
行内式(不推荐使用)
<div onclick="alert('我是一个div标签')">文本</div>- 优点: 直接对元素进行操作
- 缺点: 直接书写在行内,代码显示比较乱 没有做到结构样式行为的分离 不易于维护
-
内嵌式
-
基本语法格式:将所有的js代码放在一个script标签里面
<script> //js语句 </script> -
书写位置:放在head里面或者是body里面,或者是任何位置都可以
-
js里面的代码是从上到下执行的
-
-
外链式
<script src="js文件的路径"></script>- 一个页面中可以引入多个外部js文件
js的注释
- 单行注释: 直接使用双斜杠 //
ctrl+/ - 多行注释: /* */
shift+alt+a
js的输出形式
alert('') 弹窗输出,以浏览器弹窗进行显示
console.log() 以控制台形式进行输出的
console.log() 打印属性和方法
document.write() 页面输出
打断点
debugger
实现点击页面中的元素
-
单机事件
onclick-
超链接
<a href="js语句">文本</a> -
非超链接
<div onclick="alert('我是一个div标签')">文本</div>
-
注意: 如果元素是一个非a标签,则需要触发一个js点击事件
变量
含义:变量指的是程序中存储输入的一个容器
计算机存储数据的过程中以一个标识符代表这个数据,
可以通过这个标识符找到对应的数据
标准语法:var 空格 变量名 = 值
var 关键词,声明变量的时候必须使用的
空格 分割关键词和变量
变量名 个容器,标识符
= 赋值
值 变量的数据内容
变量声明
-
声明并赋值
var num = 100 -
先声明,使用时再赋值
var num1;num1 = 200 -
直接声明,不赋值
var num2声明变量不赋值,直接打印,返回undefined -
不声明直接使用变量 没有声明的变量直接使用,程序报错 js里面只要程序报错,后面的程序将不会被运行,阻断程序运行
-
同时声明多个变量
var num4,num5,num6变量与变量直接使用逗号隔开 一起打印,在一行中输出,输出的值是以空格隔开的
console.log(num4,num5,num6) -
同时声明多个变量并直接赋值
var num7=700,num8=800
变量的命名规则和规范
-
命名规则:具有强制性,必须遵守
1、字母,数字,下划线(_),$组成 2、严格区分大小写:num,NUM 3、不能以数字开头 4、不能使用关键字和保留字 关键字:程序中已经规定的关键词,var,for,if,else,break,contniu... 保留字:有可能以后出现的内容变成关键字top.left.right.bottom.center,position... 5、不能出现空格 -
命名规范:
1、见名知意 2、驼峰命名法:从第二个单词开始,首字母大写myName,shopCar
数据类型
-
基本数据类型
-
数值类型--Number类型
所有的数字都是数值类型(10,2,8,16进制的数值也算) NaN不是一个数字的数值类型 控制台打印呈蓝色 -
字符串类型--String类型
任何带引号的都算作字符,包括空格 控制台打印呈黑色 -
布尔类型--Boolean类型
true真和false假,主要应用在判断里面 -
null类型--空类型
空的意思 只有一个就是null 要想显示,出现的话,必须赋值一个空才能显示 -
undefined类型--未定义类型
只有一个,代表的是没有定义的意思 变量声明没有赋值,没有值的意思
-
-
复杂数据类型
- 函数
Function - 数组
Array - 对象
Objest - 日期
Date - 正则
RegExp
- 函数
检测数据类型
-
typeof(变量/检测的内容) -
typeof 变量 document.write(typeof null)返回值为特殊值,object对象
-
typeof 返回值
numberstringbooleanobjectfunctionundefined
typeof(typeof(124))
//注意:无论嵌套多少个typeof检测数据类型最终返回的结果必然是string
判断变量是否是数字
isNaN() -- is not a number "是的,它不是一个数字"
语法:isNaN(变量)
不是数字返回 ture
是数字返回 false
注意:isNaN方法,会将变量中的值隐式转换成数值类型再进行检测
Number.isNaN(变量)
不是数字返回 ture
是数字返回 false
注意:检测前没有隐式转换
数据类型转换
-
转换成数值类型
-
Number(变量)1)可以把一个变量强制转换成数值类型 2)可以接收小数 3)可以转换布尔类型,true=1 false=0 4)null转换数值0 5)强制转换成数值时,如果不能转换将返回NaN(不是一个数字),数据类型是数值类型**注意:**所有其他数据类型转为数值的隐式转换。都是使用Number方法进行转换
-
浮点整型转换**
parseInt(变量)**1)不允许接收小数 2)从第一位开始检查,是数字就保留,直到遇到不是数字的就结束 3)如果第一位就不是数字,直接结束返回NaN -
浮点型转换**
parseFloat(变量)**1)只认一个小数点 2)转换时,除小数点之外,遇到其他的字符都直接结束 3)转换时,从第一位开始识别,直到遇到非数字的值 4)如果第一位就不是数字,直接结束返回NaN -
除了+号以外的数学运算符
数学运算符: + - * / % 加号两侧都是为数值类型,则返回数值 加号任意一侧是字符串类型则实现的拼接 其他的数学运算符 返回值为数值类型的内容 -
转为数值的隐式转换
除了加法以外的 数学运算符 - * / % 自操作 -- 运算 isNaN() == 比较的时候 有一边是数值类型,则另一边会隐式转为数值 > >= < <= 的比较,如果有一边是数值类型,则另一边会隐式转为数值
-
-
转换成字符串类型
-
变量.toString( )使用的时候,不能转换null,undefined,其余的都可以强制转换 -
String(变量)都可以转换**注意:**其他数据类型转为字符串的隐式转换,都是使用的String方法进行转换
-
转为字符串的隐式转换
+前后只要有一个数据类型为字符串,都会返回字符串类型,实现拼接 数据当做对象的属性名的时候,会隐式转为字符串
-
-
转换成boolean类型
-
Boolean(变量)只有""(空字符串)、null、undefined、0、NaN会转换成false,其余的都转换成true**注意:**其他数据类型转换为布尔的隐式装换,都是使用的boolean方法进行
-
转为布尔隐式转换
!取反 逻辑运算的时候,会先隐式转换为布尔,然后校验 条件判断的时候(条件分支,循环分支)
-
进制的表示
十六进制:0x 或 0X
八进制:0 或 0o 或0O
二进制:0b 或 0B
数学运算符
+ - * / %
做数学运算时,除了+以外所有的-*/%都会针对于一个纯数字的字符串进行隐式转换
布尔类型做运算的时候会转换成数值类型--隐式转换(true--1,false--0)
数学运算时,null隐式转换成0,undefined做数学运算的时候返回NaN
-
数学+
本质:求和,能做拼接 +两侧都为数值类型,求和 +的任意一侧是字符串,则实现拼接 -
数学-
本质:求差值 -两侧都为数值类型,则进行数学运算 -任意一侧不是数值,将返回NaN 注意:布尔类型做运算的时候会转换成数值类型--隐式转换(true--1,false--0) -
数学*
本质:求乘积 -
除号/
注意:null做除法运算的时候,返回Infinity -
取余%
取余数运算的时候,不会涉及null,undefined
赋值运算
= += -= *= /= %=
赋值= : var a = 100 将右侧的值赋值给左侧的变量
赋值+=: a+=1 <=> a = a + 1
赋值-=: a+=1 <=> a = a - 1
赋值*=: a+=2 <=> a = a * 2
赋值/=: a+=2 <=> a = a / 2
赋值%=: a+=2 <=> a = a % 2
比较运算符
> >= < <= == === != !==
大于>
大于,条件成立返回true否则返回false
大于等于>=
大于或等于,条件成立返回true否则返回false
小于<
小于,条件成立返回true否则返回false
小于等于<=
小于或等于,条件成立返回true否则返回false
等于==
两个数值相等即可
注意:纯数字的字符串会隐式转换,先转换成数值,然后再比较
全等于===
要求值和类型都相等
不等于!=
只要值不相等就返回true
不全等!==
要求值和类型都不相等
逻辑运算符
&&与 ||或 !非
逻辑与&&
同时满足
同真则真,遇假则假
逻辑或||
满足一个即可
有真则真,同假则假
逻辑非!
取反
注意: 逻辑运算符具有短路逻辑,如果条件1不满足,条件2则不进行运算
自运算
前置++a <==> a += 1 <==> a = a + 1
后置a++ <==> a += 1 <==> a = a + 1
赋值情况:
b=++a 先运算++a,在赋值
b=a++ 先赋值,再运算a++
位运算
转二进制运算
& 按位与:同1则1
| 按位或:有1则1
^ 异或:一个数异或另一个数两次回到自己本身
三目运算符
x = 表达式1 ? 值1 : 值2
判断表达式1是否为真,如果为真则将值1赋值给x,否则将值2赋值给x
例:max = a > b ? a : b;
弹窗
-
提示框**
alert()**点击确定,弹窗自动关闭 -
可输入的弹窗**
prompt(参数1,参数2)**参数1:提示文本 参数2:输入框中的默认值注意:返回值为字符串类型
-
确认取消框**
confirm()**
js程序三大执行结构
顺序结构、选择结构、循环结构
-
顺序结构:
代码自上而下执行 -
选择结构(分支语句):
-
if语句:
1)if语句: if(判断条件/表达式){ 条件满足执行的代码块 } 2)if else语句 if(判断条件){ 条件满足执行的代码块 }else{ 条件不满足执行的代码块 } 3)if else if语句 if(判断条件1){ 条件1满足执行的代码块 }else if(判断条件2){ 条件2满足执行的代码块 条件2不满足将直接跳出 } 4)if else if else语句 if(判断条件1){ 条件1满足执行的代码块 }else if(判断条件2){ 条件2满足执行的代码块 }else{ 条件都不满足执行的代码块 } -
switch语句:
switch (变量){ case 情况1: 满足情况1执行的代码块 break case 情况2 满足情况2执行的代码块 break case 情况3 满足情况3执行的代码块 break default: 情况都不满足,执行default语句 }注意:如果有一部分需要执行的语句是一样的,可以把break放在所有相同情况的结束位置
如果没有break,会继续执行下面的代码块,不会再进行比较,直到遇见break(没有break的时候case情况具有穿透性)
-
循环
组成部分: 1、初始变量 2、判断条件 3、执行的循环体 4、改变循环条件(自增自减)
-
while循环语句
while(判断条件){ 循环体 } -
do while循环语句(至少执行一次)
do{ 循环体 }while(判断条件) -
for循环
for(初始变量;判断条件;改变循环条件){ 循环体 } for(表达式1;表达式2;表达式3){ 循环体 } 执行原理:表达式1→表达式2→循环体→表达式3→表达式2→循环体→......
break和continue
break: 打断循环 让程序不在执行
continue: 跳出本次循环,继续执行下一次循环
双重循环
for(var i= 1; i< =9 ; i++){
for(var j =1; j<=9 ;j++){
循环体
console.log("内容")
}
}
外层循环执行1次,内容循环执行一轮 建议:大的循环在里边,小的循环在外面(性能问题)
函数
函数就是一个盒子,盒子里面放置了一些代码片段
盒子不使用,代码就不会执行
function 声明函数的关键词
空格 隔开声明和名字
box 盒子名、变量名,(遵循变量命名规则规范)
( ) 必须存在,一般用来放参数
{ } 函数封装的代码片段
函数定义
-
声明式函数
function box(a){ 执行的代码片段; } -
赋值式函数(表达式)
var box = function(a){ 执行的代码片段; }
函数调用
-
声明式函数调用
函数名( ) -
赋值式函数调用
变量名( ) -
区别:
声明式函数调用时,在函数前面或函数后面都可以调用执行 赋值式函数调用时,只能在函数后面调用
函数中的参数
函数调用和声明过程中参与执行的变量与变量的值
形参:形式参数
放在函数定义的( )里,多个形参之间用逗号隔开,形参相当于变量
实参:实际参数
放在函数调用的( )里,用来给形参赋值
[多个参数问题]
形参和实参一一对应
若形参比实参多,多出来的形参为undefined(声明变量未赋值)
若形参比实参少,多出来的实参没有变量去接收
return
本质:返回 函数中实现的作用:终止函数,返回一个值
-
终止函数:
函数体里面遇到return,return后面的程序不再执行
-
返回值:
表达式执行完毕后,返回一个值
return 返回值
注意:函数本身没有返回值,默认返回undefined
**注意:**后置操作在函数内遇见return,则会先返回变量的值,再进行自增或自减
arguments
函数内部保存了一个arguments对象,类数组
对象里面保存的是实参的内容
console.log(arguments);
console.log(arguments[0]);
arguments[下标] 下标从0开始
arguments.length 长度
获取arguments中的每一项,需要使用arguments[下标]访问获取
预解析
js在浏览器编译:js解析,js执行
-
js解析:预(提前)解析
js执行时会把所有代码通读一遍,再执行 变量提前(预解析只解析了变量的变量名,值还保留在原地)
在代码执行之前,将var声明变量及声明式函数,提升到当前作用域的最前面
赋值式函数只有变量提升,没有函数提升
在主流浏览器中,条件分支中定义的函数,预解析只能将函数名提升,但是没有值
**注意:**如果声明式函数名和var 变量同名,则以函数为准(函数是一等公民)
**注意:**函数调用,会先完成形参赋值,再预解析
**注意:**赋值式定义的函数,赋值的函数如果有名字,则此函数名只能在函数内使用var ff=function fn(){};
console.log(num) //undefined var num = 66; console.log(num) //66 相当于: var num console.log(num) num = 66 console.log(num) -
js执行:
代码自上而下运行
作用域
作用域指变量可执行的范围
全局作用域:
任何一个地方都能使用的变量
最大的变量widow
局部作用域:
在全局作用域的基础上,开辟了一个小的作用区域,变量只能在这个小的独立区域中使用
在函数的内部会形成一个独立的作用域,但是如果你变量的声明的时候,
没有加var,声明的变量仍然是全局的变量
添加了var,声明的变量只会在function函数中起作用
注意: 做函数封装的时候,定义的变量建议添加var 如果函数未调用,代码不执行,函数内的全局变量不存在变量提升
变量的使用规则
-
定义规则
在局部作用定义的变量就是 局部变量,只能在该局部作用域或后代作用域中使用 -
访问规则
1)就近原则,如果函数内部有自己的变量,优先使用自己的 如果自己没有,找父级函数,如果父级没有,继续往外层函数查找 如果都没有,则使用全局变量 如果全局变量也没有,则程序报错 2)只能向外部访问 -
赋值规则
先找到变量位置,如果自己作用域中有变量,则优先对自己作用域中的变量赋值 否则给外层的变量赋值
递归函数
函数内部嵌套自己本身,就会形成递归,递归类似于循环
基本语法:
function fun(){ //外部函数
fun() //内部调用自己本身
}
fun()
具备的条件: 函数,判断条件,必须得有(递归出口:程序结束条件) 没有递归出口就是死递归,类似于死循环
自调函数(自执行函数)
自身可以执行的函数,在函数定义好后立即执行
赋值式函数的一种特殊使用
语法1:
(function(形参){
函数体;
})(实参);
很多时候,会将分号写在自调函数的最前面
;(function () {})()
语法2:
!function(形参){
函数体;
}(实参);
语法3:
~function(形参){
函数体;
}(实参);
对象
对象:对象相当于一个内容,这个内容里面包括了该内容的所有的属性
基本语法:
var obj = {
id:"001",
name:"乐乐",
sex:"男",
age:18
}
var 声明变量的关键词
obj 对象名
= 赋值符
{ } 对象的基本内容,{}里存储的内容为:键值对
键:属性 值:属性值
注意:
- 赋值的不是对象的值,而是对象的地址
- 每个键值对之间用逗号隔开
- 键不需要带引号
- 值如果是数值就不需要带引号,字符串需要带引号
- 值不一定非得是基本数据类型
- 字面量对象中,当属性名中有特殊符号的时候,会使用引号包裹
- 对象中的属性名只能为字符串数据类型(或者Symbol)
- 对象的属性名在对象中是唯一的(不重复)
声明对象
-
js声明对象的方式有两种
- 字面量声明方法:
var obj1 = { } - 通过构造函数的方法声明对象:
var obj2 = new Object( ) //使用new创建
- 字面量声明方法:
-
声明并赋值
var obj1 = { name:"乐乐", age:18 } -
先声明,后赋值
var obj1 = {} //空的对象 obj1.name = "乐乐" //点语法 obj1['age'] = 18 //数组关联法**注意:**点"."表示"的" 中括号赋值,属性名需要带引号
如果在操作数据成员的时候,属性名存储在变量中,需要通过对象来操作变量的方式获取新增数据,则只能使用数组关联法
使用数组关联法的时候,如果中括号中是变量,则不能用引号包裹,否则不能识别
操作对象
-
给现有对象添加键值对
同上赋值方法
-
修改现有对象的键值对 同上赋值方法,覆盖
-
删除对象中的内容 方法:
deletedelete obj.age -
查对象中的属性的值
obj.age
对象补充
1、对象的属性名只能是字符串
2、字面量对象的属性名是变量则需要使用中括号包裹
3、对象的属性名如果是字符串拼接起来的则也需要用中括号包裹
4、如果对象的属性名有特殊符号比如 border-style, 在访问的时候需要用数组关联法
5、访问对象属性值的时候,如果属性名不存在则返回undefined
6、对象的属性名 如果有数字属性名,则先按数字排序,然后按写入的顺序排序
7、对象转为字符串
语法: String(对象)
返回值: '[object Object]'
注意: 所有对象通过String方法转为字符串的返回值都以样
数据存储的相关地址
- 数据存储过程中的数据分为:基本数据类型、复杂数据类型
- 存储空间分为:栈内存空间、堆内存空间
- 栈内存空间:存储基本数据类型的变量以及变量值, 复杂数据类型的变量名,变量名字的值是复杂数据类型在堆内存中的一个地址
- 堆内存空间:存储复杂数据类型的值
所以:就算对象值是一样的变量的名字不一样,两个地址也是不一样的
数组
-
是js中的一个复杂数据类型(引用数据类型)
-
数组:一个有序的数据集合
-
数组中的每一个元素(数据) 都有对应的
序号也就是索引 -
索引是以0开始的连续自然数
-
使用符号: [ ]
例:arr=[1,"111","你好",true,null]
数组里面的内容:
之间使用逗号分割 数值、布尔值不需要带引号,字符串需要带引号
多维数组
-
数组可以存储任何数据类型
-
数组也可以存储数组
-
数组中是数组多层嵌套的我们称之为 多维数组
-
数组中嵌套数组两层,就是二维数组
var arr = [ ['江西', '广东'], ['南昌', '赣州', '吉安'], ['广州', '深圳', '东莞'] ];
声明数组
-
字面量创建(声明)数组:
var arr1 = [ ] //空数组-
声明并赋值:
var arr1 = [1, 2, 3, true] -
先声明,再赋值:
var arr1 = [] //空数组 arr1[0] = "乐乐" arr1[1] = 18
-
-
构造函数的方法创建(声明)数组:
var arr2 = new Array( ) //使用new创建,Array首字母必须大写-
Array 内置构造函数
var arr = new Array() 空数组 var arr = new Array(5) 得到一个长度为5的数组,但是每一个元素数据是empty
var arr = new Array(1,2,3,4,5) 得到一个有数据的数组
- 声明并赋值: ```javascript var arr2 = new Array("1","乐乐",18)-
先声明,再赋值:(一般实际开发的时候设置个数)
var arr2 = new Array() //括号中传入数组中的项目个数 arr2[0] = "乐乐"; arr2[1] = "18";
-
数组的特性
-
数组索引
-
索引都是从0开始的连续自然数
-
索引就是 数组元素对应的 序号,也叫做 下标
-
数组的索引属性,是可读可写的属性
-
读(获取)
语法: 数组[索引] 得到: 索引对应的 数组数据 如果索引对应位置没有数据,则返回 undefined -
写
语法: 数组[索引] = 值 如果 索引 和 数组的长度 一样,则添加了一个数组元素在数组的最后面 如果 索引 比 数组的长度 小,则就是覆盖式修改索引对应数据 如果 索引 比 数组的长度 大,则对应的索引添加数据,空出来的索引位置都用empty替代
-
-
数组的长度属性
-
这是一个可读可写的属性
-
数组的长度就是 数组元素的个数
-
读取
语法: 数组.length -
写
语法: 数组.length = 数字 如果数字 比原来 数组长度 更小, 则会删除多余的数组元素 如果数字 和原来 数组长度 一样, 则没有变化 如果数字 比原来 数组长度 更大, 则新的索引位置的都是empty -
数组长度和数组索引的关系
- 数组长度-1,就是数组索引的最大值
-
遍历
遍历:循环访问到每一个内容,专门用来遍历复杂数据类型(遍历数组,遍历对象)
-
遍历数组(循环打印数组中的每一项)
-
for方法:
for (var i = 0; i < arr.length; i++) { //i 代表的是下标 console.log(arr[i]) } -
for in方法:
//循环次数为:arr.length,数组的长度 for(var i in arr){ //通过for in方法在arr中进行数据的遍历,i当做的是下标 console.log(arr[i]) }
-
-
遍历对象
-
for方法:
对象不是纯数值的下标,所以for循环不能使用
-
for in方法:
//使用for in方法循环遍历obj对象,i当做的是下标索引 for (var i in obj) { console.log(i); //获取到的是键 console.log(obj[i]); }
-
数组的常用操作方法
1、push-向数组尾部添加数据
数组.push(参数)
作用: 将参数追加到数组的末位--追加数组元素
返回值: 返回追加元素后数组的 长度
注意: 会改变原数组
2、pop-删除数组尾部一项数据
数组.pop()
作用: 将数组的最后一个元素删除
返回值: 返回删除的元素
注意: 会改变原数组
3、unshift-向数组头部添加数据
数组.unshift(参数)
作用: 将参数添加到数组的最前面--添加数组元素
返回值: 返回添加元素后数组的 长度
注意: 会改变原数组
4、shift-删除数组头部一项数据
数组.shift()
作用: 将数组的第一个元素删除
返回值: 返回删除的元素
注意: 会改变原数组
5、reverse-数组的反转
数组.reverse()
作用: 数组元素位置反转
返回值: 是反转后的数组
注意:会改变原数组
6、splice-数组的删除、截取
数组.splice(参数1,参数2,参数3)
语法1: 数组.splice(起始索引,个数)
作用: 从 起始下标开始删除数组中的多个(传入的个数)元素,将删除的元素组成一个新的数组返回
语法2: 数组.splice(起始索引,个数,在删除的开始位置添加的元素...)
作用: 从 起始下标开始删除数组中的多个(传入的个数)元素,将删除的元素组成一个新的数组返回,并从第三个参数开始作为数组的新元素从删除位置开始写入原数组
参数1:起始下标
参数2:截取删除的个数
如果第二个参数不传,则默认删除从起始索引开始到最后一个元素
参数3:被替换的内容(可不写)
如果参数3没有参数,则只对数组删除,不进行添加新内容
如果参数3有参数,则会在删除的基础上,添加替换新的内容
有参数3,不一定是删除;不一定删除多少个就得添加多少个
注意:如果参数2为0,代表不删除,添加替换的内容的下标为起始下标
返回值: 返回一个新数组
改变原数组
7、sort-排序方法
数组.sort()
作用: 数组元素排序,如果数组元素都是数字,或数字字符串,则按位比较大小排序
如果不是数组的话,按照Unicode编码排序
返回值: 排序完成的数组
会改变原数组
升序:
arr.sort(function(a,b){
return a - b;
})
参数必须是一个函数,函数要有两个形参,且函数返回两个形参的差值
返回值: 排序完成的数组
会改变原数组
降序:
arr.sort(function(a,b){
return b - a;
})
参数必须是一个函数,函数要有两个形参,且函数返回两个形参的差值
返回值: 排序完成的数组
会改变原数组
8、fill-填充数组
数组.fill(要填充的数据,起始索引,结束索引)
作用: 填充数组, 从开始索引到结束索引填充数据
如果不写起始索引,则从[0]开始
如果不写结束索引,则到最后结束
特点: 填充的时候,包前不包后(包含前面的索引,不包含后面的索引)
会改变原数组
9、flat-拍平数组(多维数组)
数组.flat(参数)
作用:拍平数组(多维数组)
如果传入的参数是数字,参数是几就拍平几层的数组
如果传入的是Infinitiy 则拍平所有层级
返回值: 拍平后的数组
不会改变原数组
10、find-查找返回符合条件的第一个元素
数组.find(function(item,index,arr){回调函数})
作用: 查找数组中符合条件的第一个元素并返回
条件在回调函数中以 return的形式书写
返回值: 符合条件的元素,如果没有则是undefined
不会改变原数组
例:var res = arr.find(function (a,b,c) {
return a > 7;
})
11、查找返回符合条件的第一个元素索引
数组.findIndex(function(item,index,arr){回调函数})
作用: 查找数组中符合条件的第一个元素的索引并返回
条件在回调函数中以 return的形式书写
返回值: 符合条件的元素索引,如果没有则是返回值 -1
不会改变原数组
例:var res = arr.findIndex(function (a,b,c) {
return a > 7;
})
12、reduce-数组累加方法
数组.reduce(function(prev,item,index,arr){ 回调函数 },初始值)
作用: 数组累计方法
1、如果没有传入初始值:
1) 第一次执行回调函数的时候, prev就是数组的第一个元素,item是数组的第二个元素,index就是item的索引,arr就是原数组
2) 第二次之后执行回调函数的时候,prev就是上一次函数执行的返回值return的结果, item就是当前循环执行的数组元素,index就是item的索引,arr就是原数组
2、如果有传入初始值:
1) 第一次执行回调函数的时候, prev就是初始值,item是数组的第一个元素,index就是item的索引,arr就是原数组
2) 第二次之后执行回调函数的时候,prev就是上一次函数执行的返回值就是return的结果, item就是当前循环执行的数组元素,index就是item的索引,arr就是原数组
回调函数最后一次执行的返回值,就是return的内容,就是reduce方法的返回值
例:var res = arr.reduce(function (prev, item, index, arr) {
return prev + item;
}, 0)
13、slice-截取数组
数组.slice(起始索引,结束索引)
参数:(起始索引,结束索引)包前不包后,可以传负数
作用: 根据起始和结束索引,截取数组中的元素组成新数组返回
返回值: 一个截取的新数组
不会改变原数组
14、join-数组转字符串
数组.join(参数)
如果参数不传递,则默认使用逗号拼接
作用: 函数中元素拼接,按照传入的参数拼接为字符串
返回值: 拼接好的字符串
不会改变原数组
例:
var arr= [1,2,2,3,4] arr.jojn() ==> 1,2,2,3,4 字符串
var arr= [1,2,2,3,4] arr.join('-') ==> 1-2-2-3-4 字符串
15、concat-合并数组
数组.concat(数组,数据....)
会将传入的参数和原始数组中的数据合并在一个新的数组中,如果参数是数组,则会将数组中的元素合并在新数组中
作用: 合并数组
返回值: 合并后的新数组
不会改变原数组
16、indexOf-查找第一次出现的索引
数组.indexOf(参数,起始索引)
如果没有传参数2:
从[0]开始 查找参数在数组中第一次出现的索引,如果不存在返回-1
如果有传参数2:
从[起始索引]]开始 查找参数在数组中第一次出现的索引,如果不存在返回-1
返回值: 索引或-1
17、lastIndexOf-反向查找第一次出现的索引
数组.lastIndexOf(参数,起始索引)
如果没有传参数2:
从后往前开始 查找参数在数组中第一次出现的索引,如果不存在返回-1
如果有传参数2:
从[起始索引]开始往前 查找参数在数组中第一次出现的索引,如果不存在返回-1
返回值: 索引或-1
18、forEach-数组遍历方法
数组.forEach(funciton(item,index,arr){ 回调函数 })
数组有多个元素,回到函数执行多少次
参数1:循环中数组的每一个元素
参数2:循环中每个元素对应数组索引
参数3:调用方法的原数组
作用: 遍历数组
返回值: 没有返回值--undefined
forEach方法重构:
function myForEach(cb) {
for (var i = 0; i < this.length; i++) {
cb(this[i],i,this)
}
}
var arr1 = ['a', 'b', 'c', 'd'];
Array.prototype.myForEach = myForEach;
arr1.myForEach(function b(item,index,arr) {
console.log( item,index,arr );
})
19、map-数组映射方法
数组.map(function(item,index,arr){ 回调函数 })
参数1:循环中数组的每一个元素
参数2:循环中每个元素对应数组索引
参数3:调用方法的原数组
映射操作 需要写在函数内的 return 后
作用: 将数组的每一个元素通过映射操作为新数组的元素
返回值: 和原数组长度一样的新数组
新数组的元素,都是通过映射操作后的数据
不会改变原数组
map方法重构:
Array.prototype.myMap = myMap;
function myMap(cb) {
var ary = [];
for (var i = 0; i < this.length; i++) {
var res = cb(this[i], i, this);
ary.push(res);
}
return ary;
}
var arr = [100, 200, 300, 400, 500];
var newArr = arr.myMap(function (v, i, ar) {
return v + 10;
})
console.log(newArr);
20、filter-数组过滤
数组.filter(function(item,index,arr){ 回调函数 })
参数1:循环中数组的每一个元素
参数2:循环中每个元素对应数组索引
参数3:调用方法的原数组
过滤操作的过滤条件 需要写在函数内的 return 后
作用: 根据过滤条件 将满足条件的元素数据,组成新的数组并返回
返回值: 返回一个新数组,新数组中的元素都是满足过滤条件的数据
不会影响原数组
filter方法重构:
Array.prototype.myFilter = function (cb) {
var ary = [];
for (var i = 0; i < this.length; i++) {
var r = cb(this[i], i, this);
r && ary.push(this[i]);
}
return ary;
}
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var newArr = arr.myFilter(function (v, i, ar) {
return v % 2 === 0;
})
console.log(newArr)
21、some/every-数组判断方法
-
some数组.some(function(item,index,ar){回调函数})如果 数组中 某一个元素满足条件 则返回 true 如果 数组中 所有元素都不满足条件 则返回 false 条件书写在回调函数的return 后; 如果 元素满足条件则循环结束 返回值: 布尔值some方法重构: Array.prototype.mySome = function (cb) { for (var i = 0; i < this.length; i++) { var r = cb(this[i], i, this); if (r) return true; } return false; } var arr = [1, 2, 3, 4, 5]; var res = arr.mySome(function (k) { console.log(k) return k > 10; }) console.log(res) -
every数组.every(function(item,index,arr){回调函数})如果 数组中 所有元素都满足条件 则返回 true 如果 数组中 某一个元素不满足条件 则返回 false 条件书写在回调函数的return 后; 如果 元素不满足条件则循环结束 返回值: 布尔值every方法重构: Array.prototype.myEvery = function (cb) { for (var i = 0; i < this.length; i++) { var r = cb(this[i], i, this); if (!r) return false; } return true; } var arr = [1, 2, 3, 4, 5]; var res = arr.myEvery(function (k) { console.log(k); return k < 3; }) console.log(res);
22、includes是否包含
-
数组.includes(参数)作用: 查询数组是否包含参数 返回值: 布尔值
数组塌陷
-
遍历数组,通过splice删除数组元素,则会发生数组元素塌陷
-
因为删除了数组元素,则数组的索引和长度发生变化,所用遍历的时候会塌陷
-
解决方案1: 在splice删除元素后
i-- -
解决方案2: 倒序遍历删除
var arr = [1, 2, 5, 5, 5, 6, 7]; // 要求删除数组中的所有5 //方案一: for (var i = 0; i < arr.length; i++) { if(arr[i]===5){ // 判断数组元素是否是5 arr.splice(i,1); i--; } } console.log( arr ) //方案二: for (var i = arr.length - 1; i >= 0; i--) { if (arr[i] === 5) { // 判断数组元素是否是5 arr.splice(i, 1); } } console.log(arr)
数组去重
- 方法一:
- 将arr数组中的元素逐个添加新数组中,如果该元素在新数组中存在则不添加
- 方法二:
- 将arr数组中的元素逐个添加新数组中,如果该元素在新数组中存在则不添加
- 使用数组方法
includes - 语法:
数组.includes(参数) - 作用: 判断参数在数组中是否存在
- 返回值:布尔值 true表示存在,false不存在
- 方法三:
- 将数组的元素当做对象的属性名使用,然后遍历对象,将属性名转为数组
- 因为对象的属性名是唯一的(不重复)
- 方法四:
- 使用
Set数据集合完成去重 - 伪数组转为真数组
- 将数组作为创建set集合的参数使用
- set数据集合最大的特点数里面的数据不能重复
- 语法:
Array.from(伪数组) - 返回真数组
- 使用
方法一:
var newArr = [arr[0]];
for (var i = 0; i < arr.length; i++) {
var flag = true; // 定义flag变量赋值为true,表示arr[i]在新数组中不存在
for (var j = 0; j < newArr.length; j++) {
if (arr[i] == newArr[j]) {
flag = false;
break;
}
}
if (flag == true) newArr.push(arr[i]);
}
console.log(newArr)
方案二:
var newArr = [arr[0]];
for (var i = 0; i < arr.length; i++) {
// 遍历新数组,判断arr[i]在数组中是否存在
if (!newArr.includes(arr[i])) newArr.push(arr[i]);
}
console.log( newArr )
方案三:
var obj = {};
for (var i = 0; i < arr.length; i++) {
// 将数组元素arr[i] 当做对象的属性名使用
// 当数组元素 找对象的属性名中第一次出现则作为属性名,且值为1
obj[arr[i]] = 1;
}
var newArr = [];
// 遍历对象,将属性名写到newArr中
for (var key in obj) {
newArr.push(key-0)
}
console.log( newArr )
方法四:
var s = new Set(arr);
// set数据也是一个伪数组集合
var newArr = Array.from(s);
console.log( newArr );
数组的注意事项
- 索引 都是 从0开始的自然数
- 数组长度 是数组元素的个数
- 数组长度
-1就是索引最值 - arr['66']=999 数字字符串会默认转为数值当做数组索引
- arr['六十六']=888 不会将'六十六'当做数组索引使用,而是当做属性名使用
- 数组长度
伪数组
-
和数组一样具有数组的 索引和长度特性
-
但是不能够使用数组方法
function fn(){ Array.from(arguments).forEach(function(){}) // arguments // 函数内的arguments--实参集合--伪数组 } -
将伪数组转为真数组
Array.from(伪数组)
冒泡排序
-
原理:
- 以数组为例,两两进行比较,前一位和后一位进行比较
- 如果前一位比后一位大,则二者进行交换,这一轮比较会实现最大值在最后
- 接着进行下一轮循环遍历,再次两两比较,两两交换,得到第二大的数值在倒数第二位
- 再进行下一轮循环遍历...
-
代码:
for (var j = 0; j < arr.length-1; j++) { //循环的次数 for (var i = 0; i < arr.length-1-j; i++) { //比较的次数 //判断:前面的一项是否大于后面的一项 //如果大于则进行交换,不大于则不交换 if (arr[i] > arr[i + 1]) { var a = arr[i]; //第三变量用于承接做交换 arr[i] = arr[i + 1]; arr[i + 1] = a; } } } //双重循环外侧打印arr console.log(arr)
选择排序
-
原理
- 先假定数组中的第 0 个就是最小的数字的索引
- 然后遍历数组,只要有一个数字比我小,那么就替换之前记录的索引
- 知道数组遍历结束后,就能找到最小的那个索引,然后让最小的索引换到第 0 个的位置
- 再来第二趟遍历,假定第 1 个是最小的数字的索引
- 在遍历一次数组,找到比我小的那个数字的索引
- 遍历结束后换个位置
- 依次类推,也可以把数组排序好
-
代码
for (var j = 0; j < arr.length - 1; j++) { var minIndex = j; //假设下标[j]就是最小值 for (var i = j + 1; i < arr.length; i++) { //遍历数组,逐个比较 if (arr[i] < arr[minIndex]) { //如果有更小的数据 minIndex = i; // 则将下标记录在minIndex中 } } //循环结束后,minIndex就是最小值的索引 //判断minIndex中和一开始假设的最小索引是否一致 if (minIndex !== j) { //如果不一致,则交换数据 var temp = arr[minIndex]; arr[minIndex] = arr[j]; arr[j] = temp; } }
计数排序
-
原理
将原数组中的数据当做新数组中的索引使用(数组索引的自动排序) 将新数组中的值 作为计数器(累计元素中相同元素的个数) 遍历新数组 将新数组中有值的索引 一次写入到原数组中 前提: 清空原数组 -
代码
var arr = [10, 20, 3, 5, 6, 1, 9, 3, 4, 5, 7] var newArr = []; // 遍历原数组,将数组中的数据作为newArr的索引 for (var i = 0; i < arr.length; i++) { // arr[i] 数组的数据 作为新数组的索引 // 值: 如果第一次出现则赋值为1,后续还有则累加 !newArr[arr[i]] ? newArr[arr[i]] = 1 : newArr[arr[i]]++; } // console.log( newArr ) // 清空原数组 arr.length = 0; // 遍历新数组,可将有值的索引 写入原数组 for (var j = 0; j < newArr.length; j++) { // 如果 该索引没有值,表示不是原数组中的数据,则结束本次循环,直接到下一次 if (!newArr[j]) continue; // 遍历(累计的次数),将索引写入原数组 for (var i = 0; i < newArr[j]; i++) arr.push(j); } console.log(arr)
插入排序
-
原理
1. 取一个数组元素,和之前的元素逐个比较,如果比他更小,则交换位置 2. 直到找到比这个元素大的,则将这个元素放到该元素后 -
代码
var arr = [3, 1, 5, 6, 4, 9, 7, 2, 8] // 1. 遍历数组 for (var i = 1; i < arr.length; i++) { // 2.将第i个元素存到临时变量中 var temp = arr[i]; // 3. 将arr[i] 依次和前面的所有数据比较 var j = i - 1;// j就是i前一个元素的所用 while (arr[j] > temp) { arr[j + 1] = arr[j] j--; } // 循环结束的时候,说明 arr[j]>temp 为fasle // 说明 arr[j]<temp,则将temp的值放到[j+1]的位置 arr[j + 1] = temp; } console.log(arr)
快速排序(递归二分法)
function quickSort(arr) {
// arr 形参接收到 一个乱序的数组
// 1. 先书写暂停条件
if (arr.length == 1 || arr.length == 0) return arr;
// 2. 获取数组的中间数
// 2.1 获取中间数的索引
var centerIndex = parseInt(arr.length / 2);
// 使用splice取出数组中间数-----注意 splice返回值是一个数组
var center = arr.splice(centerIndex, 1)[0];
// 3. 循环arr数组
var small = []; // 接受比中间数小的数据
var big = []; // 接受比中间数大的数据
for (var i = 0; i < arr.length; i++) {
arr[i] > center ? big.push(arr[i]) : small.push(arr[i]);
}
// 形成递进关系 small 和 big 也需要二分法排序
return [].concat(quickSort(small), center, quickSort(big));
}
var arr1 = [6, 1, 2, 9, 3, 5, 7, 4, 8]
// 调用函数 进行排序
console.log(quickSort(arr1))
回调函数
-
概念:
- 将函数a 作为函数b 的实参传递
- 在函数b内部,通过形参的方式调用函数a
- 此处我们 将函数a称之为 回调函数
function b(cb) { // cb 接收的就是全局函数a的地址 // cb() 就是调用了全局函数a cb(); } function a() { console.log('全局函数a') } // 变量a中存储的是一个函数地址 // 将这个作为实参传递到b函数内 b(a) -
回调函数作用
- 封装异步相关的内容
- 封装遍历相关的内容
例:利用回调函数仿写一个sort方法
function mySort(cb) {
var arr = [7, 5, 3, 1, 2, 4, 6];
// 使用冒泡排序
for (var k = 0; k < arr.length - 1; k++) {
for (let i = 0; i < arr.length - 1 - k; i++) {
// cb() 就是调用了 函数b
var res = cb(arr[i], arr[i + 1])
if (res >= 0) {
var temp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = temp;
}
}
}
console.log(arr)
}
function b(param1, param2) {
// return param1 - param2; // 升序
return param2 - param1; // 降序
}
mySort(b)
复杂数据类型的赋值
复杂数据类型赋值过程中赋值的是地址,
每一个变量都可以通过这个地址访问到该数据,
只要有一个与之相关的变量修改了对应的数据,其他变量再访问的也是修改后的结果
深浅拷贝
拷贝: 将一个变量中的数据赋值一份
一般我们说拷贝的时候,都是值对象或数组类型数据
拷贝分为三个等级:
赋值
就是将一个变量中的值赋值一份给到另一个变量
如果复杂数据类型则,两个变量操作同一个存储空间
浅拷贝
将对象中的第一层数据都 复制一份 赋值给另一个空对象
两个对象 中的第一层值都一样
for-in 遍历对象完成浅拷贝
通过 展开运算符 ... 实现浅拷贝
深拷贝
对象无论多少层 都将数据拷贝到新的对象中
拷贝完成后,无论怎么改变新对象中的数据 都不会影响原来的对象
函数中的赋值
- 实参为基本数据类型
- 赋值的是值,一个变量修改不影响其他变量
- 实参为复杂数据类型
- 赋值的是地址,一个变量的修改会影响其他变量
- 因为变量能通过地址访问到数据
this
this的英文含义:这是一个**,指代的是某一个东西 程序里是一个关键词,不是变量
- this在全局使用的时候代表的是:window
- this在局部使用的时候代表的是:
- 使用
函数名()进行调用,this始终代表的是window - 使用
对象.键名()进行调用,this代表的是当前对象
- 使用
- 事件函数中的this:
- this就代表的是触发事件函数的对象,也就是这个元素
严格模式
开启严格模式:在代码的最前方,输入字符串 'use strict'
严格模式状态下:
- 声明变量的时必须添加var
- 严格模式下,函数中没有this指向的问题
- 函数传递参数过程中的形参,不能使用相同的名字 使用相同的形参名字,只会保留最后一个的值
字符串
-
字符串在存储中是基本数据类型
-
在js中 字符串 包装数据类型
包装数据类型: 当字符串调用方法,访问数据的时候 会将基本数据类型的字符串,临时的转为复杂数据类型 当方法或属性使用完毕后,将字符串转为基本数据类型 包装数据类型是为了便于使用字符串 -
字符串创建
- 字面量创建
var str = 'qwert' - 内置构造函数创建**
var str = new String('qwert')**
- 字面量创建
-
字符串的索引属性
- 只读
- 语法: 字符串[索引]
- 作用: 通过索引找到字符串中对应的字符
- 字符串[索引] 就是将字符串是包装数据类型使用
-
字符串的长度属性
- 只读
- 语法:
字符串.length - 作用: 获取字符串中字符个数
-
遍历字符串
- 通过 for循环,索引当做循环变量 ,条件:索引<长度
按照字符串中存储的内容来进行适当的分类
普通字符串: 'qwert'
数字字符串: '12436'
html格式字符串: '<div></div>'
查询字符串: 'key1=value1&key2=value2..'
json格式字符串: '{"name":"zs","age":18}';
作用: 用于前后交互使用
字符串的常用方法
1、charAt()
字符串.charAt(索引)
作用: 在字符串中查找传入索引对应的字符
返回值: 索引对应的字符,如果索引不存在,则返回空字符串''
2、charCodeAt()
字符串.charCodeAt(索引)
作用: 在字符串中查找传入索引对应字符的编码
返回值: 传入索引对应的字符编码,如果索引不存在,则返回 NaN
3、toUpperCase()/toLowerCase()
-
所有字符大写
字符串.toUpperCase() -
所有字符小写
字符串.toLowserCase()
作用: 将字符串中的字母转为都转为小写
返回值: 转换后的字符串
4、substr()
字符串.substr(起始索引,截取个数)
作用: 截取字符串
返回值: 截取的字符串
5、substring()
字符串.substring(索引,索引)
会自动将大的索引当做结束索引
会自动将小的索引当做起始索引
包前不包后(不包含结束索引)
#注意如果不书写结束索引则是从开始索引到最后
作用: 截取字符串
返回值: 截取的字符串
6、slice()
字符串.slice(起始索引,结束索引)
包前不包后(不包含结束索引)
注意如果不书写结束索引则是从开始索引到最后
#结束索引可以使用负数,-1表示最后一个,-2倒数第二个,-3.....
作用: 截取字符串
返回值: 截取的字符串
7、indexOf()
-
语法1:
字符串.indexOf(字符片段) -
语法2:
字符串.indexOf(字符片段,起始索引)
语法1:
字符串.indexOf(字符片段)
作用: 从开头开始查找传入的字符片段 在原字符串中的位置,并返回索引,结束查找
返回值: 索引 或 -1 (在字符串中不存在)
语法2:
字符串.indexOf(字符片段,起始索引)
作用:从起始索引开始查找
返回值: 索引 或 -1 (在字符串中不存在)
8、lastIndexOf()
-
语法1:
字符串.lastIndexOf(字符片段) -
语法2:
字符串.lastIndexOf(字符片段,起始索引)
语法1:
字符串.lastIndexOf(字符片段)
作用: 从尾部开始往前查找传入的字符片段 在原字符串中的位置,并返回索引,结束查找
返回值: 索引 或 -1 (在字符串中不存在)
语法2:
字符串.lastIndexOf(字符片段,起始索引)
从起始索引开始往前查找
返回值: 索引 或 -1 (在字符串中不存在)
9、replace()
字符串.replace(替换下的字符片段,替换上的字符片段)
作用: 字符串替换
返回值: 替换后的字符串
10、search()
字符串.search(字符片段)
作用: 在原字符串中查找存入的字符片段,并返回索引 (只会从前往后查找)
返回值: 索引 或 -1(不存在)
11、trim()
字符串.trim()
作用: 清除字符串前后两边的空白字符
返回值: 清除空白后的字符串
12、trimLeft()/trimRight()
-
字符串.trimLeft() -
字符串.trimRight()
作用: 清除字符串左/右边空白字符
返回值: 清除空白后的字符串
13、split()
字符串.split(分隔符号)
如果不传参数或者传递的分隔符在原字符串中不存在,则将原字符串当做数字的一个元素返回
如果传入空字符串,则会将原字符串的每一个字符 都进行分隔,都作为数组的元素
作用: 按照传入的分隔符号,将字符串分割为多段,当做数组元素
返回值: 字符串分割后 组成的数组
14、startsWith()
字符串1.startsWith(字符串2)
作用:判断`字符串1`是否以`字符串2`开头
返回值:布尔值
15、endsWith()
字符串1.endsWith(字符串2)
作用:判断`字符串1`是否以`字符串2`结尾
返回值:布尔值
所有字符串方法都不能改变原字符串内容
Math
Math数学常用方法
1、random-生成0~1随机数
-
Math.random()生成一个随机数:0-1之间的随机数;包括0但不包括1
2、abs-绝对值方法
-
Math.abs(数字)作用: 取绝对值 返回值: 正数/ 0
3、max-一组数中的最大值
-
Math.max(一组数)Math.max(1,9,3,11) 传入的是一组数,不是一数组 一组数不能带引号,多个数字之间用逗号隔开 如果传入数组,则返回NaN 作用: 取多个数字中的最大值 返回值: 数字
4、min-一组数中的最小值
-
Math.min(一组数)Math.min(1,9,3,11) 传入的是一组数,不是一数组 一组数不能带引号,多个数字之间用逗号隔开 如果传入数组,则返回NaN 作用: 取多个数字中的最小值 返回值: 数字
5、ceil-向上取整
-
Math.ceil(数字)无论小数点后面是几都向前进1 作用: 对数字进行向上取整操作 返回值: 整数
6、floor-向下取整
-
Math.floor(你要操作的数字)无论小数点后面是几,直接把小数点后面的省略掉 作用: 对数字进行向下取整操作 返回值: 整数
7、round-四舍五入
-
Math.round(数字)满5进1 作用: 对数字进行四舍五入操作 返回值: 整数
8、pow-平方,次方
-
Math.pow(底数,指数)作用: 取底数的多少次幂(次方) 返回值: 数字
9、sqrt-开平方
-
Math.sqrt(数字)作用: 取数字的平方根 返回值: 数字
10、PI-π的值
-
Math.PI返回值:3.1415926...... 注意:PI是大写,后面没有小括号 作用: 获取圆周率
11、toFixed-保留几位小数
-
变量.toFixed(参数)保留小数点后几位,遵循四舍五入的原则
生成一个区间随机数
Math.floor(Math.random()*(max-min+1)+min)
例:生成3~15的区间随机数,含头含尾
Math.floor(Math.random()*(13)+3)
Date
Date时间对象
-
Date在js中是一个复杂数据类型
-
Date 是js内置的用于创建时间对象的 构造函数
-
一般创建的时间对象都是终端的时间为准(有时区)
-
创建时间对象
- 语法1:
new Date()
- 语法1:
-
返回当前的时间对象
-
语法2: new Date(参数)
1、参数是数值 1)只有一个数字参数 会将该数字当做时间戳来创建时间对象 时间戳: 格林尼治时间,1970年 1月1日0:0:0到某一个时刻的毫秒数 2)有两个以上的数字参数 YYYY 年份 MM 月份 0~11(0表示1月,11表示12) DD 日期 hh 小时 mm 分钟 ss 秒 注意: 数字超出范围会自动递进 2、参数是字符串: 一个时间格式的字符串 new Date('2022-07-21 09:50:00') new Date('2022/07/21 09:50:00') new Date('2022.07.21 09:50:00') 注意: 在字符串中的月份 1表示1月份
Date时间日期对象常用方法
- 获取当前的本地(客户端)时间:
var t = new Date()
- 设置将来时间:
var t = new Date("2022-05-01 00:00:00")var t = new Date(2022,04,01,00,00,00)
Date方法
-
就是操作时间对象的方法
-
主要有两套时间方法
get一套set一套
-
关键单词
FullYear 年份 Month 月份 Date 日期 Day 星期 Hours 小时 Minutes 分钟 Seconds 秒 Milliseconds 毫秒 Time 时间戳 UTC 世界时间 -
获取年份
t.getFullYear() -
获取月份
t.getMonth()返回值:0-11 -
获取日期
t.getDate() -
获取星期
t.getDay()0表示星期天 1表示星期一 6表示星期六 -
获取小时
t.getHours() -
获取分钟
t.getMinutes() -
获取秒
t.getSeconds() -
获取毫秒
t.getMilliseconds() -
获取时间戳
t.getTime() -
获取世界时间
t.getUTCHours() -
设置年份
t.setFullYear(2035) -
设置月份
t.setMonth(2)输入的参数:0表示1月,11表示12月 -
设置时间戳
t.setTime(20000000000)
js操作CSS样式
元素.style.CSS属性 = 值
**注意:**CSS属性如果是单一属性的话, 需要使用驼峰法转换
例:box.style.backgroundColor="yellow"
数字转换成进制
-
数字.toString(参数)参数: 2~36的数字, 表示将数字转为多少进制的字符串 不传参数则默认 转为十进制的数字字符串显示 作用: 将数字转为字符串(多少进制的字符串显示) 返回值: 字符串 -
变量.parseInt(参数1,参数2)参数1:要转换的内容 参数2:转换成的进制数 含义:(参数2)的(参数1)转成十进制显示 作用: 将字符串为十进制数字显示,将字符串当做几进制的数看待 返回值: 转换后的10进制数字,如果无法转换则为NaN
BOM
- BOM -- Browser Object Model 浏览器 对象 模型
- BOM操作 就是浏览器提供了的API来操作浏览器这个软件的相关内容
- 也就是说 BOM操作都是对象操作
- BOM中的顶级对象 是 window
- BOM操作 都可以省略 window.
- 全局中的 this和top关键字都是指向 window
- 在全局中通过var 关键字定义的变量或声明式定义的函数 默认是挂载在window对象上
- window对象中name是一个比较特殊的属性,name属性的值必须是字符串对象,设置别的类型会默认转为字符串类型
获取可视窗口大小
窗口大小包含滚动条
宽:width.innerWidth
高:window.innerHeight
BOM弹窗
-
提示框:
alert("弹出内容")表现: 提示信息 + 确定按钮 没有返回值 -
可输入的弹窗:
prompt(提示内容,默认值)参数1:提示语 参数2:输入框的默认值 表现: 提示信息 + 输入框 + 确定按钮 + 取消按钮 如果想要使用输入弹窗中的值需要使用一个变量去接收 返回值: 确定:返回内容(字符串类型) 取消:返回null 注意:输入框中获取的数据默认是字符串类型 -
确认取消框:
confirm("提示语")表现: 提示信息 + 确定按钮 + 取消按钮 返回值: 确认:true(真) 取消:false(假)
注意: 所有弹窗都会终止浏览器的渲染
浏览器的标签页
- 开启一个新的标签页
window.open(url)
open(url,窗口名,参数)
- 关闭当前标签页
window.close()
地址栏
- 浏览器访问页面的url
http://www.baidu.com:80/search/error.html?name=zs&age=18#123
http 超文本传输协议;https 安全的超文本传输协议
www.baidu.com 域名 一个域名对应了一个IP地址,一个IP地址就是远程服务器
80 是端口号,http默认80,https默认 443
/search/error.html 请求地址
name=zs&age=18 查询字符串 发起请求携带给请求地址的数据
#123 哈希字符串 页面(锚点)定位
{
hash: "#123"
host: "www.baidu.com"
hostname: "www.baidu.com"
href: "http://www.baidu.com/search/error.html?name=zs&age=18#123"
origin: "http://www.baidu.com"
pathname: "/search/error.html"
port: "" 端口
protocol: "http:"
search: "?name=zs&age=18"
}
location
-
如何获取到浏览器的地址?
-
window中有一个属性location,是一个对象
-
href属性-获取设置地址
可以获取设置浏览器的地址栏 获取: location.href 设置: location.href = 地址 设置浏览器的地址栏,页面会自动刷新请新的地址 -
reload 方法-刷新浏览器
可以刷新浏览器 location.reload() 注意: 不要写在全局中 -
直接给 location赋值也可刷新页面请求新的地址
location = 地址 -
assign 刷新页面请求新地址
-
history历史记录
history是window中的一个对象
histoty对象中默认会存在一个length属性:
在不同的浏览器中lentgh显示的数值不一样
谷歌浏览器和火狐浏览器里面默认的长度属性值为1
低版本的ie浏览器里面lentgh默认的取值为0
-
前进:
history.forward()
-
后退:
history.back()
-
前进后退 go方法:
history.go(参数)- 参数>0表示前进
- 参数<0表示后退
- 参数==0刷新当前页面
- 参数==2代表前进两个页面
浏览器对象
window下有一个navigator属性
这个属性对象中存储了浏览器的信息
load加载事件
在页面所有资源加载完毕后执行
基本语法:
window.onload = function(){
执行的js代码片段
}
应用位置:
1)head标签内部
2)</body>位置的前面
位置不同实现的作用都是一样的:让页面所有资源(页面结构,css,js,图片..)加载完毕之后,再去执行load事件函数
注意:
如果将js代码放在</body>的前面的话,window.onload可以不添加,直接写js代码即可,因为代码自上而下运行
如果在头部(head标签)获取元素,并且进行修饰的话,则需要在头部添加window.onload方法
给script标签添加defer="defer",defer代表延迟加载
scroll滚动事件
当浏览器的滚动条发生滚动的时候,触发对应的事件函数,执行代码片段
基本语法:
window.onscroll=function(){代码片段}
-
获取浏览器卷去的距离:
获取方法: 没有!doctype: document.body.scrollTop document.body.scrollLeft 有!doctype: document.documentElement.scrollTop document.documentElement.scrollLeft IE浏览器中没有!doctype的时候,两个方法都行 谷歌浏览器中没有!doctype的时候,使用(短的方法)document.body.scrollTop 谷歌浏览器中有!doctype的时候,使用(长的方法)document.documentElement.scrollTop 同时兼容: var aa= 长的方法 || 短的方法 scroll还能使用scrollLeft(左右滚动)
resize窗口变化事件
当浏览器的页面大小发生变化的时候,触发对应的事件函数,执行代码片段
基本语法:
window.onresize=function(){
代码片段
}
设置页面滚动到某个位置
-
通过给scrollTop/scrollLeft赋值
-
没有DOCTYPE声明
document.body.scrollTop = 值 document.body.scrollLeft = 值 -
有DOCTYPE声明
document.documentElement.scrollTop = 值 document.documentElement.scrollLeft = 值 -
注意: 瞬间到达目标位置
-
-
通过scrollTo() 方法
window.scrollTo(参数)- 参数是一个对象
- 对象中有top属性和left属性
- 是瞬间到达,可以添加参数对象属性
- ehavior,默认值为instant 就是瞬间到达
- 可以选参数 smooth 可以平滑到达目标位置
window.scrollTo(水平坐标, 垂直坐标)
例: window.scrollTo(100, 200)
例: window.scrollTo({top: 200,left: 100,behavior: "smooth"})
behavior: "smooth" 匀速
定时器
- 一次性定时器
setTimeout(function(){执行代码},2000,实参1...)- 表示2000毫秒==2秒后执行代码
- 只执行一次程序
- 第三个参数开始往后的参数,都是函数执行的实参
- 周期性定时器
setInterval(function(){执行代码},3000,实参1...)- 每隔多长时间让程序执行一次,会反复执行
- 第三个参数开始往后的参数,都是函数执行的实参
定时器的返回值:
与页面中定时器的个数有关系(返回第几个定时器),可用于关闭定时器
往往实际开发的时候,定时器使用完毕之后,降低内存消耗
把定时器函数的返回值清空掉tim1=null
定时器函数的执行顺序:
所有的定时器函数中的内容,都是等待主程序跑完之后,再执行(异步执行)
- 清空定时器
- 清空一次性定时器:
clearTimeout() - 清空周期性定时器:
clearInterval()
- 清空一次性定时器:
一般情况下,两种清空定时器方法,建议一一对应使用,但可以混用
DOM
- DOM ---- Document Object Model 文档对象模型
- 在DOM操作中 docuemnt是DOM中的顶级对象
- DOM 操作 就是操作浏览器的文档流内容
- DOM操作 基本都是操作页面元素(标签)
- 页面元素的 增删改查
- 页面元素的属性操作(id type class...)
- 页面元素的样式
- 页面元素的内容
- .....
- DOM中一些特殊的元素
- document 文档流 承载了页面所有内容,也是window对象的一个属性
- html 页面根元素节点 页面中最大的标签
- head 头部元素标签, 此标签中的内容一般都是对页面的设置
- body 页面中显示的内容都是在这个标签中的
标签属性分类
- 原生属性
- 在W3C规范中有的属性名
- 比如: id、class、style、type、src、href、checked....
- 自定义属性
- 在W3C规范中没有的属性名,是我们自己书写在标签上的
- H5自定义属性
- 目的: 就是为了区分和原生属性在标签上的形式
- 要求: 书写H5 自定义属性的时候,都得以
data-开头 - 比如:
data-index=666data-表示这个就是 H5自定义属性index表示属性名'666'表示属性值
操作元素的样式
- 标签属性:
元素.HTML自身属性 - CSS样式:
元素.style.CSS样式名
通过js操作的CSS属性都是属于行内样式,获取的样式也是操作后的行内样式
-
获取内部、外部样式表中样式(包含了行内和非行内样式):
-
非IE浏览器:
window.getComputedStyle(元素).样式名
window.getComputedStyle(元素)['样式名']- computed:计算属性,里面存储的是该元素能设置的所有的属性
-
IE浏览器(IE8及以下):
元素.currentStyle.样式名
元素.currentStyle['样式名']
-
#注意: 涉及到带中划线的样式名的时候
#转为驼峰写法: ele.style.backgroundColor
#使用数组关联法: ele.style['background-color']
输入、获取页面标签中的内容
-
元素.innerHTML可读可写 获取(读): 如果标签内的内容为代码片段,使用该方法,会将代码片段获取到 如果标签内没有代码只有文本,则会把文本获取到 设置(写): 元素.innerHTML="赋值" 赋值的时候,如果你元素中有内容,则新内容会将原内容覆盖 如果新赋值的内容,是代码片段,则会被运行,不是代码片段则不影响 作用: 完全覆盖式的书写标签的超文本内容 注意: 可以识别解析 html格式字符串 -
元素.innerText只能获取标签中的文本 可读可写 获取(读): 无论标签中是否有代码,或者只有文本,只能获取到文本 设置(写): 元素.innerText="赋值" 作用: 完全覆盖式的书写标签文本内容 注意: 没有办法识别解析 html格式字符串 -
表单元素.value这是表单标签的原生属性操作 可读可写 获取(读): 表单元素.value 得到: 该标签元素的value值 设置(写): 表单元素.value = '值' 作用: 设置标签元素的value值
操作元素的类名
-
目的: 批量的修改元素的样式
-
className
元素.属性名
其实就是原生属性操作 因为 js中有一个关键字 calss,为了避开改名叫做 className 注意: 类名的值 是字符串,可能是多个类名一起的 -
classList
每一个元素身上都有一个属性叫 classList 该属性对应的值是一个类似于数组的数据结构,方法是该元素的所有类名 类名的增删改查 都是对元素的classList操作的,有专门的方法 方法: 增: 元素.classList.add(类名) 删: 元素.classList.remove(类名) 切换: 元素.classList.toggle(类名) 原来元素有该类名则删除,没有则添加
获取页面中的元素
-
通过元素id名获取
document.getElementById("id属性值")document----页面文档 get---------得到 Element-----元素 By----------通过某种方式 Id----------id的名字获取元素 返回值: 返回 页面中id属性和传入的id值一致的第一个标签元素 如果页面中没有 传入的id属性值的标签, 则返回null 特殊情况:如果给元素添加了id属性,id属性值就代表了这个元素 -
通过元素class名获取
document.getElementsByClassName("class名")返回值: 返回 页面中 具有传入类名的 所有那标签元素组成的一个伪数组 如果页面中没有 具有传入类名的标签元素, 则返回空的伪数组 想要访问对应的元素,则需要使用下标 -
通过元素的标签名获取
document.getElementsByTagName("标签名")返回值: 返回 页面中所有对应相同标签名的页面元素元素组成的一个伪数组 如果页面中没有 没有对应的标签, 则返回空的伪数组 访问则需要使用下标 -
通过元素的name属性获取
document.getElemntsByName("name属性值")应用在:获取表单元素中 返回的是一个类数组,访问需使用下标
获取页面中的元素-选择器方法
- 方法1:
document.querySelector("选择器")- 只会取一个元素
- 返回值:
- 返回 页面中 第一个满足选择器的标签元素
- 如果选择器 没有选中页面元素 返回null
- 方法2:
document.querySelectorAll("选择器")- 返回的是一个类数组,访问内容需要使用下标
- 返回值
- 返回 页面中 所有满足选择器的标签元素 组成的伪数组
- 如果选择器 没有选中页面元素 返回空的伪数组
- 通过此方法获取页面元素返回的伪数组 实现了
forEach遍历方法 - 此方法和数组的forEach遍历方法用法一致
- 注意: 选择器一定要带符号 .box #box ul>li
获取元素尺寸
-
第一套语法:
元素.offsetWidth (内容 + padding + border 区域的宽度) 元素.offsetHeight (内容 + padding + border 区域的高度) -
第二套语法:
元素.clientWidth (内容 + padding 区域的宽度) 元素.clientHeight (内容 + padding 区域的高度)
获取元素的偏移量
-
获取元素的偏移参考元素
元素.offsetParent得到: 该元素的偏移量参考父级 就是该元素的定位父级 如果到body都没有定位父级,那么这里的offsetParent就是body -
第一套语法
元素.offsetLeft 获取元素相对于offsetParent(定位父级) 的左侧距离 元素.offsetTop 获取元素相对于offsetParent(定位父级) 的上方距离 -
第二套语法
元素.clientLeft 获取元素(内容+padding区域) 相对于该元素border左边的尺寸 就是左边框的宽度 元素.clientTop 获取元素(内容+padding区域) 相对于该元素border上边的尺寸 就是上边框的宽度
-
元素.offsetWidth计算的是元素的内容,内边距和边框的实际距离 -
元素.offsetHeight计算的是元素的内容,内边距和边框的实际距离
获取可视窗口的尺寸
- DOM级别获取: 不包含滚动条
document.documentElement.clientWidthdocument.documentElement.clientHeight
获取和修改标签自身的属性
元素.属性获取属性的值元素.属性=值修改属性对应值
获取和设置HTML标签属性
元素.attributes- 返回一个存储所有属性的对象
元素.attributes.id- 返回标签中的id属性和属性值
元素.attributes[0]- 也可以使用数组下标的方法访问对应的内容
获取和设置HTML标签属性的值
-
元素.getAttribute("属性名")作用:直接获取到HTML标签属性的值 get---------得到 Attribute---一个属性 -
元素.setAttribute("参数1","参数2")作用:修改对应的属性的值 参数1:对应的属性名 参数2:更换后的属性值 注意:如果参数2没有值,代表的清空属性的值
删除属性
-
元素.removetAttribute("属性名")获取到元素才能删除 经常应用在选项卡切换的过程中
获取节点
节点:页面进行渲染的时候,都是将所有的标签、文本、属性、注释,都当做一个DOM树进行加载渲染
-
节点的分类:
- 元素节点
- 文本节点
- 空节点
- 属性节点
- 注释节点
-
获取非常规元素节点
html: document.documentELement head: document.head body: document.body -
获取常规元素节点
document.getElementById() document.getElementsByClassName() document.getElementsByTagName() document.querySelector() document.querySelectorAll()
-
获取元素里面所有的节点
父节点.childNodes得到: 该父节点下的所有子一级节点 -
*获取元素内部的所有元素节点
父节点.children得到: 该父节点下的所有子一级元素节点 -
获取第一个子节点
父节点.firstChild得到: 该父节点下的第一个子节点 -
*获取第一个子元素节点
父节点.firstElementChild得到: 该父节点下的第一个子元素节点 -
获取最后一个子节点
父节点.lastChild得到: 该节点下的最后一个子节点 -
*获取最后一个子元素节点
父节点.lastElementChild得到: 该节点下的最后一个子元素节点 -
获取当前元素的后面一个兄弟节点
节点.nextSibling得到: 该节点的下一个兄弟节点 -
*获取当前元素的后面一个兄弟元素节点
节点.nextElementSibling得到: 该节点的下一个兄弟元素节点 -
获取当前元素的前面一个兄弟节点
节点.previousSibling得到: 该节点的上一个兄弟节点 -
*获取当前元素前面一个兄弟元素节点
节点.previousElementSibling得到: 该节点的上一个兄弟元素节点 -
获取当前元素的父节点
节点.parentNode得到: 该节点的父节点 -
获取当前元素的所有属性节点
节点.attributes得到: 该节点的所有属性节点,包括自定义的属性 -
获取该节点的父节点
节点.parentElemen得到: 该节点的父元素节点
节点属性
-
属性节点: 节点类型的一种
-
节点属性: 描述节点的信息
-
所有的节点都共有的内容,只是不同节点值不一样
-
节点类型
节点.nodeType返回值: 元素节点: 1 属性节点: 2 文本节点: 3 注释节点: 8 -
节点名字
节点.nodeName返回值: 元素节点: 大写的标签名 属性节点: 属性名 文本节点: #text 注释节点: #comment -
节点内容
节点.nodeValue返回值: 元素节点: null 属性节点: 属性值 文本节点: 返回文本内容 注释节点: 返回注释的内容
操作节点
创建节点
-
创建一个dom元素节点
document.createElement("标签名")返回值: 一个被创建的标签 -
创建一个文本节点
document.createTextNode("文本")返回值: 文本节点
追加节点
-
向后追加
父节点.appendChild(追加节点)作用: 将子节点插入到父节点内,并放在最后的位置 -
向前追加
父节点.insertBefore(参数1,参数2)参数1:追加节点 参数2:插入在哪一个子节点前面 作用: 将子节点插入到父节点内,并指定放在那个节点之前 -
注意:
节点输出的时候,只能使用追加,不能使用document.wirte(),不能使用innerHTML,因为节点是一个对象 创建一个元素节点只能使用一次,只能追加一次
删除节点
-
直接删除自身节点
节点.remove()作用: 把节点自己移除 -
删除某个元素节点
父节点.removeChild(子节点)作用: 把子节点从父节点中移除 例: ul.removeChild(ul.children[1])
替换节点
-
父元素节点.replaceChild(新节点,旧节点)作用: 在父节点内容,新节点 替换掉 旧节点
克隆节点
-
节点.cloneNode(布尔值)复制一模一样的节点 如果没有任何参数的话,则只克隆当前节点 取值为false的话,表示不克隆后代节点,则克隆当前节点 取值为true的话,表示克隆后代节点 ,则克隆当前节点及以内的所有节点
创建文档碎片
document.createDocumentFragment();
字符串的拼接
- 创建文档碎片
- 语法:
document.createDocumentFragment()
- 语法:
将数据拼接到表格
例:var arr = [
{name: "Jack",age: 18,gender: "男",},
{name: "Rose",age: 20,gender: "女",},
{name: "Top",age: 22,gender: "男",},
{name: "申帅",age: 18,gender: "未知",},
{name: "静雅",age: 16,gender: "女",}
]
[for方法]
var str = "<table>";
for (var i = 1; i <= 3; i++) {
str += "<tr>";
for (var j = 1; j <= 3; j++) {
str += "<td>" + "234" + "</td>";
}
str += "</tr>";
}
str += "</table>";
document.write(str)
[for in方法]
var str = "<table>";
for (var i = 0; i < arr.length; i++) {
str += "<tr>";
for (var a in arr[i]) {
//console.log(arr[i])//对象
//console.log(a)//键
str += "<td>"+arr[i][a]+"</td>";
}
str += "</tr>";
}
str += "</table>";
document.write(str);
事件
事件:需要通过鼠标、键盘、滚动等一系列行为才能实现的效果,这种触发效果称之为事件
事件的组成部分:
1)事件对象:触发事件的事件源
2)事件类型:触发事件的事件类型,click、scroll
3)触发事件执行的事件函数
例:div.onclick=function(){}
div 事件源
on 添加、绑定
click 事件类型
function(){} 事件函数
[提示]循环绑定单击事件定义变量用let
鼠标事件
-
单机事件
元素.onclick = function(){}点击一次,鼠标按下,鼠标抬起,形成一次单机 -
双击事件
元素.ondblclick = function(){}连续点击鼠标两次 -
鼠标按下事件
元素.onmousedown = function(){}按下的那一瞬间触发事件函数 -
鼠标抬起事件
元素.onmouseup = function(){}松开鼠标的那一瞬间触发事件函数 -
鼠标移动事件
元素.onmousemove = function(){}当鼠标移动的时候触发事件函数 -
鼠标移入移出事件
-
第一对
mouseover鼠标进入mouseout鼠标离开如果是父子元素的话,鼠标移入到子元素的时候,会再一次触发事件函数 有事件冒泡 -
第二对
mouseenter鼠标进入mouseleave鼠标离开如果是父子元素的话,鼠标移入到子元素的时候,不会再次触发事件函数 有事件捕获 #注意:此对事件天生获取不到事件目标
-
-
右击事件
元素.oncontextmenu = function(){} -
鼠标滚动事件
wheel向下滚动 e.deltaY>0 向上滚动 e.deltaY<0
键盘事件
-
键盘按下抬起事件keypress
元素.onkeypress=function(){}输入框输入的时候,执行对应的事件函数 如果一直按着不放的话,则会一直触发事件函数 不是实时获取输入框中的值,因为第一次按下的时候触发了,获取的是空 只有数字和字母,和部分的符号键可以触发 上下左右,回车,tab,ctrl都不会触发 注意:获取的字母按键的编码区分大小写 -
键盘按下事件keydown
元素.onkeydown=function(){}按下的那一瞬间触发 获取值的时候,也会轮空一轮 能支持键盘上的所有按键 注意:获取的字母按键的编码不区分大小写 -
键盘抬起事件keyup
元素.onkeyup=function(){}松开键盘的那一瞬间触发 获取值不会轮空,获取实时的值 支持大部分的键盘摁键
UI表单事件
-
focus获取焦点事件
元素.onfocus=function(){}获取到焦点的那一瞬间,触发事件 -
blur失去焦点事件
元素.onblur=function(){}失去焦点的那一瞬间,触发事件 -
input修改值事件(输入事件)
元素.oninput=function(){}每修改一次值的时候,触发事件 一般用于输入框 -
change修改值并失去焦点事件(改变事件)
元素.onchange=function(){}修改值,并失去焦点的时候,触发事件 一般用于select,input=file -
submit提交事件
onsubmit="return true"可以提交 onsubmit="return false"不可提交 需要绑定给form标签 当点击submit按钮的时候,会触发form标签的默认提交 -
reset重置事件
需要绑定给form标签 当点击reset按钮的时候,会触发form标签的默认重置行为 页面会刷新
浏览器事件
加载事件:load
window.onload = function(){}
滚动事件:scroll
window.onscroll = function(){}
页面大小改变事件:resize
window.onresize=function(){}
触摸事件
- 专门用于触摸屏幕设备
touchstart触摸开始touchmove触摸移动touchend触摸结束
其他事件
selectstart选中开始visibilitychange切换页面- document有一个属性**
visibilityState** 可视状态- 值为**
visible** 标识课件 - 值为**
hidden** 标识不可见
- 值为**
- document有一个属性**
拖曳事件
至少需要三个事件组合完成:鼠标按下事件、鼠标移动事件、鼠标抬起事件
关系:鼠标按下的时候才能拖动,移动事件需要在按下事件里面
抬起鼠标的时候,不在移动,直接让移动事件函数为空(页面的鼠标移动事件解绑)
事件绑定
-
绑定事件的基本方法(DOM 0级别):
事件源.on事件类型=事件处理函数元素.onclick=function(){}- **弊端:**如果绑定多个相同的单击事件,后面的事件把前面的事件覆盖掉了,两个事件不能同时执行
- 特点: 同一个事件源的同一个事件类型只能绑定一个事件处理函数
-
DOM 2级别使用事件监听的方法:
非IE浏览器(标准浏览器): 元素.addEventListener("参数1",参数2,参数3) 元素 绑定事件的目标 add 添加 Event 事件 Listener 监听 参数1:事件类型,没有on,只有事件名 参数2:事件函数function(){} 参数3:冒泡还是捕获,事件触发的行为机制,要不要均可 true/false 捕获/冒泡 [小健]特点: 同一个事件源的同一个事件类型可以绑定多个事件处理函数,按照绑定顺序执行 这种绑定方式,解决多个相同事件同时被覆盖的问题:顺序绑定,顺序执行 IE浏览器(低版本IE): 元素.attachEvent("参数1",参数2) 元素 绑定事件的目标 attach 添加、绑定 Event 事件 参数1 事件类型,事件类型需要带on 参数2 事件函数function(){} 注意:IE浏览器里面只支持冒泡,不支持捕获 注意:IE11不支持该方法 在IE10,IE9里面是顺序绑定,顺序执行 但是在IE8以下顺序绑定倒叙执行 [小健]特点: 同一个事件源的同一个事件类型可以绑定多个事件处理函数,按照绑定顺序倒序执行
事件解绑
-
DOM 0级 事件解绑
- 语法:
事件源.on事件类型 = null
因为 "=" 赋值符号 覆盖的原因,就可以实现解绑 - 语法:
-
DOM 2级 事件解绑 - 标准浏览器
- 语法:
事件源.removeEventListener('事件类型',解绑的事件函数)
注意: 2级事件,如果你要解绑,那么在绑定的时候,需要把函数单独书写,以函数名的形式绑定 - 语法:
-
DOM 2级 事件解绑 - 低版本IE
- 语法:
事件源.detachEvent('on事件类型',解绑的事件函数)
注意: 2级事件,如果你要解绑,那么在绑定的时候,需要把函数单独书写,以函数名的形式绑定 - 语法:
事件对象
事件对象--Event
触发事件函数的同时,对于这个事件的一个描述
比如,点击这个盒子的时候,点击的是什么位置,坐标等等这些都是事件对象中的内容
鼠标事件对象跟键盘事件对象一样,只不过在不同的事件中e代表的内容不一样
获取触发的事件对象:
标准浏览器:
直接在事件处理函数位置接受一个形参,形参就是事件对象
会在事件触发的时候,浏览器自动传递的实参
低版本IE:
在事件处理函数内,通过window.event获取
获取对象中的值:
window.event.键(属性)
e.键(属性)
例:console.log(window.event)、console.log(window.event.x)、console.log(window.event.y)
兼容问题:
可以直接通过函数传递参数的方法去获取事件对象
例:
box.onclick=function(e){ //形参e代表了事件对象,e是event的简写,方便理解
//兼容
e = e || window.event
console.log(e)
}
事件对象.type 就可以获取到本次事件的事件类型
键盘事件对象:
e打印的结果:
KeyboardEvent {isTrusted: true, key: '1', code: 'Digit1', location: 0, ctrlKey: false, …}
keyboard 键盘
event 事件
{ } 对象
事件对象中必须知道的几个属性:
key "1/空格/enter/control" 代表的是按下的哪一个键
keyCode "键盘按键的键码"
向左:37,向上:38,向右:39,向下:40,回车:13
target 触发事件函数的目标
type 事件类型
currentTarget 事件绑定对象
获取键码:
语法:事件对象.keyCode
考虑键码获取的兼容性的问题:
语法:事件对象.keyCode || 事件对象.which (兼容火狐浏览器)
得到: 一个编码,每一个按键有的一个自主的独立编码(Unicode)
#注意:
keydown事件对象获取的字母按键的编码不区分大小写
keypress事件对象获取的字母按键的编码区分大小写
鼠标坐标信息
获取事件对象中的内容
-
事件对象.offsetX,事件对象.offsetY鼠标在元素内部的坐标位置 边框里面的位置,不包括边框,包括内边距的位置 不受滚动条的影响 鼠标光标相对于 事件目标 左上角的坐标位置 console.log(e.offsetX) -
事件对象.clientX,事件对象.clientY鼠标距离浏览器可视窗口的坐标 不受滚动条的影响 始终都是鼠标落点与浏览器左上角之间的距离 -
事件对象.screenX,事件对象.screenY鼠标落点,距离显示器左上角的坐标位置 -
pageX,pageY距离左上角body(文档流)的坐标位置 页面就算有滚动条,始终都是计算鼠标落点与左上角body的坐标位置
鼠标按键信息按键
事件对象.button
返回值:
0 (左键)
1 (滚轮键)
2 (右键)
组合键
组合键一般需要配合键盘上面的ctrl,alt,shift等这些键一起使用
事件对象中为我们提供了三个属性,用来检测组合键
事件对象.ctrlKey
事件对象.altKey
事件对象.shiftKey
事件对象.metaKey (win: win键,mac:command)
使用的时候必须配合这三个键来使用
以上四个按键的值都是布尔值: true表示按下,false表示没有按下
例:
ipt.onkeyup = function (e) {
if (e.keyCode == 13 && e.ctrlKey && e.altKey) {
console.log(this.value);
}
}
事件抛发(自定义事件)
-
之前的事件绑定中,绑定的事件类型,都是浏览器已经有的
-
还有一个事件绑定的方式,可以给DOM元素绑定任意的自定义事件,就是
- 创建事件对象
- 语法:
var evt = new Event('自定义的事件类型');
- 语法:
- 绑定事件---事件绑定的方式和常见的事件绑定方式一样
- 语法:
事件源.addEventListener('自定义的事件类型',事件处理函数)
- 语法:
- 将绑定的事件 抛发----手动触发
- 语法:
事件源.dispatchEvent(事件对象)
- 语法:
例: // 1. 创建事件对象 var evt = new Event('hello'); // 2. 绑定自定义的hello事件 document.addEventListener('hello', function () { console.log('你好!') console.log(this) }) // 3. 事件抛发---手动触发事件 document.dispatchEvent(evt);DOM对象之可以绑定事件并事件抛发.由于DOM元素对象继承了EventTarget这个类 其实addEventListener,removeEventListener,dispatchEvent三个是EventTarget的方式 - 创建事件对象
事件目标
- 事件目标:当事件触发的时候,那个准确触发事件的元素
- 当你给一个元素绑定事件后
- 在该元素上触发行为,是可以触发事件处理函数
- 在该元素的后代元素身上触发行为,也可以触发事件处理函数
- 获取事件目标
- 标准浏览器:
事件对象.target - 低版本IE:
事件对象.srcElement
- 标准浏览器:
- 注意: mouseenter和mouseleave 天生获取不到事件目标
事件传播(冒泡和捕获)
- 概念: 当用户在浏览器中触发指定行为的时候,会按照 结构父级 向上传递行为
- 从
事件目标开始,传递到 **window**为止- 事件目标->....-> bady -> html -> document -> window
- 在事件函数中,可以通过
事件对象.path获取到 事件目标开始的传播路径 - 在事件传播的过程中,任何浏览器都只能在一个阶段触发
- 在低版本IE中,只能在冒泡阶段触发事件,不能在捕获阶段触发事件
- 其他浏览器中,默认会在冒泡阶段触发事件,保留了在捕获阶段触发事件的能力
事件触发的时候,代码执行(事件传播)机制问题
主要是在非IE浏览器中才能实现
事件冒泡:
从事件目标开始 顺着结构父级 一直到window都触发同类型的事件
父子关系中,给父元素,和子元素绑定了对应的事件函数,
点击子元素的时候,会你默认的触发到你的父元素上面,这种事件的执行机制被称之为事件冒泡
事件执行从内向外触发
事件捕获:
先触发 window上的同类型事件,最后触发 事件目标的同类型事件
父子关系中,,给父元素,和子元素绑定了对应的事件函数,
执行顺序是,事件从外向内依次触发
在标准浏览器下,如何进行事件捕获触发行为
DOM 0级事件,没有捕获,只有冒泡
只有 addEventListener 是可以修改触发阶段
设置完参数3,就决定了代码执行是冒泡阶段还是捕获阶段
如果没有参数3,则默认是在冒泡阶段触发
如果参数3为false,则为冒泡阶段触发(子=>父)
如果参数3为true,则为捕获阶段触发(父=>子)
注意: 同一个元素的同一个事件类型的事件处理函数,先进行捕获然后进行冒泡执行
阻止事件传播
非IE浏览器阻止事件传播:
e.stopPropagation()
IE浏览器阻止事件传播(冒泡):
e.cancelBubble=true
事件委托
- 把自己的事件委托给别人来做
循环绑定事件:
缺点:
给太多的元素绑定事件,DOM性能浪费
对动态操作的元素不友好
事件委托:
事件绑定过程中,通过利用事件冒泡原理,让父元素去做一些事情,
把原本子元素上面应该干的事情,直接放在父元素上面去做
使用是DOM2事件监听的方法完成
需要使用e.target
优点:
只给一个元素绑定了一次事件
对动态操作的元素友好
核心: 利用了绑定事件的 默认事件行为的传播
比如: a元素的事件,绑定给a元素的 结构父级
在结构父级的事件内,通过 事件目标 判断 你准确点击的是 a元素
this和e.target
使用循环事件绑定,this表示当前元素
使用事件委托,e.target表示当前元素
例:
ul.addEventListener("click",function(e){
if(e.target.innerHTML=="+"){
e.target.previousElementSibling.value++
}else if(e.target.innerHTML=="-"){
e.target.nextElementSibling.value--
}
})
阻止默认行为
默认行为:
不需要事件绑定,天生自带的行为
比如:
a 标签的点击,只要点击了,会默认跳转或锚点定位
表单提交,只要点击submit按钮,那么表单会自动提交
鼠标右键点击,只要行为发生,会默认出现菜单
阻止默认行为:
不让本身应该发生的事情发生
在同类型的事件中,进行默认事件的阻止
标准浏览器:
事件对象.preventDefault()
低版本IE:
事件对象.returnValue = false
在DOM 0级事件中 也可以通过 在事件处理函数中return false;阻止默认行为
注意:
return false; 一定要写在处理函数的最后面,因为return 还会终断函数代码的执行
保证前面的代码不报错,因为js中代码报错,抛出异常,则 后续代码不会执行
阻止表单默认提交:
document.querySelector('form').addEventListener('submit',function(e){
e.preventDefault();
console.log( '已经阻止了表单的默认提交行为' );
})
阻止默认选中:
document.querySelectorAll('p')[0].onselectstart = function () {
console.log( '别想选中内容了' );
return false;
}
放大比例公式(放大镜案例)
-x*(大图宽度-大盒子宽度)/(中图宽度-遮罩层宽度)
-y*(大图高度-大盒子高度)/(中图高度-遮罩层高度)
this指向
-
官方: 指当前代码执行的上下文环境(context) 也就是执行上下文
-
私人解释:
- 就是在一个作用域中(全局/局部)的关键字
- 全局作用域 this
- 在全局作用域中,this就是 window
- 函数作用域 this
- 定义: 函数中的this 和函数定义在哪里没有关系,和函数的调用(执行)方式有关(箭头函数除外)
1.普通调用 函数名() 函数内的 this 指向 window 2. 对象调用 对象.函数名() 函数内的this 指向 调用函数的对象 3. 事件处理函数 事件源.on事件类型 = 函数 事件源.addEventListener('事件类型',函数) 事件触发的时候,执行的函数中 this 指向 事件源(绑定事件的元素) 4. 定时器处理函数 setTimeout(函数,毫秒) setInterval(函数,毫秒) 函数内的this 指向 window 5. 自调用函数(立即执行函数) ;(函数)() !(函数)() ~(函数)() 函数调用后会立即执行,而且函数内的this 指向window总结: 1)全局里面:this=>window 2)普通函数:this=>window 3)对象里面的函数:this=>与函数调用有关系 函数名()=>window 对象.键()=>对象 数组[索引]()=>数组 4)事件函数:this=>事件源 5)定时函数:this=>window 6)自调用函数:this=>window 7)箭头函数中的this:#箭头函数中的`this`就是 定义箭头函数作用域中的 `this` 1、箭头函数中没有自己的this指向 2、箭头函数中的this,根据上下文来决定this指向 3、如果单机事件中有一个箭头函数,箭头函数中的this指向单机事件的事件源 4、如果单机事件中有一个定时器函数,定时函数使用箭头函数,定时器函数中的this指向单机事件的事件源 5、箭头函数中this与代码调用没有关系 6、箭头函数的this指向箭头函数所在作用域的上一级作用域的this
强行改变this指向
-
强行改变this的指向
- this的指向 是由函数的调用方式决定的
- 就是在本次调用函数的时候,改变函数内 this 的指向
-
all函数名.call(指向,实参),对象.函数名.call(指向,实参)
第一个参数: 此次执行函数内 this 的指向 第二个参数开始: 依次给该函数的实参 直接附加在函数后面直接调用使用,可以让他忽略原有函数中的this指向 特点: 立即调用函数 -
apply函数名.apply(指向,实参数组),对象.函数名.apply(指向,实参数组)
第一个参数: 此次执行函数内 this 的指向 第二个参数: 是一个数组或伪数组集合,集合中的每一个数据,按照顺序依次作为函数执行的实参 直接附加在函数后面直接调用使用,可以让他忽略原有函数中的this指向 特点: 立即调用函数 -
bind函数名.bind(指向,实参),对象.函数名.bind(指向,实参)
第一个参数: 新函数的内 this 的指向 第二个参数开始: 依次给新函数调用的实参 bind直接使用则返回代码片段,需要让代码片段执行所以需要用变量接收,调用这个变量 特点: 不会立即中执行函数,而是返回一个新函数,新函数和原函数代码一模一样,只不过新函数中的this指向第一个参数,而且新函数中的this指向锁死了 新函数中的this指向已经锁死,任何方式不能修改
ECMAScript
-
ES 就是 ECMAScript的简称
-
ES 就是 javascript的语法标准规范
1997 ES1 1998 ES2 1999 ES2.1 2000 ES3(目前我们使用的大部分语法都是ES3的标准语法) 2001 (ES4版本夭折,因为ES4版本的语法有太多颠覆性的修改,这一版没有通过) 2013 ES5 主要添加了一些数组方法 2014 ES5.1版本已经被大部分浏览器兼容 2015 ES2015(ES6)版本 推出了比较多的新语法 let const 箭头函数 展开运算符 promise... 2016 ES2016(ES7) async/await语法 2017 ES2017(ES8) 2018 ES2018(ES9) 2019 ES2019(ES10) 2020 ES2020(ES11) replaceAll 间隔数字写法 10-0000-0000 2021 ES2021(ES12) 2022 ES2022(ES13)
动态表格
获取一个 table
var tr= table.insertRow() 插入行 <=> document.createElement("tr")
行有一个 rowIndex 属性 动态显示行号
var td= tr.insertcell(); 插入单元格 <=> document.createElement("td")
table.deleteRow(index); index 行号
ES5新增的数组方法
-
forEach、map、filter原理、例: 数组.forEach(function(x,y,z){}) arr.forEach(function (x, y, z) { console.log(x); console.log(y); console.log(z); }) ==等价于== for (var i = 0; i < arr.length; i++) { fun(arr[i], i, arr) } function fun(x, y, z) { console.log(x); console.log(y); console.log(z); }
JSON
JSON:特殊字符串,字符串里有特定的格式
一般里面放数组、数组对象、对象
格式:
对象 var json1={}
json格式字符串 var json2='{}'
数组,数组里面存储对象 var json3=[{},{}]
json格式字符串 var json4='[{},{}]'
注意:
1. json格式的字符串中 只能 由 单引号包裹
2. json格式的字符串中 只能 有 数组或对象类型结构的数据
3. json格式的字符串中 不要有函数(自动过滤函数)
4. json格式的字符串中 对象的属性名只能使用双引号包裹,文本内容也是只能由双引号包裹
5. json格式的字符串中 对象或数组最后一项数据后不能有逗号
字符串和JSON数据转换
- 将json格式的数据,转换成数组、对象
JSON.parse(json格式字符串)- 返回值: 转换后的数组或对象
- 将数组、对象转换成json数据格式
JSON.stringify(数组或对象)- 返回值: json格式的字符串
- 注意: 如果报错信息是 Unexpected token XXX in JSON at position 则说明JSON.parse中数格式错误
- 实现深度拷贝
var obj2 = JSON.parse(JSON.stringify(obj))
JSON文件
以 .json 为后缀的文件,文件内容必须满足JSON字符串格式
可以把.json文件当成一个JavaScript文件来处理
例: <script src="./person.json"></script>
ES6
ES6-变量声明
除了使用var之外,还可以使用:let、const
变量声明:var、let
常量声明:const
变量:可以更改变化的量
常量:不可以更改的量,声明之后不能修改
-
let、const声明变量和var的区别
1)let,const不能重复声明一个变量 2)let,const不存在声明提前(预解析) 3)let,const存在一个独立的块级作用域(也称之为‘暂时性死区’) 花括号{}就代表了一个块,只会在{}里起作用 -
let和const区别
1)let可以重新赋值;const不能重新赋值 如果const声明基本数据类型,值不可修改 如果const声明复杂数据类型,可以修改内容,不可修改引用地址 2)let可以先声明后赋值;const是不能先声明后赋值,只能声明并赋值
ES6-箭头函数
属于函数的一种,只是函数的一种简单的表达形式
只能应用在表达式声明的函数中简写
语法:var box=()=>{}
()用来书写形参
=> 箭头函数的标志
{}用来放函数体代码
对象中的函数:
fn:()=>{console.log("乐乐")}
简写注意事项:
1、()可以简写
箭头函数中只有一个行参时,()可以省略
没有或者有多个行参时必须添加()
var box=a=>{}
2、{}可以简写
箭头函数中,只有一句表达式时,{}可以省略
自动返回该行结果,自动把这句话的结果当做函数的返回值,所以不写 return
var box=()=>console.log("乐乐")
var box=a=>console.log("乐乐"+a)
let fun1 = (a, b) => a + b; console.log(fun1(10, 20));
#箭头函数中的this
箭头函数中的`this`就是 定义箭头函数作用域中的 `this`
注意:事件函数中的代码片段,不推荐转换成箭头函数,改成箭头函数之后,this指向了window
箭头函数中的this:
1)箭头函数中没有自己的this指向
2)箭头函数中的this,根据上下文来决定this指向
3)如果单机事件中有一个箭头函数,箭头函数中的this指向单机事件的事件源
4)如果单机事件中有一个定时器函数,定时函数使用箭头函数,定时器函数中的this指向单机事件的事件源
5)箭头函数中this与代码调用没有关系
6)箭头函数的this指向箭头函数所在作用域的上一级作用域的this
#箭头函数中的arguments
箭头函数中没有arguments对象
不能使用 arguments
ES6-对象的简写
-
对象的属性名和变量名同名,可以只写一次(值是变量)
例: let age = 20; var obj = { name: "张三", age, // 等价于age:age sex: "男" }; console.log(obj); -
如果对象的属性是一个函数,function可以省略(不能是箭头函数)
例: var obj = { name: "张三",age:18, fun1: function () { console.log("普通函数") }, fun2() { console.log("普通函数简写形式") } }
ES6-解构和赋值
解构:分解拆分结构
赋值:拆分完毕结构之后进行赋值
语法: 解构 = 数组/对象
赋值等号 左边的叫做: 解构
赋值等号 右边的叫做: 数组/对象
在[]内按照索引位置书写变量即可
在{}内书写对象结构的键名
解构和赋值使用的符号{}[]
解构对象:{}
解构数组:[]
多维数组解构:把原数组复制一份一模一样的放在结构的位置
对象的多维解构:
结构多维对象数据
直接把对象数据类型复制一遍,放到结构位置
对象解构可以起别名:在解构中,除了书写可以获取的键名外,可以 `键名:别名`
例:
var obj = {name: "乐乐",sex: "男",age: 100}
var arr=["勇哥",'浠浠','鹏哥']
解构对象 let { name, sex, age} = obj;
解构数组 let [a,,c]=arr
注意:解构的变量中可以比原来少,也可以比原来多
多的情况没有对应的键值,获取不到对应的值返回的为undefined
变量的名字要与对象中的键保持一直
注意:解构的时候没有必要完全的解构出来,如果想要中间的不结构,一定要空开
如果对象或者是数组是多层结构,解构的时候也需要多层嵌套,格式必须一致
例:var brr=[1,[3],4]
let [a,[b],c]=brr
例:对象解构起别名
let obj = {objname:'zs',userage:17}
let {objname:username} = obj;// 等价于 let username = obj.objname;
console.log( username ) // 'zs'
[交换变量]
var a=3,b=4
var [b,a]=[a,b] 右侧赋值给左侧
ES6-扩展运算符
也叫做展开运算符,主要是用来展开数组和对象
使用的符号: ...
用就是用来打散一数组,打散一对象
伪数组也可以
注意:
展开的对象需要放在 {}
展开的数组需要放在 [] 或 方法函数实参位置
例:console.log(...arr)
var brr=[...arr,"乐乐","申帅","静雅"]
例:var obj = {name: "小张",sex: "男",age: 100}
var obj1 = {...obj,love: "乐乐"}
如果用在形参上,会把实参的值合并成一个数组
例:function fn(...a) {console.log(a);} // 输出[10,20,30,40]
fn(10, 20, 30, 40);
例:function fun(a, b, ...c) {console.log(a, b, c);} // 输出 10 20 [30,40]
fun(10, 20, 30, 40)
伪数组通过展开运算符转为真数组
例:let lis = document.getElementsByTagName('li');
let arrLis = [...lis]
[面试题]
求最大值的方法:
1)循环冒泡排序
2)sort(function(a,b){return a-b})
3)Math.max(...arr) 参数不能为数组,参数为一组数
4)非得要从Math.max()传入数组:修改this指向
var a=Math.max.apply(Math,arr); console.log(a)
ES6-展开运算符
...既可以展开数组,也可以合并多个数据,得到数组- 当
...用于函数形参位置的时候,就是一个合并运算符,可以将多个实参合并起来得到一个数组 - 合并运算符,可以适当的弥补箭头函数中没有
arguments的缺陷
ES6-模块化语法
-
模块化语法
- 利用自身语法规则,在自己文件中引入其他文件
-
**(前提)**当你需要按照模块化语法进行开发的时候
- 当前页面的script标签需要一个
type属性,值设置为module- 只有这样,浏览器在js语句的时候,才会按照模块化语法来解析
- 当前页面必须在服务器上打开,本地打开不能使用模块化语法
- 在vscode中可以使用
Live Server插件
- 在vscode中可以使用
- 当前页面的script标签需要一个
-
模块化语法规则
- 当你开始使用模块化语法的时候
- 每一个js文件都会变成一个独立js文件,互相之间没有任何联系和关系
- 文件和文件之间不共通
- 我们把每一个独立文件叫做 文件作用域(模块作用域)
- 当你需要互通数据的时候
- 需要使用导入导出语法
- 当你开始使用模块化语法的时候
-
导出语法:
-
当前文件中,需要把一些数据向外暴露
语法1: export default 数据 语法2: export 数据例: //这是a.js模块 // 这个文件就是一个 独立模块 const num = 666; const str = 'hello'; let fn = ()=>console.log( '我是a.js文件中的函数' ); // 我希望别的文件引入 a.js 之后可以使用 某一些内容 // 那么 我来导出,向外暴露 const obj = { num, str } console.log( 'a.js执行了' ) // 导出语法1 export default obj; //export default function ff() {}; // 导出语法2 export const msg = 'ok'; export const code = 1; /* 相当于向外暴露了 { default: {num,str} msg, code } */
-
-
导入语法:
-
在当前自己文件中,把某一些文件导入自己内容
-
目的: 为了使用该文件中暴露的数据,执行该文件
-
导入文件的时候,会执行该文件
语法1: import 变量名 from 文件名 语法2: import { } from 文件名 语法3: import 文件名 #注意: # 导入语法1 只能导入 导出语法1 的内容 # 导入语法2 只能导入 导出语法2 的内容例: // 这是b.js模块,我要导入a.js文件 // 对应的导入语法1 // ModuleA 得到的是 a.js中导出的那个default import ModuleA from './a.js'; // 导入语法2 import {msg} from './a.js' // 同时使用导入语法1,导入语法2 import ModuleA,{msg,code} from './a.js' console.log( ModuleA ); // console.log( msg ); // console.log( code );
-
ES6-模板字符串
把一块代码当做模板来使用
基本语法:`` 反引号
(``)和("")的区别:
1)普通的引号使用多字符串的时候需要多次拼接而且不能换行
2)使用模板字符串,不用再次换行拼接,默认里面就支持内容
注意:模板字符串里面任何内容都能显示出来,如 空格,tab等等
模板字符串拼接内容:
不打断拼接,使用${}的形式直接获取,直接放在模板字符串中即可,可直接访问变量的值
例: ${name}
3)可以调用函数,可以拆分参数
例: fun`JS${num}你好${num2}世界` <=> fun([JS,你好,世界],num,num2)
形参1:[JS,你好,世界]
${}将以此传给其他形参
正则
作用: 经验字符串是否符合规则
返回是布尔值 true,false
正则的基本语法:
把一些特殊符号放在两个斜杠符号中间,代表一个正则
正则也是复杂数据类型
创建方式有两种:
1)字面量直接定义:
var reg1=/abcd/
2)构造函数的定方法:
var reg2=new RegExp('abcd')
两种创建正则的区别
-
书别标识符的区别
字面量: 直接书写在正则的后面 例:let r1 = /qwer/ig; 内置构造函数: 以第二个参数的形式书写 例:let r2 = new RegExp('qwer','ig') -
拼接变量的能力
字面量: 不能进行变量拼接 let reg = '/^'+str+'$/'; 拼接后的reg是字符串,不是正则 内置构造函数: 可以拼接变量 因为内置构造函数的第一个参数就是字符串类型 例:let reg2 = new RegExp('^'+str+'$') -
书写基本元字符
字面量: /\d\w/ 内置构造函数: new RegExp('\\s\\w\\d') 在字符串中 \ 具有转义含义 `\\` 前一个 \ 是将后一个 \ 转为一个普通文本字符
正则的常用方法
-
test() 匹配基本语法:正则.test(字符串) 如果满足正则规则,则返回true 如果不满足正则规则,则返回false -
exec() 捕获基本语法:正则.exec(字符串) 作用:把字符串中符合规则的内容筛选出来 返回:一个数组 或 null 返回的:['你好', index: 0, input: '你好我叫乐乐,你好,helloworld', groups: undefined] "你好" 捕获的内容 groups: undefined index: 0 该查找内容在字符串中的下标 input: "..." 查找的是哪一个字符串 length: 1 查找到数组内容的长度 返回值: 1. 原字符串中没有符合规则的字符片段 返回值:null 2. 原字符串中有符合规则的字符片段 返回值:一个数组,[0]的位置就是从原字符串中捕获到的内容 a)正则中没有(),也没有全局标识g 返回值:只有[0] 捕获到的内容 不管捕获多少次,正则都是从原字符串开始的位置进行检索捕获 b)正则中有全局标识g 返回值:数组,[0]依旧是正则捕获到的内容 但是从第二次捕获开始,会从上一次捕获结束位置开始检索 以此类推,直到找不到了为止,返回值null 再下一次又从原字符串的开始位置进行检索 c)正则中有() 返回值:数组,为[0]依旧是捕获捕获的内容 从[1]开始 依次是每一个小括号的单独捕获内容
基本元字符
正则中具有特殊意义的处理字符
a) . 任意的一个非换行(换行:\n)字符都可以
b) \ 反斜杠:转义字符,将一些有意义的符号转换成没有意义的字符
把你的没有意义的字符转换成有意义的符号
\. 原因:.是匹配所有字符, \. 就代表的了一个点
c) \s 作用:匹配的是空白字符(包括 空格(\n),回车,tab(\t))
d) \S 作用:匹配的是非空白字符串
e) \d 作用:匹配的是数字
f) \D 作用:匹配的是非数字
g) \w 作用:匹配的是字母数字下划线
h) \W 作用:匹配的是非字母数字下划线
总结:小写的使用频率比较高
限定符--限定元字符
限定元字符:用来限定前一个符号连续出现的次数
a) * 作用:至少匹配0次,0~正无穷次
b) + 作用:至少匹配1次,1~正无穷次
c) ? 作用:匹配的是0次或者是1次,最少0次,最多就1次
d) {n} 作用:限定为n次
e) {n,} 作用:匹配的是至少n次,n~正无穷次
f) {n,m} 作用:匹配的是至少n次,最多m次
边界符--边界元字符
限定字符串的开始,限定了字符串的结尾
限定开始 ^
限定结尾 $
注意:
如果^和$一起添加,则限定了次数
没有^和$ 叫做'包含'
有^和$ 叫做'只能'
特殊元字符
任何的一个符号,字母,空格,数字等等都算作一个字符
a) () 作用:限定一组元素,把一些东西放在一组里面,
一般情况下需要配合|来使用
表示一个整体
单独捕获(捕获方法中)
b) | 作用:表示或者,几个里面选择一个,
一般和 () 联用
只有() ^ $ 能区分'或'的边界
例如:123@qq.com 123@sina.com 567@163.com 999@yahoo.cn
假如:前面就限定:3为数字
/^\d{3}\@(qq|sina|163|yahoo)\.(com|cn)$/
c) [] 作用:代表的是一个字符集;从中括号里选择一个
注意: 一个[]只占一个位置
[13579]从奇数里面拿一个
\d等价于[0123456789]
d) [^] 作用:代表的是一个字符集,排除掉中括号中的内容
注意: 一个[^]只占一个位置
\D等价于除了中括号里面数字的所有内容[^0123456789]
e) - 作用:连续的意思,一个范围
一般和[]联用
注意: 匹配中文必须保证 Unicode 码是连续的
表示0~9: [0-9]
表示小写字母: [a-z]
匹配大写字母: [A-Z]
匹配小写的a-z和大写的A-Z: [a-zA-Z]
匹配一位中文:[\u4e00-\u9fa5]
重复元字符
语法: \n 比如: \1 \2 \3 ....
重复出现
需要第n个小括号的内容一模一样的重复
#注意: 不是重复多少次,而是重复第n个小括号匹配的内容
如何区分正则表达式中第几个小括号:
在正则内,按照'开始小括号'数
'(' 开始括号
')' 结束括号
例:
(a(b(c)))(d)(e)
\2:表示重复(b(c))的内容
断言符--断言元字符
断言(预查)
需要匹配前后跟特定模式的内容
分为`前瞻断言`和`后瞻断言`
前瞻断言
1. 前瞻肯定断言
语法: x(?=y)
作用: 匹配x,且x后面必须跟着y
2. 前瞻否定断言
语法: x(?!y)
作用: 匹配x,且x后面必须不跟着y
后瞻断言
1. 后瞻肯定断言
语法: (?<=y)x
作用: 匹配x,且x必须跟在y后面
2. 后瞻否定断言
语法: (?<!y)x
作用: 匹配x,且x必须不跟在y后面
标识符
书写在正则表达式后面
用来修饰整个正则表达式
匹配全局: g (global单词的缩写)
忽略大小写: i (ignore单词的缩写)
匹配全局:正则表达式后面加g
/\d{2}/g
查找字符串中有符合条件的内容
和捕获方法一起使用才有效果
匹配忽略大小写:正则表达式后面加i
/\d{2}/i
无论输入大写还是小写都行
正则的两大特性
-
懒惰性
当你捕获内容的时候,每次默认从字符串的开始位置检索 解决方案: 加一个全局标识g -
贪婪性
贪婪匹配: 能拿'多少'拿'多少',尽量可能多的捕获 非贪婪匹配: 能拿多'少'拿多'少',尽量可能少的捕获 贪婪限定符: * + ? {n,} {n,m} 非贪婪限定符: *? +? ?? {n,}? {n,m}? 例: let reg = /<p.*>/ let reg = /<p.*?>/
字符串方法
-
search()基本语法: 字符串.search(正则) 返回值: 如果有符合的字符片段,则返回该字符片段的起始索引 没有查找到,则返回的是-1 -
match()基本语法:字符串.match(正则) 返回一个数组 g(匹配全局)查找字符串中所有符合条件的内容,否则只查找一个 返回值: 如果传入的参数是字符片段,或者是没有全局标识g的正则,则返回值和正则的exec方法一模一样 如果传入的参数是正则且有全局标识g,则返回一个数组,数组内的数据都是捕获到的内容 -
replace(参数1,参数2)用法1: 参数1:正则 参数2:替换上的字符 返回值:替换好的字符串 当你传递的是正则表达式,且有全局标识g,则会全部替换 用法2: 参数1:正则 参数2:回调函数(返回替换上的) 参数1:元字符串 参数2:匹配到字符串第一段 参数3:匹配到字符串第二段 参数4:匹配到字符串第三段
函数节流和函数防抖
函数节流:n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效
节流阀,开关
在单位时间内只触发一次内容
从开始的时候,就固定了结束的时候
函数防抖:n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时
在单位时间内只触发一次内容
开始之后,当第二次开始的时候,重新计时
函数传参时的默认值
使用逻辑或||的短路逻辑,如果||前面为真则取前面的值,前面值为假则取后面的值
如果不传递实参则使用默认值
例:
function box1(){
x=x||20
console.log(x)
}
box1(30)
ES6中和箭头函数中可以直接在()中写默认值:
var fun1=(a=10)=>console.log(a)
fun1(30)
检查数据类型
-
typeof(变量)方法:
typeof主要应用在检查基本数据类型中 如果检查复杂数据类型时: 检查函数则返回function 检查其他复杂数据类型则返回object -
精准检测
Object.prototype.toString.call(内容)返回值: [object Number] [object String] [object Boolean] [object null] [object undefined] [object Function] [object Array] [object Objest] [object RegExp] [object Date] 扩展: 打印分组开始:console.group() 打印分组结束:console.groupEnd()
运动函数
实现运动函数的必要参数:
1)运动属性:top、left
2)判断条件的目标值:运动到什么位置
3)运动元素
-
简单运动函数
例: /** * @description: 简单的运动函数 * @param {Object} ele 运动的元素 * @param {String} type 运动的样式 * @param {Number} target 运动的目标样式值 */ function move(ele, type, target) { // 获取到元素的当前left样式值(获取非行内样式是带单位的字符串) let current = parseInt(window.getComputedStyle(ele)[type]); let timer = setInterval(() => { current += 5; // 每过一段时间,将current累加5的距离,然后显示在div上 // 判断是否到达目标位置 type: target if (current >= target) { // 到达目标位置 // 关闭定时器 clearInterval(timer); ele.style[type] = target + 'px' // 重新将目标位置的值赋值 } else { // 每过一段事件运动后显示的效果 ele.style[type] = current + 'px' } }, 20) } -
多元素运动函数(直线运动)
例: document.querySelector('div').onclick = function () { move(this, { left: 400, top: 200 }) } /** * @description: 简单的运动函数 * @param {Object} ele 运动的元素 * @param {Object} options 多个运动样式和目标值组成的对象 */ function move(ele, options) { // 因为是多样式的运动, 遍历options对象--for-in for (const type in options) { // type 就是元素运动的样式名 // options[type] 运动样式对应的目标值 // 让元素运动到目标位置的代码 // 获取到元素的当前运动样式的 样式值(获取非行内样式是带单位的字符串) let current = parseInt(window.getComputedStyle(ele)[type]); let timer = setInterval(() => { // 获取目标值和当前样式值的差,然后获取百分之10 let goLength = (options[type] - current) / 10 // goLength 就是本次定时器,需要移动的距离,应该是一个整数 goLength = goLength > 0 ? Math.ceil(goLength) : Math.floor(goLength); current += goLength; // 每过一段时间,将current累加goLength的距离,然后显示在元素上 // 判断是否到达目标位置 type: options[type] if (current === options[type]) { // 因为每次运动剩下的百分之10,并取整,这样就保证了一定会到达目标位置 // 关闭定时器 clearInterval(timer); ele.style[type] = options[type] + 'px' // 重新将目标位置的值赋值 } else { // 每过一段事件运动后显示的效果 ele.style[type] = current + 'px' } }, 20) } } -
透明度运动函数
例: document.querySelector('div').onclick = function () { move(this, { left: 500, top: 400, opacity: .1 }) } /** * @description: 简单的运动函数 * @param {Object} ele 运动的元素 * @param {Object} options 多个运动样式和目标值组成的对象 */ function move(ele, options) { // 因为是多样式的运动, 遍历options对象--for-in for (const type in options) { // type 就是元素运动的样式名 // options[type] 运动样式对应的目标值 // 判断是否是透明度运动样式 let current; if (type === 'opacity') { // 放大一百倍 current = parseInt(window.getComputedStyle(ele)[type] * 100); options[type] *= 100; } else { // 不是透明度 current = parseInt(window.getComputedStyle(ele)[type]); } let timer = setInterval(() => { // 获取目标值和当前样式值的差,然后获取百分之10 let goLength = (options[type] - current) / 10 // goLength 就是本次定时器,需要移动的距离,应该是一个整数 goLength = goLength > 0 ? Math.ceil(goLength) : Math.floor(goLength); current += goLength; // 每过一段时间,将current累加goLength的距离,然后显示在元素上 // 判断是否到达目标位置 type: options[type] if (current === options[type]) { // 因为每次运动剩下的百分之10,并取整,这样就保证了一定会到达目标位置 // 关闭定时器 clearInterval(timer); } else { // 每过一段事件运动后显示的效果 if (type === 'opacity') { // 如果是透明度运动,则缩小100倍赋值 ele.style[type] = current / 100; } else { ele.style[type] = current + 'px'; } } }, 20) } } -
运动后回调
例: document.querySelector('div').onclick = function () { // left = 400 top = 200 opacity .3 // 运动结束后,需要在div中添加 一段文字 作为内容 // 调用封装的move函数实现 运效果 move(this, { left: 500, top: 400, opacity: 1 }, () => { this.innerText = '666'; this.style.backgroundColor = 'red'; }) } /** * @description: 简单的运动函数 * @param {Object} ele 运动的元素 * @param {Object} options 多个运动样式和目标值组成的对象 * @param {Function} cb 运动结束后执行的回调函数 */ function move(ele, options, cb = () => { }) { let count = 0;// 定义一个计数器 为0 // 因为是多样式的运动, 遍历options对象--for-in for (const type in options) { // type 就是元素运动的样式名 // options[type] 运动样式对应的目标值 // 判断是否是透明度运动样式 let current; if (type === 'opacity') { // 放大一百倍 current = parseInt(window.getComputedStyle(ele)[type] * 100); options[type] *= 100; } else { // 不是透明度 current = parseInt(window.getComputedStyle(ele)[type]); } // 开启一个定时器 计数器++ count++; let timer = setInterval(() => { // 获取目标值和当前样式值的差,然后获取百分之10 let goLength = (options[type] - current) / 10 // goLength 就是本次定时器,需要移动的距离,应该是一个整数 goLength = goLength > 0 ? Math.ceil(goLength) : Math.floor(goLength); current += goLength; // 每过一段时间,将current累加goLength的距离,然后显示在元素上 // 判断是否到达目标位置 type: options[type] if (current === options[type]) { // 因为每次运动剩下的百分之10,并取整,这样就保证了一定会到达目标位置 // 关闭定时器 clearInterval(timer); // 关闭定时器 计数器-- count-- // 判断计数器是否回0 if (count === 0) { // 所有定时器都关闭了,则运动完全结束 if (type === 'opacity') { // ele.style[type] = current / 100; } else { ele.style[type] = current + 'px'; } cb(); // 执行传入的回调函数 return;// } }// else { // 每过一段事件运动后显示的效果 if (type === 'opacity') { // 如果是透明度运动,则缩小100倍赋值 ele.style[type] = current / 100; } else { ele.style[type] = current + 'px'; } // } }, 20) } }
面向对象
OOP面向对象不是语法,是一个思想,是一种编程思想
核心:高内聚低耦合(性能)、抽象(类)
特性:封装、多态、继承
创建对象的方式
-
系统内置的构造函数创建对象:
js内置了一个Object构造函数,用来创造对象 当构造函数与new关键字连用时,就可以创造一个对象 例: var aa = new Object() //空对象 aa.name = 'Jack' //正常操作对象 -
字面量创建对象:
字面量形式创建,也就是直接写{} 直接添加成员,也可以动态添加 var aa={ name = 'Jack'} -
工厂函数创建对象:
工厂函数里可以创造一个对象,并且给对象添加属性,还能把对象返回 手动创建对象 手动添加成员 手动返回对象 例: function createObj() { //创建工厂函数 var obj = new Object() //手动创建对象 obj.name = 'Jack' //手动向对象添加成员 return obj //手动返回对象 } //使用这个工厂函数创建对象 var a1 = createObj() var a2 = createObj() -
自定义构造函数创建对象:
自动创建对象 自动添加成员 自动返回对象 先写一个构造函数 构造函数内向对象添加成员 使用构造函数创造对象(和new连用) 构造函数可以创建对象,并且创建一个带有属性和方法的对象 面向对象就是想办法找到一个有属性和方法的对象 面向对象就是自己制造构造函数的过程 例: function Person(name, gender) { //先创造一个构造函数 this.name = name this.gender = gender } //使用构造函数创建对象 var p1 = new Person('Jack', 'man') var p2 = new Person('Rose', 'woman')
构造函数的基本使用
1)和普通函数一样,但是调用的时候要和new连用,不写new就是普通函数调用
function Person() {}
var obj1 = new Person() // 空对象
var obj2 = Person() // undefined,普通函数调用
2)首字母大小(潜规则)
3)调用时如果不传参可以不写(),建议写上,如果需要传参就必须写上
4)构造函数内部的this,由于和new连用的关系,指向当前实例对象
function Person() { console.log(this) }
var obj1 = new Person() // this => obj1
var obj2 = new Person() // this => obj2
5)因为构造函数会自动返回一个对象,所以构造函数内部不要写return
return基本数据类型 return无意义
return复杂数据类型 构造器无意义
原型 prototype
原型是为了解决构造函数的缺点
属性放到函数内,方法放到prototype里
prototype是每个函数天生自带的成员,是一个对象空间
这个prototype可以由函数名来访问
例:
function Person() {}
Person.prototype.name = 'prototype'
Person.prototype.sayHi = function () {}
ES6 class声明类
为了避免:
1、自定义构造函数毕竟还是函数,可能会 Person() 调用
2、自定义构造器函数需要和 new 配合调用
ES6通过class来避免这个问题:
例:
class 类名{
/* 类的构造器 */
constructor(){
this.属性名=值,
...
}
方法名(){
}
}
类 class 语法:
类和构造函数的作用是一样的(ES6中的类就是ES5中构造函数的语法糖)
作用:创建对象
语法:new 类名()
'类'只能用于创建对象(只能通过new语法创建对象),不能像构造函数一样,当做函数调用
类的原型链和构造函数一样
类语法:
class 类名{
constructor(){
}
}
注意:
1. 在类的大括号中书写方法,不能写function,而且写的方法是添加在原型中
2. '类'默认有一个constructor方法--构造器方法
类在new 实例化对象的时候,默认执行构造器方法
构造器方法中的关键字this指向'实例对象'
在实例化对象的时候,需要给实例对象添加属性方法,则在构造器方法中通过this添加
3. 类中的字段,就是相当于给实例对象添加的属性
字段名 = 值
实例化对象的时候,不能修改值
4. 静态属性和静态方法
static 字段 = 值
static 字段 = 函数
静态的属性和方法是 给类添加