1 简介
1.1 浏览器执行JS
- 渲染引擎 用来解析HTML和CSS,俗称内核,比如chrome浏览器的blink 老版本webkit
- JS引擎 也称JS解释器 用来读取网页中的js代码,对其处理后运行,比如chrome浏览器的v8引擎
浏览器本身并不会执行js代码,而是通过内置javascript引擎来执行js代码。js引擎执行代码是逐行解释每一句源码(转换为机器语言),然后由计算机去执行,所以javascipt语言归为脚本语言,会逐行解释执行。
1.2 JS的组成
-
ECMAScript javascript语法
-
DOM 页面文档对象模型
DOM提供的接口可以对页面上各种元素进行操作(大小,位置,颜色等)
-
BOM 浏览器对象模型
通过BOM可以操作浏览器窗口,比如弹出框、控制浏览器跳转、获取分辨率
1.3 JS三种书写方式
-
行内
<input type='button' value='1' onclick='alert('123')'> -
内嵌
-
外部js
1.4 JS注释
- 单行注释:ctrl+/
- 多行注释 默认shift+alt+a 可以自己修改为ctrl+shift+/
1.5 JS输入输出语句
alert(msg)弹出警示框console.log(msg)浏览器控制台打印输出信息propmt(info)浏览器弹出输入框,用户可以输入 prompt取过来的值是字符型的
2 变量和数据类型
2.1 JS变量
-
变量是用于
存放数据的容器。我们通过变量名获取数据,甚至数据可以修改 -
变量是程序在内存中申请的一块用于存放数据的空间
-
变量的初始化
- 声明变量 声明变量后计算机会自动为变量分配内存空间
- 赋值 把值存放到变量中
-
变量语法拓展
-
一个变量被重新复制后,它原有的值就会被覆盖,变量值将以最后一次赋的值为准
-
同时声明多个变量,只需要写一个
var,多个变量名之间使用逗号隔开var age = 10,name='sz',sex='男' -
只声明不赋值
undefined不声明不赋值 报错 不声明赋值直接使用 变量未定义
-
-
变量命名规范
- 由字母、数字、下划线、美元符号组成
- 不能以数字开头
- 严格区分大小写
- 不能是关键字 保留字 var for while
- 变量名要有意义,简易明了,易懂易理解
- 遵守驼峰命名法 首字母小写,后面单词的首字母需要大写myFirstName
2.2 JS数据类型
-
在计算机中,不同的数据所需占用的存储空间不同,为了便于把数据分成所需内存大小不同的数据,充分利用存储空间,于是定义了不同的数据类型
-
Js是一种弱类型语言。这意味着js不用提前声明变量的类型,只有在程序运行的过程中,类型会被自动确定
var num //这里的num我们并不确定是什么数据类型 var num = 10 //这里的num属于数字型
可见,js的变量数据类型是只有程序在运行过程中,根据等号右边的值来确定
-
Js拥有动态类型,同时意味着相同的变量可用作不同的类型
var num=123 num='abc' -
JS把数据类型分为两类
-
简单数据类型(number,string,boolean,undefined,null)
-
复杂数据类型(object)
-
number 数字型
常见的进制有二进制 八进制 十进制 十六进制
var num1=010 console.log(num1) //0开头表示八进制 输出8 var num2=0x12 console.log(num2) //0x开头表示十六进制 输出18js中数值的最大值和最小值
alert(Number.MAX_VALUE) alert(Number.MIN_VAlUE)三个特殊值
-
infinity代表无穷大 大于任何数值 -
-infinity代表无穷小 小于任何数值 -
NaNnot a number 代表一个非数值isNaN()这个方法用来判断非数字,返回值true表示不是数字,flase表示是数字
-
-
字符串型 String
字符串引号嵌套:
-
可以用单引号嵌套双引号,或者双引号嵌套单引号
var str='我是"高富帅"'
字符串转义符
-
\n 换行
var str='我是\n"高富帅"' -
\ \ 斜杠\
-
\' 单引号
-
\'' 双引号
-
\t tab缩进
-
\b 空格
字符串长度及拼接
-
length属性获取字符串长度var str='my nae is paul' console.log(str.length) -
拼接方式:
字符串+任何类型=拼接之后的新字符串拼接之前会把与字符串相加的任何类型转成字符串,再拼接成一个新的字符串
console.log('穿越'+'火线') console.log('今年'+18) //先把18转为字符串'18'再拼接 var age=18 console.log('今年'+age+'age')//更灵活
-
-
boolean 布尔型
-
布尔类型有两个值:true和false,其中true表示真,而false表示假
-
布尔型和数字型相加的时候,true的值为1,false的值为0
console.log(true+1) //2 console.log(false+1) //1
-
-
undefined
- 如果一个变量声明未赋值,就是
undefined-未定义数据类型 - undefined与数字相加 结果为
NaN-不是一个数字
- 如果一个变量声明未赋值,就是
-
null
- 可以给变量赋空值
- null与数字相加,结果为那个数字
-
-
2.3 typeof检测变量数据类型
var num= 10;
console.log(typeof num)
2.4 字面量
字面量是在源代码中一个固定值的表示法,简单来说,通过字面量可以一眼看出变量类型
- 数字字面量: 1,2,3....
- 布尔字面量: true,flase
2.5 数据类型转换
使用表单、prompt获取过来的数据默认是字符串类型的,此时就不能直接简单的进行加法运算,而需要转换变量的数据类型。
-
转换为字符串
toString()var num=1;alert(num.toString());String()强制转换 var num=1;alert(String(num))- 直接加空字符串转换 var num=1;alert(num+' ')
-
转换为数字型
-
parseInt(string) 将string类型转成整数数值型 parseInt('78')
var age = prompt('请输入您的年龄') console.log(parseInt(age)) -
parsenFloat(string) 将string类型转成浮点数数值型 parseFloat('78.12')
-
Number() 强制转换函数 Number('12')
-
js隐式转换(- * /) 利用算术运算隐式转为数值型 var a='12'-0
var year = prompt('请输入您的出生年份') var age = 2022 - year alert('您今年已经'+age+"岁了")
-
-
转换为布尔型
Boolean()函数 将其他类型转换成布尔值
- 代表空、否定的值会被转换成false,如' '、0、NaN、 null、undefined
- 其余的值都会被转为
true
2.6 解释型语言(js)与编译型语言(java)
- 编译器翻译的方式有两种:一种是
编译,一种是解释,两者区别在于翻译的时间点不同 编译就是在代码执行前进行编译,生成中间代码文件解释就是在运行时进行及时解释,并立即执行- 比喻:
- 编译语言:首先把所有菜做好(即所有代码编译好),才能上桌吃饭
- 解释语言:好比吃火锅,边吃边涮(执行一行编译一行),同时进行
2.7 标识符、关键字、保留字
- 标识符
- 指开发人员为变量、属性、函数、参数取的名字
- 关键字
- 指JS本身已经使用了的字,不能再使用它们充当变量名、方法名
- 例如:break case catch continue delete do else finally for while....
- 保留字
- 实际上就是预留的'关键字',意思是现在虽然还不是关键字,但是未来可能成为关键字,同样不能使用它们当变量名或方法名使用
- 例如:boolean byte char class const debugger double export....
3 运算符和语句
3.1 运算符
运算符(operator)也被称为操作符,是用于实现赋值、比较和执行算数运算等功能的符号
-
算术运算符
-
加、减、乘、除、取余(%)
-
浮点数算术运算里面会有问题
console.log(0.1+0.2)//0.3000000000000000000000001 console.log(0.01*100)//1.000000000000000000000001 -
不能直接用浮点数进行比较是否相等
var num = 0.1+0.2 console.log(num==0.3)//false所以不要直接判断两个浮点数是否相等
-
表达式和返回值
表达式是由数字、运算符、变量等组成的式子 例如 1+1
表达式最终都会有一个结果返回给我们 就是返回值
-
-
递增递减运算符
如果需要反复给数字变量添加或者减去1,可以使用递增++和递减--
运算符放在变量前为前置递增/递减运算符,放在变量后为后置递增/递减运算符
-
前置递增/递减运算符 ++num --num 先递增后返回值(执行程序)
-
后置递增/递减运算符 num++ num-- 先返回值(执行程序)后递增
var e = 10; var f = e++ + ++e; //10+12 e++=10 e=11 ++e=12 e=12 从左向右执行 console.log(f) -
比较运算符
比较运算符是两个数据进行比较时所用的运算符,比较运算后会返回一个布尔值。
==会自动把字符串型数据转型 例如:console.log(18=='18') //true
-
逻辑运算符
逻辑运算符是用来进行布尔值运算的运算符,其返回值也是
布尔值。- && 逻辑与 短路运算(逻辑中断) 只要左边不满足就返回
false - || 逻辑或 短路运算(逻辑中断) 只要左边满足就返回
true - !逻辑非
- && 逻辑与 短路运算(逻辑中断) 只要左边不满足就返回
-
赋值运算符
用来把数据赋值给变量的运算符
-
运算符优先级
- 一元运算符里的
逻辑非优先级很高 - 逻辑与比逻辑或优先级高
- 一元运算符里的
3.2 流程控制
流程控制就是控制代码按照什么结构顺序执行
流程控制主要有三种结构:
- 顺序结构
- 分支结构
- 循环结构
3.2.1 if分支语句
-
if单分支语句
if(条件表达式){ //执行语句 } -
if-else双分支语句
if(条件表达式){ //执行语句 }else{ //执行语句 } -
if-else if 多分支语句 适用大范围情况
if(条件表达式1){ //语句1 }else if(条件表达式2){ //语句2 }else if(条件表达式3){ //语句3 }else{ //最后的语句 }
3.2.2 Switch多分支语句
适用特定几种情况(与 if-else if相比)
switch(表达式){
case value1:
//执行语句1
break
case value2:
//执行语句2
break
default:
//执行最后的语句
}
如果当前的case里面没有break 则不会退出switch 继续执行下一个case
3.3 三元表达式
由三元运算符组成的式子称为三元表达式
语法结构:条件表达式?表达式1:表达式2
var num =10
var result = num > 5?'true':'false'
console.log(result)
3.4 循环结构
在js中,主要有三种类型的循环语句
3.4.1 for循环
-
结构:
for(初始化变量,条件表达式,操作表达式){ //循环体 } -
for循环嵌套结构
for(i=1,i<10,i++){ for(j=1,j<i,j++){ //执行语句 } }
3.4.2 while循环
-
结构:
while(条件表达式){ //循环体 } -
do....while循环
-
结构:
do{ //循环体 }while(条件表达式)
-
3.4.3 continue和break
-
continue关键字用于跳出本次循环,继续下一次循环
for(var i=1;i<=5;i++){ if(i=3){ continue; } console.log(i) } //打印台输出:1 2 4 5 -
break关键字用于跳出整个循环
for(var i=1;i<=5;i++){ if(i=3){ break; } console.log(i) } //打印台输出:1 2
4 数组
4.1 数组概述
- 数组是指一组数据的集合,其中的每个数据被称作元素,在数组中可以存放任意类型的元素
4.2 数组创建方式
-
利用
new创建数组var 数组名 = new Array(); //几种写法 var arr = new Array(2) //数组长度为2 里面2个空元素 var arr1 = new Array(2,3) //arr1=[2,3] -
利用数组字面量创建数组
//1 使用数组字面量方式创建空数组 var 数组名 = [] //2 使用数组字面量方式创建带初始值的数组 var 数组名 = ['小白','小黑',1,2,3,true]
4.3 访问数组元素
4.3.1 数组的索引
数组名[下标]用来访问数组元素的序号(数组下标从0开始)
//定义数组
var arrStus = [1,2,3]
//获取数组中第二个元素
console.log(arrStus[1])
4.3.2 遍历数组
即把数组中的元素从头到尾都访问一次
4.3.2.1 原生js遍历
//原生js
var arr=['1','2','3',1,2,3,true,flase]
for (var i = 0; i < arr.length; i++){
console.log(arr[i])
}
4.3.2.2 for of(ES6)
var arr = ['a','b','c'];
for(let item of arr) {
console.log(item);
}
4.3.2.3 map() 方法
支持return,相当与原数组克隆了一份,把克隆的每项改变了,不影响原数组
var arr = [1,2,3,4];
newarr = arr.map( function(item) {
return item;
})
当然有了 箭头函数 => 后更方便
var arr = ['a','b','c'];
var newArray = arr.map(x => x);
alert(newArray); // ['a','b''c']
map() 方法创建一个新数组,可以让每一个元素调用一个函数后返回结果
var newArray = arr.map(function (item) {
return [expression];
})
例如:
var arr = [1,2,3,4];
var newArray = arr.map(
x => x * x
)
alert(newArray); // [1,4,9,16]
4.4 常用数组方法
4.4.1数组中新增元素
-
通过修改
length长度新增数组元素var arr=['red','green','blue'] console.log(arr.length) arr.length += 1 //arr=['red','green','blue',undefined] -
通过修改数组索引新增数组元素
var arr=['red','green','blue'] arr[3]='pink' arr[4]='black'
4.4.2 筛选数组元素
var arr = [2,0,1,77,6,14,323,2,13]
var newArr = [];
for(var i = 0;i<arr.length;i++){
if(arr[i]>=10){
//这里是关键
newArr[new.Arr.length]=arr[i]
}
}
console.log(newArr)
4.4.3 检测是否为数组
-
instanceof运算符var arr = [] //数组 var obj = {} //对象 console.log(arr instanceof Array) //true console.log(obj instanceof Array) //false -
Array.isArray(参数)var arr = [] //数组 var obj = {} //对象 console.log(Array.isArray(arr)) //true console.log(Array.isArray(obj))
4.5 添加删除数组元素
-
push()
在数组末尾添加一个或多个元素 返回的是新数组长度
var arr = [1,2,3] arr.push(4,5) //[1,2,3,4,5] console.log(arr.push(6)) //输出6 -
unshift() 在数组开头添加一个或多个元素 返回的是新数组长度
var arr = [1,2,3] arr.unshift(4,5) //[4,5,1,2,3] console.log(arr.unshift(6)) //输出6 -
pop() 删除数组最后一个元素 返回的是删除的那个元素
var arr = [1,2,3] arr.pop() //没有参数 [1,2] console.log(arr.pop()) //输出2 -
shift() 删除数组第一个元素 返回的删除的元素
var arr = [1,2,3] arr.shift() //没有参数 [2,3] console.log(arr.shift()) //输出2 -
用上面的方法简化筛选数组
var arr = [2,0,1,77,6,14,323,2,13] var newArr = []; for(var i = 0;i<arr.length;i++){ if(arr[i]>=10){ //newArr[new.Arr.length]=arr[i] newArr.push(arr[i]) } } console.log(newArr)
4.6 数组索引的方法
indexOf从前面开始查找给定元素的索引 存在返回索引号 不存在返回-1lastIndexOf从后面开始查找给定元素的索引 存在返回索引号 不存在返回-1
var arr = ['red','green','blue','black']
console.log(arr.indexOf('blue'))
-
数组去重案例
目标:把旧数组中不重复的元素取出来放在新数组中,重复的元素只保留一个
核心算法:遍历旧数组,用旧数组中的元素去查询新数组,若新数组中没有这个元素则添加
//封装一个去重的函数 function deleteRepet(arr){ var newArr = [] for(var i = 0;i<arr.length;i++){ if(newArr.indexOf(arr[i])==-1){ newArr.push(arr[i]) } } return newArr } var arr = [2,3,3,1,1,3,2,4,5,4] console.log(deleteRepet(arr))
4.7 数组转换为字符串
var arr = [1,2,3]
console.log(arr.toString()) //'1,2,3'
console.log(arr.join()) //'1,2,3'
console.log(arr.join('-')) ,//'1-2-3'
-
数组拼接和截取
4.8 数组排序
-
翻转数组
reversevar arr=[2,4,3,1,5,6] arr.reverse() console,log(arr)//[6,5,,1,3,4,2] -
冒泡排序
//原生js var arr=[2,4,3,1,5,6] for(var i=0;i<=arr.length-1;i++){ for(var j=0;j<=arr.length-1;j++){ if(arr[j]<arr[j+1]){ var temp = arr[j] arr[j] = arr[j+1] arr[j+1] = temp } } } //sort方法 var arr=[2,4,3,1,5,6] arr.sort(function(a,b){ //return a-b 升学的顺序排列 //return b-a 降序的顺序排列 })
sort() 方法用于对数组的元素进行排序。
排序顺序可以是字母或数字,并按升序或降序。
默认排序顺序为按字母升序。
5 函数
5.1 函数概述
在JS里面,可能会定义非常多相同的代码或相似的代码,这些代码可能需要重复使用。
函数就是封装了一段可被重复调用执行的代码块,通过此代码块可以实现大量代码的重复使用
-
函数的使用
-
声明函数
function 函数名(形参1,形参2){ //函数体 } -
调用函数
函数名(实参1,实参2) -
如果实参个数多于形参,会取到形参的个数;如果小于形参,对应形参会默认为undefined
-
-
函数返回值
returnfunction 函数名(){ return 需要返回的结果 }- return还具有终止函数的功能,函数执行到return就会结束,并且return只能返回一个值
- 函数如果没有return语句会默认返回
undefined 、
-
函数的练习
利用函数翻转任意数组
function reverse(arr){ var newArr = [] for(var i =arr.length-1;i>=0;i--){ newArr[newArr.length]=arr[i] } return newArr } num=[1,2,3,4,5] reverse(num) //5,4,3,2,1
5.2 arguments的使用
-
当我们不确定有多少个参数传递的时候,可以用
arguments来获取。在Js中,arguments实际上是当前函数的内置对象,所有函数都内置了一个arguments对象,arguments对象存储了传递的所有实参 -
function fn(){ console.log(arguments) //里面存储了所有传递过来的实参 } fn(1,2,3) //打印台输出 1,2,3 -
arguments展示形式是一个伪数组,因此可以遍历。伪数组具有一下的特点:
-
具有length属性
-
按索引存储数据
-
不具有数组的push、pop方法
-
//利用函数求任意个数的最大值 function getMax(){ var max = arguments[0] for(var i =1;i<arguments.length;i++){ if(arguments[i]>max){ max=arguments[i] } } return max } getMax(1,2,3) //3 getMax(2,4,1,2) //4
-
-
只有函数才有arguments这个对象
5.3 函数的两种声明方式
-
利用函数关键字自定义函数
function 函数名(){ } 函数名() -
函数表达式(匿名函数-没有函数名)
var 变量名 = function(){ } 变量名()
5.4 作用域
-
Javascript作用域:就是代码名字(变量)在某个范围内起作用和效果。
目的:为了提高程序的可靠性,减少命名冲突
分类:
- 全局作用域:整个script标签 或者是一个单独的js文件
- 局部作用域(函数作用域) 只在函数内部有效
-
变量作用域
-
全局变量
- 在全局作用域下声明的变量
- 在函数内部没有声明但是直接赋值的变量(变量提升)
-
局部变量
比较:
- 全局变量只有浏览器关闭的时候才会销毁,比较占内存资源
- 局部变量程序执行完毕就会销毁,节约内存资源
-
-
ES6引入块级作用域
比如if{ }、 for{ }
-
作用域链
-
只要是代码就至少有一个作用域
-
函数内部的是局部作用域
-
如果函数中还有函数,这个作用域中又诞生一个新作用域
-
根据在内部函数可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问,就称作作用域链
function fn(){ var num = 20 function fun(){ console.log(num) //20 } } -
结果输出123
-
5.5 JS预解析(变量提升和函数提升)
js代码由浏览器的js解析器执行,js解析器在运行js代码的时候分为两步:
-
预解析
-
变量预解析(变量提升)
变量提升就是把所有的变量声明提升到当前作用域最前面,不提升赋值操作
- var 定义的变量
- 函数中未定义直接赋值的变量
-
函数预解析(函数提升)
函数提升就是把所有函数声明提升到当前作用域最前面,不调用函数
- 函数关键字定义的函数
-
-
代码执行
6 对象
6.1 对象概述
在js中,对象是一组无序的相关属性和方法的集合,所有的事物都是对象,例如字符串、数值、数组、函数等
对象是由属性和方法组成的,换句话说有属性和方法的都是对象
- 属性:事物的特征
- 方法:事物的行为
保存一个值时可以用变量,保存多个值时可以用数组,保存一个人完整的信息?
var arr=['张三疯','男',22]
6.2 创建对象的三种方式
-
利用
字面量创建对象就是
{ }里面包含了表达这个具体事物(对象)的属性和方法var obj ={ username:'张三', age:18, sayHi:function(){ //方法冒号后面跟的是一个匿名函数 console.log('hi~') } } //调用属性的两种方式 console.log(obj.username) console.log(obj['username']) //调用方法 obj.sayHi() -
new Object创建对象利用
=赋值的方法添加对象的属性和方法var obj = new Object() obj.name='张三' obj.age='18' obj.sayHi=function(){ console.log('~hi') } -
利用
构造函数创建对象可以利用函数的方法,重复创建具有相同属性和方法的对象
function 构造函数名(){ this.属性 = 值 this.方法 = function(){} } var obj1 =new 构造函数名();- 构造函数名首字母要大写
- 构造函数不需要
return就可以返回结果 - 构造函数属性和方法前必须用
this 构造函数和new 构造函数名- 构造函数,抽象了对象的公共部分,封装到了函数里面,泛指某一大类
- new 构造函数名,特指某一个,使用new关键字创建对象的过程也称对象实例化
6.3 遍历对象属性
使用for in遍历对象属性
for(变量 in 对象){
}
//例如
var obj={
name:'pete',
age:18
}
for(var k in obj){
console.log(k)//k变量 输出得到属性名
console.log(obj[k]);//得到对应的属性值
}
使用for in里面的变量一般使用k或key
6.4 内置对象
js中对象分为三大类:自定义对象、内置对象、浏览器对象
内置对象就是指Js语言自带的一些对象,这些对象供开发者使用,并提供了一些基本常用的功能(属性和方法)
-
查文档
- MDN
- W3C
6.4.1 Math对象
-
-
仿Math封装PI属性和最大最小值方法:
var myMath= { PI:3.1415926, max:function(){ var max = arguments[0] for(var i = 1;i<arguments.length;i++){ if(arguments[i]>max){ max=arguments[i] } } return max }, min:function{ var min = arguments[0] for(var i = 1;i<arguments.length;i++){ if(arguments[i]<min){ min=arguments[i] } } return min } } console.log(myMath.PI) console.log(myMath.max(11,55,13)) console.log(myMath.min(10,22,1)) -
常用属性和方法
- Math.PI 圆周率
- Math.floor() 向下/小取整
- Math.cell() 向上/大取整
- Math.round() 四舍五入取整 就近取整
-3.5结果为-33.5结果3 - Math.abs() 绝对值 隐式转换 会把字符串转换为数字
-
随机数方法
-
Math.random() 返回一个随机的小数 0=<x<=1
-
想要得到两个数之间的随机整数并包含这两个整数
Math.floor(Math.random()*(max-min+1))+min //封装成函数 function getRandom(min,max){ return Math.floor(Math.random()*(max-min+1))+min } //用此来随机点名 var arr=['张三','李四','王二麻'] console.log(arr[getRandom(0,arr.length-1)]) -
6.4.2 Date对象构造函数
只能通过调用Date来实例化日期对象,以常规函数调用它(即不加new操作)将会返回一个字符串,而不是一个日期对象。并且,Date没有字面量格式
-
使用Date 如果没有参数 返回系统的当前时间
-
参数常用写法 数字型 2019,10,01 字符串型'2019-10-1 8:8:8'
var date1 = new Date(2019,10,1) console.log(date1) //返回的是 2019,11,1 var date2 = new Date('2019-10-1 8:8:8') console.log(date2) -
格式化日期年月日
var date = new Date console.log(date.getFullYear()) //年份 console.log(date.getMonth()+1) //月份 getMonth()返回的月份小1个月 所以要加1 console.log(date.getDate()) //几号 console.log(date.getDay()) //周一-周六 1~6 周日为0 var year = date.getFullYear() var month = date.getMonth()+1 var dates = date.getDate() var arr = ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'] var day = date.getDay() console.log('今天是'+year+'年'+month+'月'+dates+'日'+arr[day]) -
格式化日期时分秒
var date = new Date() console.log(date.getHours()) //时 console.log(date.getMinutes()) //分 console.log(date.getSeconds()) //秒 //封装一个返回当前时分秒的函数 格式:08:08:08 function getTime(){ var time = new Date() var h = time.getHours() h = h <10 ? '0' + h : h var m = time.getMinutes() m = m <10 ? '0' + m : m var s = time.getSeconds() s = s <10 ? '0' + s : s return h+':'+m+':'+s } console.log(getTime()) -
Date总的毫秒数(时间戳)
Date对象是基于1970年1月1日(世界标准时间)起的毫秒数
-
通过 valueof() getTime()
var date = new Date() console.log(date.valueof()) //我们现在时间距离 1970.1.1总毫秒数 console.log(date.getTime()) -
+new Date (最常用)
var date = +new Date console.log(date) -
h5新增
console.log(Date.now())
-
-
倒计时案例
核心算法:输入的时间减去现在的时间就是剩余的时间,即倒计时
用时间戳来计算再转换为具体的时分秒
- d = parseInt(总秒数/60/60/24) // 计算天数
- h = parseInt(总秒数/60/60%24) // 计算小时
- m = parseInt(总秒数/60%60) // 计算分数
- s = parseInt(总秒数%60) // 计算秒数
function countDown(time){ var nowTime = +new Date() var inputTime = +new Date(time) var times = (inputTime - nowTime)/1000; var d = parseInt(times/60/60/24) d = d < 10 ? '0' + d : d var h = parseInt(times/60/60%24) h = h < 10 ? '0' + h : h var m = parseInt(times/60%60) m = m < 10 ? '0' + m : m var s = parseInt(times%60) s = s < 10 ? '0' + s : s return d + '天' + h +'时'+m+'分'+s+'秒' } console.log(countDown('2022-12-30 08:08:08'))
7 字符串对象
7.1 字符串对象概述
-
基本包装类型
-
对象即复杂数据类型才有属性和方法
-
简单数据类型如字符串为什么会有length属性呢? 因为基本包装类型把简单数据类型包装成为复杂数据类型
var str = 'andy' //等价于 //(1)把简单数据类型包装成为复杂数据类型 var temp = new String('andy') //(2)把临时变量的值给str str = temp //(3)销毁临时变量 temp = null这样基本数据类型就有了属性和方法
-
-
字符串的不可变
- 指的是里面的值不可变,每次重新赋值都是换新的地址开辟新的内存空间
- 因为字符串的不可变,所以不要大量的拼接字符串
7.2 根据字符返回位置
-
字符串的所有方法,都不会修改字符串本身(字符串是不可变的),操作完成后会返回一个新的字符串
-
var str = '天来了改革春风吹满地,春' //str.indexOf('要查找的字符',[起始的位置]) console.log(str.indexOf('春')) //2 console.log(str.indexOf('春',3))//8 从索引号是3的位置开始往后查找 -
返回字符位置
求某个字符出现的位置和次数
先查找第一个指定字符出现的位置
只要indexOf返回的结果不是-1就继续往查找
因为indexOf只能查找第一个,所以后面的查找,一定是当前的索引加1,继续往后查找
var str = 'abcoedasdoeadoekh' var index = str.indexOf('o') var num = 0 while(index !== -1){ num++; index=str.indexof('o',index+1) } console.log('o出现的次数:'+num)
7.3 根据位置返回字符
var str = 'andysen'
console.log(str.charAt(2)) //d
console.loh(str.charCodeAt(2)) //100 d对应的ascil码为100 可以用于判断用户按下了哪个键
console.log(str[2]) //数组索引方式 d
统计出现次数最多的字符
-
核心算法:利用charAt()遍历这个字符串
-
把每个字符都存储为对象的属性,如果对象没有这个属性,就为1,如果已存在就+1
-
遍历对象,得到最大值和该字符
var str = 'abcdoefgwoeasooshgo' var obj = {} for(var i =0;i<str.length;i++){ var chars = str.charAt(i) //因为这里的chars是字符串 所以不能用o.chars索引方式 只能用o[chars] 即要么o.a 要么o['a'] if(obj[chars]){ //o[chars] 得到的是属性值 obj[chars]++ }else{ obj[chars] = 1; } } console.log(obj) var max = 0 var chr = '' for(var key in obj){ //key得到的是属性名 //obj[key]得到的是属性值 if(obj[key]>max){ max = obj[key] chr = key } } console.log('最大次数:'+max+'最大字符:'+chr)
7.4 字符串操作方法
-
concat('字符串1','字符串2',,...)
var str = 'andy' console.log(str.concat('red')) //andyred -
substr(start,length)
- start 截取的起始位置 必需 要抽取的子串的起始下标 如果是负数,那么该参数声明从字符串的尾部开始算起的位置。也就是说,-1 指字符串中最后一个字符
- length 如果省略了该参数,那么返回从start到结尾的所有字符
var str1 = '改革春风吹满地' console.log(str1.substr(2,2)) //春风 console.log(str1.substr(1))// -
slice(start,end) 返回被截取的元素
- start 截取的起始位置 使用负数从数组的末尾进行选择 如果省略,则类似于 "0"。
- end 截取结束的位置 使用负数从数组的末尾进行选择 如果省略,将选择从开始位置到数组末尾的所有元素
var fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"]; var citrus = fruits.slice(1, 3); //Orange Lemon -
substring(start,stop)
- start 截取的起始位置 不能为负数
- stop 实际要截取结束的位置+1
var str="Hello world!" document.write(str.substring(3,7)) //lo w -
字符串转换大小写
- toUpperCase() //将所有英文字符统一转换大写
- toLowerCase() //将所有英文字符统一转换小写
7.5 替换字符串以及转为数组
-
替换字符 replace('被替换的字符','替换为的字符') 只替换第一个字符
var str = 'andyaa' console.log(str.replace('a','b')) //bndyaa实现多次替换
var str = 'andyaa' while(str.indexOf('a')!=-1){ str = str.replace('a','b') } console.log(str) -
字符转换为数组 split('分隔符') 与
join功能相反var str = 'red,blue,green' console.log(str.split(',')) //['red','blue','green'] var str1 = 'red&blue&green' console.log(str.split('&')) //['red','blue','green']
8 数据类型内存分配
8.1 简单类型和复杂类型
-
简单类型又叫做基本数据类型或者值类型 null string number boolean undefined null
-
简单数据类型
null返回的是一个空的对象 object -
如果有个变量我们以后打算存储为对象,暂时没想好放什么,可以先赋值null
-
var timer = null console.log(typeof timer) //object
-
-
复杂数据类型又叫做引用类型 通过new关键字创建的对象,如Object Array Date
8.2 堆和栈
-
栈:由操作系统自动分配释放存放函数的参数值、局部变量的值。简单数据类型存放到栈里面,复杂数据的地址也存放到栈空间
-
堆:存储复杂类型(对象) 一般由程序员分配释放,若程序员不是放,由垃圾回收机制回收。复杂数据类型存放到堆里面
-
-
9 Web APIS
-
web apis 与 js基础关联性
-
API和Web API
- API 为程序员提供的一种工具,以便轻松的实现某种功能
- Web API 是浏览器提供的一套操作浏览器页面和页面元素的API(BOM和DOM) 比如 alert
10 DOM对象
10.1 DOM概述
-
文档对象模型(Document Object Model) 通过DOM改变网页的内容、结构和样式
-
DOM树
- 文档:一个页面就是一个文档
- 元素:页面中的所有标签都是元素,DOM用element表示
- 节点:网页中的所有内容都是节点(标签、属性、文本、注释) DOM中使用node表示
- DOM把以上内容都看成对象
10.2 获取元素的方式
-
根据ID
-
getElementById返回的是一个元素对象 -
<div id='time'>2022-1-18</div> var timer = document.getElementById('time') console.dir(timer)
-
-
根据标签名
-
getElementsByTagName()返回的是获取过来元素对象的集合 以伪数组的形式存储 不推荐 -
<ul> <li>一二三四五</li> <li>五六七八九</li> </ul> var lis = document.getElementsByTagName('li') console.log(lis) console.log(lis[0]) //我们想要依次打印里面的元素对象我们可以采取遍历的形式 for(var i = 0; i<lis.length;i++){ console.log(lis[i]) }//一二三四五 五六七八九 //如果页面中只有一个li标签,返回的还是伪数组的形式 //如果页面没有这个元素,这个元素返回的空的伪数组形式 -
还可以获取某个元素内部的所有指定标签名的子元素
element(父元素).getElementsByTagName('标签名')父元素必须是单个对象(即必须指明是哪一个父元素对象),获取的时候不包括父元素自己
<ul> <li>一二三四五</li> <li>五六七八九</li> </ul> <ol id='ol'> <li>上梁山</li> <li>当好汉</li> </ol> <ol id='lo'> <li>春花月</li> <li>何时了</li> </ol> var ol = document.getElementsByTagName('ol') console.log(ol[0].getElementsByTagName('li')) //上梁山 当好汉 //ol[0]指定的就是第一个ol 因为通过标签返回的是元素的集合 伪数组 还有下一个 ol //或者通过id更明确的指定 var ol = document.getElementById('ol') console.log(ol.getElementsByTagName('li')) //上梁山 当好汉
-
-
通过H5新增方法
-
getElementsByClassName(类名)根据类名获取某些元素的集合 返回的也是元素对象的集合 -
<div class='box'>盒子1</div> <div class='box'>盒子2</div> <div id = 'box'>盒子3</div> var boxs = document.getElementByClassName('box') console.log(boxs) //输出伪数组 [div.box div.box] boxs[0].innerText ='1盒子' //<div class='box'>1盒子</div> boxs[1].innerText ='<p>盒子2</p>' //<p>盒子2</p> -
querySelector('选择器')根据指定选择器返回第一个元素对象里面的选择器需要加符号
类选择器-.classid选择器-#id<div class='box'>盒子1</div> <div class='box'>盒子2</div> <div id = 'box'>盒子3</div> var firstbox = document.querySelector('.box') console.log(firstbox) //盒子1对应的div var nav = document.querySelector('#nav') console.log(nav) //盒子3对应的div -
querySelectorAll('选择器')根据指定选择器返回所有元素对象<div class='box'>盒子1</div> <div class='box'>盒子2</div> <div id = 'box'>盒子3</div> var allbox = document.querySelectorALL('.box') //盒子1和盒子2对应的div
-
-
特殊元素获取 body和html
-
获取body元素
var bodyEle = document.body console.log(bodyEle) console.dir(bodyEle) -
获取html元素
var htmlEle = document.docunmentElement console.log(htmlEle)
-
10.2 DOM事件
-
事件三元素
-
事件源 事件被触发的对象
-
事件类型 如何触发 例如鼠标点击 键盘按下
-
事件处理程序 通过函数赋值的方式完成
事件源.事件类型 = 事件处理程序
-
-
执行事件过程
-
获取事件源
var div = document.querySelector('div') -
注册事件(绑定事件)
div.onclick -
添加事件处理程序(采取函数赋值形式)
div.onclick = function(){ //.... }
-
10.3 操作元素
-
改变元素内容
-
element.innerText从起始位置到终止位置的内容,但它会去除html标签,同时空格和换行也会去掉
-
element.innerHTMl从起始位置到终止位置的全部内容,包括html标签,同时保留空格和换行
//点击按钮时显示时间 <button>显示当前系统时间</button> <div>当前时间为</div> <p></p> //1 获取元素 var btn = document.querySelector('button') var div = document.querySelector('div') //2 注册事件 btn.onclick = function(){ div.innerText = getTime() } //封装一个返回当前时分秒的函数 格式:08:08:08 function getTime(){ var time = new Date() var h = time.getHours() h = h <10 ? '0' + h : h var m = time.getMinutes() m = m <10 ? '0' + m : m var s = time.getSeconds() s = s <10 ? '0' + s : s return h+':'+m+':'+s } //元素可以不用添加事件 var p =document.querySelector('p') p.innerText=getTime() -
innerText和innerHTML的区别
-
innerText不识别html标签 去除空格和换行
-
innerHTL识别html标签 保留空格和换行
-
这两个标签是可读写的 可以获取元素里的内容
<p> 123 <span>456</span> </p> var p = document.querySelctor('p') console.log(p.innerText) console.loh(p.innerHTML)
-
-
-
修改元素属性
-
src、href
<button id='btn'>按钮</button> <img src='images/1.jpg' alt='' id='img' title= '1'> var btn = document.getElementById('btn') var img = document.getElementById('img') btn.onclick = function(){ img.src = 'images/2.jpg' img.title = '1' img.id = 'image' } -
id 、alt、title
-
-
修改表单元素属性
利用DOM可以修改type、value、checked、selected、disabled表单属性
<button></button> <input type='text' value='输入内容'> //1 获取元素 var btn = document.querySelector('button') var input = document.querySelector('input') //2 注册事件 处理程序 btn.onclick = function(){ // input.innerHTML = '点击了' 是无效的 innerHTML只能对普通盒子有效,例如div,表单里的文字内容是通过value修改的 input.value='被修改了' //禁用按钮 //btn.disabled = true this.disabled = true //this指向的是事件函数的调用者btn }案例 仿京东显示密码
核心思路:点击眼睛按钮,把密码框类型改为文本框就可以看见里面的密码
一个按钮两个状态,点击一次切换为文本框,再点击切换为密码框
<div class="box"> <label for=""> <img src="icon/bukejian.svg" alt="" id="eye"> </label> <input type="password" name="" id="pwd"> </div>.box{ width: 400px; border-bottom: 1px solid #ccc; margin: 100px auto; position: relative; } .box input{ width: 370px; height: 30px; border: 0; outline: none; } .box img{ width: 24px; position: absolute; top: 2px; right: 2px; }window.onload=function(){ //1获取元素 var eye =document.getElementById('eye') var pwd = document.getElementById('pwd') //2注册事件 处理程序 var flag = 0 eye.onclick = function(){ if(flag == 0){ pwd.type = 'text' eye.src = 'icon/mimaxianshi.svg' flag = 1 }else{ pwd.type = 'password' eye.src = 'icon/bukejian.svg' flag = 0 } } } -
修改样式属性
修改元素大小、颜色、位置等属性
-
element.style 行内样式操作 适合样式较少的情况
var div = document.querySelector('div') div.onclick = function(){ //element.style里面的属性采用驼峰命名法 this.style.backgroundColor='purple' this.style.width='250px' }注意:
- Js里面的样式采取驼峰命名法,比如fontSize、backgroundColor
- Js修改style样式操作,产生的是行内样式,css权重比较高
-
案例1 循环精灵图
-
案例2 显示隐藏文本框内容
<input type='text' value='手机'> var text = document.querySelector('input') text.onfocus = function(){ if(this.value === '手机'){ this.value = '' } //获得焦点文字要加深 this.style.color = 'darkblack' } text.onblur = function(){ if(this.value === ''){ this.value === '手机' } //失去焦点颜色变浅色 this.style.color = 'grey' } -
element.className 类名样式操作 适合样式较多的情况
<div>文本</div> .change{ background-color:red; color:#fff; font-size=25px; } var test =document.query('div') test.onmouseover=function(){ this.className = 'change' }className操作会覆盖原来的类名,如果需要保留原来的类名:
this.className = '原来的类名 '
-
-
案例:百度换肤效果
var imgs = document.querySelector('.baidu').querySelectorAll('img') for (var i =0;i<imgs.length;i++){ img[i].onclick=function(){ document.body.style.backGroundImage = 'url('+this.src+')' } }
10.4 自定义属性操作
比如用户自己添加的用于标号的index属性
<div getTime='20'></div>
var div = document.querySelector('div')
console.log(div.getTime) //undefined 无法获取
console.log(div.getAttribute('getTime')) //20
-
获取属性值
element.属性获取的是元素内置的属性值element.getAttribute('属性')还可以获取程序员自定义的属性
-
修改自定义属性
-
element.属性='值'设置内置属性值 -
element.setAttribute('属性','值')还可以设置自定义属性 -
移出自定义属性
element.removeAttribute('属性')
-
案例:tab栏切换
核心思想:给上面的tab选项卡添加自定义属性,属性值从0开始编号
-
H5自定义属性
自定义属性目的:为了保存并使用数据。有些数据可以保存到页面中而不用保存到数据中
- H5规定自定义属性data-开头作为属性名并且赋值
- 例如
<div data-index = '1'></div>
- 例如
- 或者自己手动添加
element.setAttribute('data-index',1)
- 获取H5自定义属性
- 兼容性获取
element.getAttribute('data-属性名') - H5新增
element.dataset.属性名或者element.dataset['属性名']
- 兼容性获取
- H5规定自定义属性data-开头作为属性名并且赋值
10.5 节点操作
利用节点层级关系获取元素
-
页面中所有元素都是节点,一般节点至少拥有:
-
nodeType(节点类型)
-
元素节点 nodeType = 1
元素节点是HTML标签元素,元素节点主要提供了对元素标签名、子节点及属性的访问
-
属性节点 nodeType = 2
-
文本节点 nodeType = 3
文本结点就是元素起始标签和闭合标签内的不加其他标签修饰的文本内容 ,文本节点包含文字、空格、换行
-
实际操作主要操作元素节点
-
-
nodeName(节点名称)
-
nodeValue(节点值)
-
-
父级节点
node.parentNode得到的是离元素最近的父级节点,找不到返回null<div class='box1'> <div class = 'box2'></div> </div> var box2 = document.querySelector('box2') console.log(box2.parentNode) //即box1 -
子节点
parentNode.childNodes返回包含指定节点的子节点(包含元素节点、文本节点等等)集合,该集合为即时更新的集合如果只想要获得里面的元素节点,则需要专门处理,所以我们一般不提倡使用childNotes
var ul = document.querySelector('ul'){ for(var i =0;i<ul.childNodes.length;i++){ if(ul.childNodes[i].nodeType == 1){ console.log(ul.childNodes[i]) } } console.log(ul.children) }-
children 获取所有的子元素节点 也是实际开发常用的
-
parentNode.firstChild返回第一个子节点 不管是文本节点还是元素节点找不到返回null<ol> <li>1</li> <li>2</li> </ol> //一共6个节点 从上往下 1换行 2元素节点-li 3文本节点 4元素节点-li 5文本节点 6换行 var ol = document.querySelector('ol') console.log(ol.firstChild) //这里输出的是文本节点-换行 console.log(ol.lastChild) //还是文本节点换行parentNode.firstElement返回第一个元素节点 ie兼容性不好
-
parentNode.lastChild返回最后一个子节点 找不到返回nullparentNode.lastElement返回最后一个元素节点
-
实际开发写法:既没有兼容性问题又仅返回第一个子元素(不包含文本节点)
console.log(ol.children[0]) console.log(ol.children.length - 1)
-
-
兄弟节点
-
node.nextStibling下一个兄弟节点 包含元素节点和文本节点
-
node.previousSibling上一个兄弟节点 包含元素节点和文本节点
-
node.nextElementSibling返回当前元素下一个兄弟元素节点 找不到返回null
-
node.previousElementSibling返回当前元素上一个兄弟元素节点 找不到返回null
-
-
创建节点
-
document.createElement('tagName')创建元素节点创建由tagName指定的HTML元素。因为这些元素原先不存在 ,是根据我们的需求动态生成的,所以我们也成为动态创建元素节点
-
element.innerHTML主要创建文本节点也可以将创建标签元素
div.innerHTML = '<a href='#'>百度</a>' -
document.write(了解)直接将内容写入页面的内容流,但是文档流执行完毕,他会会导致页面全部重绘
-
document.createElement('tagName')和element.innerHTL区别- innerHTML 创建多个元素效率更高(但是最好不要拼接字符串,采用数组形式拼接) 结构稍微复杂
- createElement() 创建多个元素效率稍微低一点点,但是结构更清晰
- 不同浏览器下,innerHTML效率要比createElement高
-
-
添加节点
-
node(父级).appendChild(child)将一个节点添加到指定父节点的子节点列表末尾。类似after伪元素
<ul> <li>123</li> </ul> var li = document.createElement('li') var ul = document.queryselector('ul') ul.appendChild(li) -
node.insertBefore(child,指定元素)将一个节点添加到父节点的指定子节点前面,类似于before伪元素
<ul> <li>123</li> </ul> var li = document.createElement('li') var ul = document.queryselector('ul') ul.insertBefore(li,ul.children[0]) -
案例 简单版发布留言
var btn = document.querySelector('button') var text = document.querySelector('textarea') var ul = document.querySelector('ul') btn.onclick = function(){ if(text.value == ''){ alert('您没有输入内容') return false }else{ var li = document.createElement('li') //添加文本并且添加删除功能 li.innerHTML = text.value+'<a href='javascript:;'>删除<' //倒序添加 最新添加的在最上方 ul.insertBefore(li,ul.children[0]) //删除元素 删除的是a标签对应的父元素li标签 var as = document.querySelectorAll('a') for(var i =0;i<as.length;i++){ as[i].onclick = function(){ ul.removeChild(this.parentNode) } } } }
-
-
删除节点
-
node.removeChild(child)<button>按钮</button> <ul> <li>1</li> <li>2</li> </ul> btn.onclick=function(){ if(ul.children.length == 0){ //删除按钮失效 this.disabled = true }else{ var ul = document.querySelector('ul') ul.removeChild(ul.children[0]) } }
-
-
复制节点
-
node.cloneNode()- 如果括号参数为空或者false,则为浅拷贝,只克隆节点本身,不克隆里面的子节点
- 括号里为true,深拷贝,复制节点并且复制里面的内容
<ul> <li>1</li> <li>2</li> <li>3</li> </ul> var ul = document.querySelector('ul') //克隆第一个元素 var clone_li = ul.children[0].cloneNode(true) ul.appendChild(clone_li)
-
-
案例 动态生成单元格
<tbody></tbody> //添加进去的数据 var datas = [ { name:'豹子头', sex: '男', age:35 }, { name:'玉麒麟', sex: '男', age:36 }, { name:'黑旋风', sex: '男', age:33 }, ] var tbody = document.querySelector('tbody') for(var i = 0;i<datas.length;i++){ var tr = document.createElement('tr') tbody.appendChild(tr) //遍历添加数组里面每一个对象里面的属性 for(var key in datas[i]){ //创建单元格并填充数据 var td = document.createElement('td') //key得到的是属性名 datas[i][key]得到的是属性值 td.innerHTML = datas[i][key] tr.appendChild(td) } //创建显示删除两个字的单元格 var td = document.createElement('td') td.innerHTML = '<a href="javascript:;>删除</a>' tr.appendChild(td) } //删除功能 var as = document.querySelector('a') for(var i = 0;i<as.length;i++){ as[i].onclick = function(){ // 点击a 删除当前a所在的行(父元素) tbody.removeChild(this.parentNode.parentNode) } }
10.6 事件高级
-
注册事件 (绑定事件)
-
传统注册方式
-
利用on开头的事件,比如onclick onmouseover
-
注册事件的唯一性。同一个元素同一个事件只能设置一个处理函数,最后处理注册的处理函数将会覆盖前面注册的处理函数
-
-
方法监听注册方式
-
addEventListener()
-
同一元素同一事件可以注册多个监听器,按注册顺序依次执行
-
-
addEventListener
eventTarget.addEventListener(type,listener,useCapture)-
将指定的监听器注册到eventTarget(目标对象)上,当该对象触发指定事件时,就会执行事件处理函数
-
type:事件类型字符串,比如’click‘ ’mouseover‘ 注意不要带on,一定要是字符串
-
listener:事件处理函数 事件发生时会调用该监听函数
-
useCapture: 可选参数,是一个布尔值
默认为false,处于冒泡阶段
如果为true则处于捕获阶段
-
-
-
删除事件 (解绑事件)
-
传统删除方式
eventTarget.onclick = null
-
方法监听注册删除方式
-
eventTarget.removeEventListener(type,listener,useCapture)var div = document.querySelector('div') div.addEventListener('click',fn)//里面的fn不需要调用小括号 function fn(){ div.removeEventListener('click',fn) //删除click事件 }
-
-
-
DOM事件流
- 事件发生时会在元素节点之间按照特定的顺序传播,这个传播的过程就是DOM事件流
- DOM事件流分为三个阶段
- 捕获阶段
- 当前目标阶段
- 冒泡阶段
- 事件捕获:由DOM最顶层节点开始,然后逐级向下传播到具体元素的接收过程
- 事件冒泡:由具体元素接收,然后逐级向上传播到DOM最顶层节点的过程
- JS代码只能执行捕获或者冒泡其中一个阶段
- 传统事件例如onclick只能得到冒泡阶段
- 有些事件没有冒泡,比如onblur、onfocus、onmouseenter、onmouseleave
-
事件对象
var div = document.querySelector('div') div.onclick = function(event){}这里的event就是一个事件对象,写到我们侦听函数的小括号里面,当作形参来看
-
事件对象只有有了事件才会存在
-
事件对象是我们事件一系列相关数据的集合 跟事件相关的
比如鼠标点击里面就包含了鼠标的相关信息
比如键盘事件就包含了键盘事件的信息,比如判断用户按下了哪个键
-
这个事件对象可以自己命名,推荐使用event、evt、e
-
事件对象的常见属性和方法
-
e.target和this的区别-
e.target 返回的是触发事件的对象(元素)
-
this 返回的事绑定事件的对象(元素)
<ul> <li>123</li> <li>456</li> </ul> var ul = document.querySelector ul.addEventListener('click',function(e){ //我们这里绑定的是ul 所以this指向ul 写死了固定是ul console.log(this) //ul //但是由于冒泡 当我们点击li的时候也会触发ul console.log(e.target) //li //因为由li触发,所以指向li 但是如果我们不点击li e,target便不会指向li })e.target 点击了哪个元素就指向那个元素
this 哪个元素绑定了该事件就指向谁
-
-
阻止默认行为(事件)
比如让链接不跳转 让提交按钮不提交
-
e.preventDefaultvar a = document.querySelector('a') a.addEventListener('click',function(){ e.preventDefault() //这样点击a超链接就不会再跳转 //或者 return false })
-
-
阻止事件冒泡
事件冒泡是逐级由具体元素向DOM最顶层节点传播
-
e.stopPropagation这样触发子元素就不会引起父元素相应事件的触发
-
-
事件委托(代理、委派)
不是给每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点
例如:当我们点击每一个li元素时都会修改背景颜色
<ul> <li>1</li> <li>2</li> <li>3</li> </ul> //这时我们只需要给父元素绑定监听器 每一个li被点击后会触发到父元素 var ul = document.querySelector('ul') ul.addEventListener('click',function(e){ e.target.style.backgroundColor = 'red' })
-
-
-
常用鼠标事件
-
禁止鼠标右键
-
contextmenu用于控制右键上下文菜单 -
实现方法:
//在js代码首部添加 document.addEventListener('contextmenu',function(e){ e.preventDefault })
-
-
禁止鼠标选中
-
selectstar开始选中 -
实现方法:
//在js代码首部添加 document.addEventListener('selectstart',function(e){ e.preventDefault })
-
-
鼠标事件对象
document.addEventListener('click',function(e){ console.log(e.clientX) console.loh(e.clientY) console.log(e.pageX) console.log(e.pageY) }) //或者用传统注册事件方式 document.onclick = function(){ console.log(e.clientX) console.loh(e.clientY) console.log(e.pageX) console.log(e.pageY) }clientX和clientY返回的是鼠标相对与可视框的相对距离 不随滚动条改变pageX和pageY返回的是相对于文档页面的坐标- 设置相关案例时不要忘记单位px
img.style.left=x+'px'
-
-
常用键盘事件
-
//document.onkeyup = function(){} 也行 但是要习惯用方法监听注册方法 document.addEventListener('keyup',function(e){ console.log(+e.key+'键盘被松开') }) document.addEventListener('keydown',function(){ console.log(+e.key+'键盘被按下') }) -
三个事件执行顺序:keydown--keypress-keyup
keydown和keypress在文本框的特点:这两个事件触发时,文字还没有落入文本框中,keyup事件触发的时候,文字已经落入文本框了,实在不会keyup和keydown来回交替调试
-
键盘事件对象
key返回该键keyCode返回该键的ascll码值//document.onkeyup = function(){} 也行 但是要习惯用方法监听注册方法 document.addEventListener('keyup',function(e){ console.log(e.key+'键盘被松开') console.log('ascll码为:'+e.keyCode) })-
keyup和keydown不区分字母大小写 a和A都返回65 -
keypress区分大小写 a返回97 A返回65 -
案例1 京东按键输入内容
核心思路:检测用户是否按下了s键,如果按下s键,就把光标定位到搜索框
<input type='text'></input> var search = document.querySelector('input') document.addEventListener('keyup',function(e){ if(e.keyCode == 83){ //focus()方法自动获取焦点 search.focus() } })注意:这里不用keydown是因为keydown会输入进去s
案例二 京东快递输入单号自动放大效果
<div class='search'> <div class='con'>123</div> <input type='text' placeholder='请输入单号' class='jd'> </div> .con{ font-size: 24px; display:none } var con = document.querySelector('.con') var jd_input = document.querySelector('.jd') jd_input.addEventListener('keyup',function(){ if(this.value == ''){ con.style.display = 'none' }else{ con.style.display = 'block' con.innerText = this.value } }) //失去焦点就隐藏盒子 blur方法 jd_input.addEventListener('blur',function(){ con.style.display = 'none' }) //获得焦点就显示盒子 focus方法 jd_input.addEventListener('focus',function(){ con.style.display = 'block' })
-
-
11 BOM对象
11.1 BOM概述
-
浏览器对象模型,提供了独立于内容而与浏览器窗口进行交互的对象,核心对象是
window -
-
BOM包含DOM,DOM操作指令开头其实省略了
window. -
文档加载事件
-
window.onclick=function(){}window.addEventListener('onclick',function(){ })是窗口加载事件,当文档内容(包括样式表、图片、flash等等)全部加载完毕才会触发该事件
window.onload传统注册事件只能写一次 -
document.addEventListener('DOMContentLoaded',function())仅当DOM加载完成就触发,不包括样式表、图片、flash等等 加载速度比onload快
-
-
调整窗口大小事件
window.onresize=function(){}window.addEventListener('resize',function(){ })- 只要窗口大小发生变化,就会触发
- 经常用来完成响应式布局
window.innerWidth获取当前屏幕的宽度
11.2 定时器
-
设置定时器
-
setTimeout()-
setTimeout(回调函数,[延迟毫秒数])回调函数-callback 回调函数就是干完一件事后再回头调用的意思
-
延迟毫秒数可以省略,默认为0 单位为ms
function callback(){ console.log('boom') } setTimeout(callback,3000) //等于 setTimeout(function(){ console.log('boom') },3000) -
-
setIntervalsetInterval(回调函数,[间隔毫秒数]) -
倒计时案例
<div> <span class='day'></span> <span>:</span> <span class='hour'></span> <span>:</span> <span class='minute'></span> <span>:</span> <span class='second'></span> </div> var day = document.querySelector('.day') var hour = document.querySelector('.hour') var minute = document.querySelector('.minute') var second = document.querySelector('.second') var inputTime = +new Date('2022-12-30 08:08:08') countDown() //提前调用一次 防止页面有空白 function countDown(){ var nowTime = +new Date() var times = (inputTime - nowTime)/1000; var d = parseInt(times/60/60/24) d = d < 10 ? '0' + d +'天' : d +'天' day.innerHTML = d var h = parseInt(times/60/60%24) h = h < 10 ? '0' + h + '小时' : h +'小时' hour.innerHTML = h var m = parseInt(times/60%60) m = m < 10 ? '0' + m + '分钟': m +'分钟' minute.innerHTML = m var s = parseInt(times%60) s = s < 10 ? '0' + s + '秒': s + '秒' second.innerHTML = s } //开启定时器 setInterval(countDown,1000)//这里设置为1秒 每隔一秒执行一次重点:提前调用一次,防止页面有空白
-
-
停止计时器
- 停止
setTimeout()定时器
clearTimeout(定时器标识符)<button>按钮</button> var btn = document.querySelector('button') var timer = setTimeout(function(){ //timer就是该定时器的标识符 console.log('1') },5000) btn.addEventListener('click',function(){ clearTimeout(timer) })-
停止
setInterval()定时器clearInterval(定时器标识符)
<button class='begin'>按钮</button> <button class='stop'>按钮</button> var begin = document.querySelector('.begin') var stop = document.querySelector('.stop') //利用全局变量解决函数访问局部变量的问题 var timer = null //全局变量 begin.addEventListener('click',function(){ timer = setInterval(function(){ console.log('nihao') },1000) }) stop.adddEventListener('click',function(){ clearInterval(timer) })这里对于局部定时器标识符的访问要理解
- 停止
-
发送短信案例
手机号码: <input type = 'number'> <button>发送</button> var btn = document.querySelector('button') var time = 10;//定义等待秒数 btn.addEventListener('click',function(){ btn.disabled = true vat timer = setInterval(function(){ if(time == 0){ //清楚定时器和禁用效果 clearInterval(timer) btn.disabled = false btn.innerHTML = '发送' }else{ btn.innerHTL = '还剩下'+time+'秒' time-- } }) })
11.3 Location对象
-
window对象提供了一个用于获取或设置窗体的URL功能的对象
-
URL 统一资源定位符
-
location对象属性
-
案例:5秒后跳转页面
<div></div> var div = document.querySelector('div') btn.addEventListener('click',function(){ location.href = 'baidu.com' }) var timer = 5 setInterval(function(){ if(timer == 0){ loaction.href = 'www.baidu.com' }else{ div.innerHTML = '将在'+timer+'秒钟之后跳转到首页' } },1000) -
获取URL参数
location.search案例:跨页面获取
//login.html <from action='index.html'> 用户名: <input type='text' name='user_name'> <input type = 'submit' value='登陆'> </form> //index.html ?user_name=curry //1 先去掉? var params = location.search.substr(1); //user_nae=curry //2 利用=把字符串分割为数组 var arr = params.split('=') //arr = ['user_name','curry'] //3 把数据写入div中 var div = document.querySelector('div') div.innerHTML=arr[1]+'欢迎你' -
location常见方法
location.assign(新页面网址)重定向到新的页面 记录历史location.replace()替换当前页面地址 不记录历史不可以后退页面location.reload()重新加载页面 相当于刷新页面或者f5 如果参数为true 等于强制刷新ctrl+5
-
navigator对象
navigator对象包含有关浏览器的信息,有很多属性,最常用的是userAgent,该属性可以返回由客户机发送服务器的user-agent头部的值 -
history对象
- back() 可以后退功能
- forward() 前进功能
- go(参数) 前进后退功能 参数如果是1前进1个页面 如果是-1 后退1个页面
12 补充
12.1 this指向问题
一般情况下this最终指向的是那个调用它的对象
-
全局作用域或者普通函数this指向全局对象window (定时器里的this也指向window)
console.log(this) //window function fn(){ console.log(this) //window } setTimeout(function(){ console.log(this) //window },1000)//window.setTimeout -
方法调用中谁调用this指向谁
var obj = { sayHi :function(){ console.log(this) } } obj.sayHi() //obj var btn = document.querySelector('button') btn.onclick = function(){ console.log(this) //btn } -
构造函数中this指向构造函数的实例
function fun(){ console.log(this) } var fun1 = new fun();//指向fun1
12.2 JS执行队列
-
JS是单线程语言,同一时间只能做一件事
console.log(1) setTimeout(function(){ console.log(2) },5000) console.log(3)按同步的执行顺序:首先输出1,5秒后输出2,再执行输出3
但是实际的输出顺序是:1->3->2
12.3 异步
-
在处理一件很长时间的事情时同时处理其他事情
-
同步任务:同步任务都在主线程上执行,形成一个执行栈
-
异步任务:通过回调函数完成
- 异步任务有以下三种类型
- 普通事件 如click、resize
- 资源加载 如load、error
- 定时器,包括setInterval、setTimeout
- 异步任务相关回调函数添加到任务队列
- 异步任务有以下三种类型
-
实际上Js是先执行栈中的同步任务,遇到异步任务会将其添加到任务队列中,执行完之后再去执行任务队列里的异步任务,只不过处理时间都非常短,所以看起来同步和异步会一起执行
12.4 offset 系列
-
注意:返回不带单位的数值
-
案例 获取鼠标在盒子中的坐标(不是在页面中的坐标)
-
我们在盒子内点击,要得到鼠标距离盒子左右的距离
-
首先得到鼠标在页面中的坐标(e.pagex,e.pagey)
-
其次得到盒子在页面中的距离(box.offsetLeft,box.offsetTop)
-
用鼠标距离页面的距离-盒子在页面的距离,得到鼠标在盒子内的坐标
<div class='box'></div> .box{ width:300px; height:300px; background-color:red } var box = docuent.querySelector('.box') //鼠标事件用mouseover box.addEventListener('mouseover',function(){ var x = e.pageX - this.offsetLeft var y = e.pageY - this.offsetTop this.innerHTML='x坐标:'+x+'px '+'y坐标:'+y+'px' })
-
-
12.5 client系列
动态获得元素的边框大小、元素大小
-
立即执行函数
不需要调用,立马能够执行
-
(function(形参){})(实参) -
(function(形参){}(实参)) -
立即函数结束要加;
-
立即执行函数最大的作用是独立的创建了一个作用域
-
淘宝flexible.js
<script> (function flexible(window, document) { // 获取html的根元素 var docEl = document.documentElement // dpr 是物理像素比 var dpr = window.devicePixelRatio || 1 // adjust body font size 设置body的字体大小 function setBodyFontSize() { // 如果页面中有body这个元素,就设置body的字体大小 if (document.body) { document.body.style.fontSize = (12 * dpr) + 'px' } else { // 就是在引入时没有加载到body // 如果页面中没有body这个元素,则等着页面的主要DOM元素加载完毕再去设置body的字体大小 document.addEventListener('DOMContentLoaded', setBodyFontSize) } } setBodyFontSize(); // set 1rem = viewWidth / 10 (自己划分rem) 设置html元素的文字大小 function setRemUnit() { var rem = docEl.clientWidth / 10 docEl.style.fontSize = rem + 'px' } setRemUnit() // reset rem unit on page resize 当页面尺寸大小发生变化的时候,要重新设置下rem的大小 window.addEventListener('resize', setRemUnit) // pageshow 是重新加载页面触发的事件 window.addEventListener('pageshow', function(e) { // e.persisted 返回的是true,就是说如果这个页面是从缓存取过来的页面,也需要重新计算一下rem的大小 if (e.persisted) { setRemUnit() } }) // detect 0.5px supports 有些移动端的浏览器不支持0.5像素的写法 if (dpr >= 2) { var fakeBody = document.createElement('body') var testElement = document.createElement('div') testElement.style.border = '.5px solid transparent' fakeBody.appendChild(testElement) docEl.appendChild(fakeBody) if (testElement.offsetHeight === 1) { docEl.classList.add('hairlines') } docEl.removeChild(fakeBody) } }(window, document)) </script>
12.6 scroll系列
返回元素的大小 滚动距离
var div = querySelector('div') div.addEventListener('scroll',function(){ console.log(div.scrollTop) })仿淘宝侧边栏效果:
-
核心原理:
-
需要用到的页面滚动事件
scroll,所以事件源是document -
滚动到banner位置,就将侧边栏设置为固定定位
-
滚动到main位置时,侧边栏添加回到首部功能
-
页面被卷去的头部:
window.pageYOffset左侧:window.pageXOffset元素被卷去的头部element.scrollTop
-
-
-
-
三大系列总结
12.6 mouseover和mouseenter的区别
12.7 简单动画函数封装
//简单动画函数封装obj目标对象 target 目标位置
function animate(obj,target){
//先清除以前的定时器
clearInterval(obj.timer)
//给不同函数添加不同定时器
obj.timer = setInterval(function(){
if(obj.offsetLeft>= target){
//停止动画 本质是停止定时器
clearInterval(obj.timer)
}
//注意 元素必须开启定位才有left属性
obj.style.left = obj.offsetLeft + 1 +`px`
},1000)
}
var div = document.querySelector('div')
animate(div,400)
-
动画函数给不同函数添加不同定时器
如果多个元素都使用这个动画函数,每次都要var声明定时器,我们可以给不同的元素使用不同的定时器(自己专门用自己的定时器)
核心原理:利用js是一门动态语言 可以很方便的给当前对象添加属性
方法:
obj.timer = setInterval(function(){},1000) -
给元素只设置一个定时器
clearInterval(obj.timer) obj.timer = setInterval(function(){},1000) -
缓动动画原理
核心算法:
(目标值-现在的位置)/10作为每次移动的距离步长停止条件:到达目标位置就停止定时器
function animate(obj,target,callback){ //先清除以前的定时器 clearInterval(obj.timer) //给不同函数添加不同定时器 obj.timer = setInterval(function(){ //步长公式:(目标值-现在的位置)/10 var step = (target-obj.offsetLeft)/10 //把步长改为整数,不要出现小数问题 step = step > 0 ? Math.ceil(step):Math.floor(step) if(obj.offsetLeft>= target){ //停止动画 本质是停止定时器 clearInterval(obj.timer) //如果有回调函数传进来执行回调函数 //if(callback){ // callback() //} callback &&callback() } //注意 元素必须开启定位才有left属性 obj.style.left = obj.offsetLeft + step +`px` },1000) }
12.8 节流阀
防止轮播图按钮连续点击造成播放过快
节流阀目的:当上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法连续触发
核心实现思路:
-
利用回调函数,添加一个变量来控制,锁住函数和解锁函数
-
开始设置一个变量 var flag = true
-
if(flag){flag = false;do something} 关闭水龙头
-
利用回调函数 动画执行完毕 flag = true 打开水龙头
-
缓慢返回顶部
-
可以用a标签实现
-
可以用ui插件返回顶部按钮
-
用js:
- 滚动窗口至文档中的特定位置
window.scroll(x,y) - 注意,里面的x和y不跟单位 直接写数字
- 页面滚动多少用
window.pageYOffset得到
//把左右相关的改为上下相关的 function animate(obj,target,callback){ //先清除以前的定时器 clearInterval(obj.timer) //给不同函数添加不同定时器 obj.timer = setInterval(function(){ //步长公式:(目标值-现在的位置)/10 var step = (target-window.pageYOffset)/10 //把步长改为整数,不要出现小数问题 step = step > 0 ? Math.ceil(step):Math.floor(step) if(window.pageYOffset>= target){ //停止动画 本质是停止定时器 clearInterval(obj.timer) //如果有回调函数传进来执行回调函数 //if(callback){ // callback() //} callback &&callback() } //注意 元素必须开启定位才有left属性 //obj.style.left = obj.offsetLeft + step +`px` window.scroll(0,window.pageYOffset + step) },1000) } var btn = document.querySelector('btn') btn.addEventListener('click',function(){ //因为是窗口滚动 所以对象是window animate(window,0) }) - 滚动窗口至文档中的特定位置
-
13 本地存储
-
特性:
- 数据存储在用户浏览器中
- 设置、读取方便、甚至页面刷新不丢失数据
- 容量较大,sessionStorage约5M、localStorage约20M
- 只能存储字符串,可以将对象
JSON.stringify()编码后存储
-
window.sessionStorage-
生命周期:浏览器打开到浏览器关闭
-
在同一个窗口(页面)下数据可以共享 不可以同一浏览器共享
-
以键值对的形式存储
-
存储数据:
sessionStorage.setItem(key,value)
-
获取数据
sessionStorage.getItem(key)
-
删除数据
sessionStorage.removeItem(key)
-
删除所有数据
sessionStorage.clear() 不用写参数
<input type='text'> <button class='set'>存储数据</button> <button class='get'>获取数据</button> <button class='remove'>删除数据</button> <button class='del'>清空数据</button> var ipt = document.querySelector('input') var set = document.querySelector('.set') var get = document.querySelector('.get') var remove = document.querySelector('.remove') var del = document.querySelector('.del') set.addEventListener('click',function(){ //点击之后 将表单里的数据存储起来 var val = ipt.value sessionStorage.setItem('uname',val) //可以在chrome控制台application-Storage-Session Storage看到 }) get.addEventListener('click',function(){ //点击之后 将表单里的数据获取 sessionStorage.getItem('uname') }) remove.addEventListener('click',function(){ //点击之后 将表单里的数据删除 sessionStorage.removeItem('uname') }) del.ddEventListener('click',function(){ //点击之后 将表单里的数据全部删除 sessionStorage.clear() })
-
-
window.localStorage-
生命周期是永久,除非手动删除,否则页面也会存在
-
可以多窗口(页面)共享(同一浏览器可以共享)
-
以键值对的形式存储使用
-
只能存储字符串的数据格式
var todolist=[{ title:'11', done:'false' },{ title:'22'. done:'false' }] //把数组对象转换为字符串格式 localStorage.setItem('todo',JSON.stringify(todolist)) //取出来也是字符串格式 获取本地数据需要转换为数组对象 var data = localStorage.getItem('todo') //字符串格式转换为对象格式JSON.parse() data = JSON.parse(data) -
存储数据:
localStorage.setItem(key,value)
-
获取数据
localStorage.getItem(key)
-
删除数据
localStorage.removeItem(key)
-
删除所有数据
localStorage.clear() 不用写参数
-
-
记住用户名案例
-
案例分析:
- 把数据存起来,用到本地存储
- 关闭页面,也可以显示用户名,所以用到localStorage
- 打开页面,先判断是否有这个用户名,如果有,就在表单里面显示用户名,并且勾选复选框
- 当复选框发生改变时change事件
- 如果勾选就存储,否则就删除
<input type='text' id='username'><input type='checkbox' name='' id='remember'>记住用户名 var username = document.querySelector('#username') var remember = document.querySelector('#remember') //如果之前有存储数据则自动输入 if(localStorage.getItem('username')){ username.value = localStorage.getItem('username') remember.checked = true } //如果勾选记住用户名则存储数据 remember.addEventListener('change',function(){ if(this.checked){ localStorage.setItem('username',username.value) }else{ localStorage.removeItem('username') } })
-