目录
JS语言
JS即JavaScript是一门 基于对象 和 事件驱动 的 脚本语言 ,通常用来提高网页与用户的交互性。
- 基于对象:它不仅可以创建对象,也能使用现有的对象。JS没有类的概念,也没有编译的过程。是一边解释一边执行。
- 事件驱动:在JS中,大部分情况下都是通过事件触发驱动函数执行的,从而实现特定的功能。(比如点击div将内容替换为时间、当鼠标滑过元素,元素就有翻转的动态。)
- 脚本语言:在网络前端开发环境下,用于嵌入在客户端浏览器中的一段小程序。
JS由三个部分组成
- bom(brower object Model):js操作浏览器发生变化的属性和方法
- dom(document object model):js操作文档流发生变化的属性和方法
- ecmascript:js的书写语法和书写规则
JS特点
- JS是一门直译式的语言,直接执行的就是源代码.
- 是一边解释一边执行,没有编译的过程(不像Java需要提前编译为class文件再运行).
- JS是一门弱类型的语言,没有严格的数据类型.
JS的作用:用ecmascript语法去操作浏览器发生一些变化,用ecmascript语法去操作文档流去发生一些变化
JS代码的书写位置
- 行内式
- 内嵌式
- 外链式
行内式
解释:直接把代码书写在标签身上
书写时标签分为2类
a标签:将js代码书写在href属性上
<body>
<a href="javascript:alert('hello world');">点我一下</a>
</body>
非a标签:将js代码书写在标签的行为属性上
<body>
<div onclick="alert('hello world');">点我一下</div>
</body>
内嵌式
解释:把代码书写在一个script标签对内
<body>
</body>
<script>
//打印提示窗口
alert('hello world');/* 加不加分号都行 */
</script>
外链式
把js代码写在一个.js的文件内,在这个文件内直接写我们需要执行的代码就可以了
<script src="test.js"></script>
src:引入所要加入的js文件地址
<body>
<!-- html文件 -->
<script src="test.js"></script><!-- 放哪都可以执行,执行优先级head高于body -->
</body>
/* test.js文件内 */
alert('hello world');
关于内嵌标签与外链标签
- 内嵌式与外链式标签,不需要任何依赖行为,打开页面就会执行
- 内嵌与外链式标签在页面里面可以引入多个
- 内嵌与外链式标签标签放在页面哪里都可以
JS注释
单行注释://
多行注释:/*内容*/
JS定义变量
变量:在程序的运行过程中,保存一个中间值使用
定义变量的关键字
声明提前(预解析):声明的变量会被提升到作用域顶部,并被赋值为undefinded(即使在下面赋值,被声明提前到上面也是undefinded)
- const:支持块级以及函数作用域概念、不可被声明提前,不可重复声明,声明时必须赋值,这个值不能被改变
- let:支持块级以及函数作用域概念,不可被声明提前,不可重复声明,赋值可以多次赋值而且可以赋值任意类型
- var:忽视块级作用域(不忽视函数作用域)会被声明提前,可以重复定义及赋值,而且赋值可以是任意类型
var a,num; num=10;
var num=10;
var a,num=10;
变量的书写
- 变量由字母、数字、下划线、$组成
- 不能以数字开头
- 严格区分大小写
- 不能使用关键字——js里面有特殊意义的单词
JS作用域
作用域按照范围分
- 全局作用域:一个页面就是一个全局作用域
- 私有作用域:只有函数生成私有作用域
作用域的访问:自己用自己的,自己没有的用父级作用域的,以此类推。
作用域按照类型分
- 块级作用域:任何一对{}中的语句集都属于一个块,在这之中定义的所有变量在代码外都是不可见的,我们称之为块级作用域,比如if(){}、for(){}的{}都是块级作用域
- 函数作用域:function(){}的形式等函数中的参数和变量在外部是不可见的,{}就是函数作用域
JS的数据类型
- 基本数据类型
- 引用数据类型
基本数据类型
数值类型(number)
包含10进制数字、科学计数法、其他进制表示方式的数字
字符串类型(string)
在js内一切以单引号/双引号包裹的内容,就是字符串内容
注意:在js中不区分单引号和双引号
布尔类型(boolean)
var a=true;——真
var b=false;——假、默认
空类型
undefined:当一个变量定义但没赋值的时候,那么就是undefined,表示没有值
var b;
null:表示有值,有一个空值
var b=null;
引用数据类型
函数、数组、对象(自定义对象、内置对象、Dom对象、Bom对象)
检测变量的数据类型
关键字:typeof
语法:typeof 要检测的变量;
结果:该变量储存数据的数据类型
<script>
var n1=null
var result=typeof n1
/* 打印语句 */
console.log(result)
//注意,mull类型返回的数值类型为object类型,比较特殊
</script>
数据类型转换
转数值
把其他类型转化成数值类型
语法:Number(要转换的内容);
语法:parseInt(要转换的内容);
语法:parseFloat(要转换的内容);
结果:转好数值类型的结果
Number解析规则: 把转换的内容一位一位的查看,若出现不是合法数字的字符则直接出现NAN
parseInt解析规则:把转换的内容一位一位的查看只有第一位就不是合法数字的时候会出现NAN否则就是把前面的数字位置内容保留,不是数字位置舍弃
parseFloat解析规则:和parseInt一样只不过parseInt只能解析整数部分(小数部分舍去),而parseFloat能解析到小数部分
<script>
var n1='100abc'
var result=parseInt(n1)//number
console.log(typeof(result))//100
console.log(result)/* 结果为100,number函数为nan */
</script>
转数值可能出现
- NaN:not a number、整体不能转化成一个合法数字
- Infinity:正2无穷大
- -Infinity:负无穷大
转字符串
把其他类型转化成字符串类型
语法:String(要转换的内容)
语法:要转换的内容.toString()
结果:转好的字符串类型的结果
转布尔
把其他数据类型转化成布尔类型
语法:Boolean(要转换的内容)
结果:转换好的布尔值
注意:在js中共5个值会被转换为false,分别为:0、NAN、‘’、undefined、null
JS的运算符
算数运算符:进行数学运算的符号
+:进行加法运算
- 当符号两边都是数字或布尔的时候,会进行数学运算(true为1,false为0)
- 只要符号任意一边是字符串的时候,就会进行字符串拼接
-:进行减法运算
*:进行乘法运算
/:进行除法运算
%:进行取余运算
赋值运算符:进行赋值操作的符号
=:进行赋值操作
+=:加等于运算符
-=:减等于运算符
*=:乘等于运算符
/=:除等于运算符
%=:取余等于运算符
比较运算符:进行比较运算的符号
>:大于
<:小于
>=:大于等于
<=:小于等于
==:等于——只比较值是否相等,不考虑数据类型
===:全等于——值和数据类型都相等才算相等
!=:不等于——只要值不相等就是不等
!==:不全等——值和数据类型有任意一个不相等就算不全等
逻辑运算符:进行逻辑运算的符号
&&:与——两边都为true、结果才为true
||:或——有一个为true、结果就为true
!:非
自增自减运算符:单独对一个变量进行+1或-1操作的符号
a++:a先参与运算后加一
++a:a先加一后参与运算
a--:a先参与运算后减去一
--a:a先减一后参与运算
三目运算符:有3个操作数的运算符
表达式1 ? 表达式2 :表达式3
含义:表达式1成立,则整个表达式的结果为表达式2,否则为表达式3
JS里面的关键字
break:跳出循环
continue:结束当前循环跳到下一个循环
switch:分支选择关键字
case:switch分支选择的通道
default:switch语句默认选择项
delete:删除属性——delete 属性名
do:do……while循环的执行
while:while/do……while循环语句
if:if分支语句
else:if语句的分支选择
for:for循环
in:for……in循环
instanceof:判断左边数据是不是属于右边的数据类型,若是则返回true
<script>
//返回boolean类型,若为true说明左边属于右边类型
function fun(){
var a=arguments instanceof Array
alert(a)
}
fun()
</script>
new:创建对象关键字
this:代表本类对象的引用
var:定义变量关键字
typeof:获取变量的数据类型
function:声明方法关键字
return:方法返回关键字
void:声明没有返回值
<script>
//加了void返回值不管用
void function fun(){
var a=arguments instanceof Array
return a
}
console.log(fun())
</script>
with:对于with关键字可以基于某个对象的里面进行操作
<script>
function obj(id,name){
this.id = id;
this.name = name;
this.getName = function(){
return this.name;
}
}
var myObj = new obj(3,"three");
with(myObj){
alert(id);//提示3
alert(name);//提示three
alert(getName());//提示three
id = 4;
alert(id);//提示4
}
alert(myObj.id);//提示4,说明with中是通过引用方式访问的,而不是复制值的方式
</script>
try:配合catch进行错误判断
catch:异常捕获封装
finally:在异常三连中一定会执行的块
throw:抛出异常
async:异步的
await:和async一起使用的语法糖
class:类
static:静态的
条件分支语句
if语句
注意:
- 当条件为true时就执行后面的代码,反之跳到下一个else if或else
- ()里面写条件,{}里面写条件满足时执行的代码
<script>
var a=false
if(a==false){
console.log('a==false')
}else{
console.log('a!=false')
}
</script>
switch语句
<script>
var foot=42
switch(foot){
case 37:console.log('37号鞋子')
break
case 40:console.log('40号鞋子')
break
default:console.log('没合适的鞋子')
}
</script>
循环语句
while循环
<script>
var n=0
while(n<3){
console.log('走一个石板')
n++
}
console.log("继续走后面的路")
</script>
do……while循环
注意:代码至少会被执行一次
<script>
do{
/* 弹出浏览器提示框 */
var res=prompt("你爱不爱我?")
}while(res!=='yes')
</script>
for循环
<script>
for(var i=0;i<3;i++){
console.log('走一个石板路')
}
console.log('继续走下一个路')
</script>
JS函数
函数的定义及调用
含义:js的函数就是一个数据类型,只不过可以存储一段代码
函数定义阶段:把代码放进函数盒子里面
//声明方式一
function fn(参数列表){方法体}
//声明方式二
var fn=function(参数列表){方法体}
函数调用阶段:把盒子里面的代码执行
调用:fn(参数列表)
<script>
var fn=function(a,b){
console.log('我进函数了')
return a+b
}
alert(fn(2,3))
</script>
注意:
- 参数列表不用写类型,直接写形参(弱类型)
- 在js调用函数时,传递的参数个数如果与声明的参数个数不符,也不会报错,但不标准。
- 如果向让函数有返回值则可以加return关键字
- 函数在传参时如果传参列表内形参>实参,那么实参会按照顺序分别为形参赋值
- 在一个页面内,如果两个函数的函数名相等内容不同,则后面的函数会将前面的函数覆盖,前面的函数失去作用
- 在调用函数时浏览器每次会传入2个隐含的参数(函数的上下文对象——this、封装实参的对象——arguments)
作用域链
含义:内部函数访问外部函数的变量,采取的是链式查找的方式来决定取哪个值,这种结构我们称之为作用域链
注意:
- 只要是代码就至少有一个作用域
- 写在函数内部的作用域叫局部作用域
- 如果函数中还有函数,那么这个作用域中就又可以诞生出一个新的作用域
- 根据内部函数可以访问外部函数变量这种机制,用链式查找决定哪些数据能被内部函数访问,就称作作用域链
- 内部函数先去上一级去查找有没有该变量,若有则执行,没有再向上一级查找,以此类推,直到找到该变量进而执行,这种查找方式就称为链式查找
链式查找原则:就近原则
<script>
//全局作用域
var num=9
function fn(){//外部函数
//局部作用域
var num=10
function fn1(){//内部函数
console.log(num);
}
fn1()
}
fn()
</script>
函数的默认值
- 函数在定义的时候可以给形参设置一个默认值
- 当没有传递实参的时候,就是用默认值,当传递了实参就使用传递的值
- 普通函数可以使用,箭头函数也可以用
- 如果没有为形参设置默认值,则该形参默认值为undefined
<script>
function fn(a=100,b=200){
//声明了2个形参并赋予默认值
alert(a)
}
fn()
fn(8)//这里面给a赋值了8,赋值是顺序赋值的
</script>
函数的递归
含义:一个函数调用了自身,并设置了结束条件,这个函数才是一个正确的递归函数
<script>
let a=1
function fn(){
if(a<=10){
console.log('我是第'+a+'个')
a++
fn()
}
}
fn()
</script>
箭头函数
含义:在ES6语法中对函数表达式的简写
注意:对声明式函数不可使用
函数表达式
含义:匿名函数,也就是我们不需要定义函数直接使用的函数
<body>
<div id="a">点击</div>
<div id="b">单击</div>
</body>
<script>
//函数表达式
a.onclick=function(){alert("你点击了")}
//箭头函数
b.onclick=()=>{alert("你单击了")}
</script>
关于箭头函数
- 当箭头函数的形参只有一个的时候小括号可以省略
- 当代码只有一句话的时候大括号可以省略,并自动将这一句话的结果当作函数的返回值
- 箭头函数内没有argument
- 箭头函数内没有this,若用则this就是外部作用域的this
<script>
var obj={
f1:function(){console.log(this)},
f2:()=>{console.log(this)}
}
obj.f1()//obj
obj.f2()//window
</script>
arguments
含义:一个类数组对象,其可以通过索引来操作数据,也可以获取长度
注意:
- 在我们调用函数时,我们所传递的实参都会在arguements中保存,其长度就是我们传递实参的数量
- 我们即使不定义实参,也可以通过arguements来获取实参,只不过麻烦
- 其里面有个callee属性,这个属性对应当前正在执行的函数
<script>
function fun(){
//获取我们传递参数的数量
console.log(arguments.length)
//获取我们传递的第一个参数
console.log(arguments[0])
//获取当前正在执行的函数
console.log(arguments.callee)
}
fun("hello",666)
</script>
预解析
前言
js代码是由浏览器中的js引擎来执行的,js引擎在运行js代码时分别为2步:预解析和代码执行
预解析:js引擎会把js里面所有的var还有function提升到作用域的最前面
代码执行:按照代码的书写顺序从上往下执行
预解析分类
变量预解析
就是把所有用var修饰的变量提升到当前作用域的最前面,但不提升赋值操作
console.log(a)
var a=12;//undefined
注意:上面的变量的声明提前 ——var a;
函数预解析
就是把所有的由function声明的函数提升到当前作用域的最前面,但是不调用函数
fun()
function fun(){
console.log("hello world");
}
//hello world
var a,b,c;
function fun(){
var a=b=c=9
console.log(a);//9
console.log(b);//9
console.log(c);//9
}
fun()
console.log(a);//undefined
console.log(b);//9
console.log(c);//9
//原因:var a=b=c=9等价于var a=9;b=9;c=9
数组数据类型
前言
数组(Array):有序的数据集合
<script>
//数组声明并赋值
var arr1=[100,true,'lili']
var arr2=new Array(true,'app')
//数组先声明后赋值
var a1=[]; //var a1=new Array(); 也可以
a1=[1,'hello']; //a1=new Array(2,'hi')也可以
</script>
注意:
- JS数组可以存放任意类型的数据
- JS数组长度可以被改变,增加数组元素/改变数组长度
- 数组是有下标的,下标从0开始,依次递增
var a=[3]:数组长度为1,有3这个值
var a=new Array(3):数组长度为3,有3个空值
数组的操作
长度的操作
获取数组的长度:数组.length
修改数组长度:数组.length=n——n为数组长度
数据的操作
获取数据:数组名[索引名]
设置数据:数组名[索引名]=n
删除数据:delete 数组名[索引名]
遍历数组
<script>
//遍历数组
var arr=[1,2,3,4,5]
console.log(arr)
for (let i = 0; i < arr.length; i++) {
console.log(arr[i])
}
</script>
forin遍历
for……in语法
for(变量定义符 索引 要遍历的数组){
console.log(变量[下标])
}
<script>
var arr=[1,2,3,4]
for(var index in arr){
console.log(arr[index])
}
</script>
forof遍历
for……of语法
for(变量定义符 数组值 要遍历的数组){
console.log(value)
}
var arr=[2,4,6,6,1,9]
for(let value of arr){
console.log(value);
}
注意:forof中要遍历的对象只能为迭代器,forin中要遍历的对象可以为对象,也可以为数组
JS数组常用方法
push()
语法:数组.push(数据)
作用:将数据追加到数组的末尾
返回值:追加后数组最新的长度
原始数组多了追加的元素
pop()
语法:数组.pop()
作用:删除数组的最后一个数据
返回值:被删除的数据
原始数组少了最后一个数据
unshift()
语法:数组.unshift(数据)
作用:将数据添加到数组的最前面
返回值:添加数据后数组的新长度
原始数组最前面多了一个数据
shift()
语法:数组.shift()
作用:删除数组最前一个数据
返回值:被删除的数据
原始数组的第一个数据被删除
reverse()
语法:数组.reverse()
作用:将数组反转
返回值:反转后的数组
原始数组被反转
splice()
语法:数组.splice(开始索引,删除多少个,要插入的数据)
开始索引默认为0,删除多少个默认为0,要插入的数据默认没有
作用:删除数组中的若干数据,并选择是否插入新数据,如果插入就从开始索引处插入
返回值:以新数组的形式返回被删除的数据
原始数组被用以上方式改变
sort()
语法:
数组.sort():从最高位开始按照顺序依次排序
数组.sort(function(a,b){return a-b}):数组从小到大升序排列
数组.sort(function(a,b){return b-a}):数组从大到小降序排列
作用:将数组进行排序返回值:排好序的数组
原始数组被排好序
join()
语法:数组.join(连接符)
作用:用连接符将数组每一项连接成字符串连接符string类型
返回值:连接好的字符串
原始数组未改变
concat()
语法:数组.concat(其他数组)
作用:将其他数组和数组拼接在一起此数组在前,其他数组在后
返回值:合并好的数组
原始数组没变化
includes()
语法:数组.includes(元素)
作用:判断该元素是否在该数组里
返回值:若元素在数组里则返回true,否则返回false
原始数组没变化
slice()
语法:数组.slice(开始索引,结束索引)——开始默认为0,结束默认数组长度,左闭右开
作用:截取数组中的某些数据
返回值:新数组的形式返回截取出来的数据
原始数组无变化
indexOf()
语法:数组.indexOf(数据)
作用:查找数据在数组中索引位置
返回值:有该数据返回第一次出现索引的位置,没有则返回-1
原始数组不变
forEach()
语法:数组.forEach(function(item,index,arr){})
作用:遍历数组
返回值:无
<script>
var arr=[100,200,300]
arr.forEach(function(item,index,arr){
console.log(item)
console.log(index)
console.log(arr)
})
/* 遍历了数组的元素,下标,原始数组 */
</script>
map()
语法:数组.map(function(item,index,arr){})
作用:映射数组
返回值:映射好的数组
<script>
var arr=[100,200,300]
var res=arr.map(function(item,index,arr){
return item*10//每一项都放大10倍
})
console.log(res)//返回值数组将原始数组每个放大10倍
console.log(arr)//原始数组不变
</script>
filter()
语法:数组.filter(function(item,index,arr){})
作用:过滤数组
返回值:过滤好的新数组
<script>
var arr=[100,200,300]
var res=arr.filter(function(item,index,arr){
return item>200//
})
console.log(res)
console.log(arr)//原始数组不变
</script>
every()
语法:数组.every(function(item,index,arr){})
作用:判断数组是不是每一项都满足条件
返回值:布尔值
<script>
var arr=[100,200,300]
var res=arr.every(function(item,index,arr){
return item>200//
})
console.log(res)//false——数组中不是每一项都>200
console.log(arr)//原始数组不变
</script>
some()
语法:数组.some(function(item,index,arr){})
作用:判断数组中是不是有某一项满足条件
返回值:布尔值
<script>
var arr=[100,200,300]
var res=arr.some(function(item,index,arr){
return item>200//
})
console.log(res)
console.log(arr)//原始数组不变
</script>
reduce()
语法:数组.reduce(function(item1,item2,index,arr){})
返回值:计算好的新数组
原始数组不变
计算规则
- 初始值是数组的第一个元素(必填),第二个元素是数组中要处理的下一个元素
- index代表第一个元素所处的索引,arr代表整个数组
- reduce会从左到右依次把数组中的元素用reduce处理,并把处理的结果作为下一次reduce的第一个参数,如果是第一次,则会把前两个元素作为计算参数
<script>
let arr=[1,2,3,4,5,6,7,8,9,0]
var result=arr.reduce((a,b)=>{
return a+b
})
console.log(result);//45
console.log(arr);//原始数组不变
</script>
JS字符串
含义:由双引号或单引号包裹的一串字符
注意:字符串也是按照索引进行排列的规则和数组一样从0开始依次递增,在字符串里一个字符就是一个索引位置
模板字符串
含义:其是ES6内新增定义字符串的方式,内容用一对反引号包裹
模板字符串和普通字符串的区别
- 可以换行书写,不会有格式错乱问题
- 可以直接在字符串内解析变量,当你解析变量时使用${变量}来解析
<script>
var age=18
var m="我今年"+age+"岁了"//传统方法
var message=`我今年${age}岁了`//模板字符串
alert(message)
console.log(m);
</script>
JS字符串常用方法
charAt()
语法:字符串.charAt(索引)
作用:获取对应索引位置的字符
返回值:对应索引位置的字符
toLowerCase()
语法:字符串.toLowerCase()
作用:把字符串的所有字母转换成小写
返回值:转换好的字符串
toUpperCase()
语法:字符串.toUpperCase()
作用:把字符串里所有的字母转换成大写
返回值:转换好的字符串
replace()
语法:字符串.replace(换下来的内容,换上去的内容)
作用:将字符串内第一个满足换下内容的片段换成换上内容
返回值:替换好的字符串
trim()
语法:字符串.trim()
作用:去除字符串首尾空格
返回值:去除空格后的字符串
split()
语法:字符串.split(分隔符)
作用:按照分隔符将字符串切割成一个数组,分隔符为string格式
返回值:切割后变成的数组
截取字符串方法
JS正则表达式
构建正则表达式
1.字面量创建
var reg = /正则表达式/修饰符
2.构造函数创建
var reg = new RegExp('正则表达式','修饰符')
修饰符
- i: ignoreCase, 匹配忽视大小写
- m: multiline , 多行匹配
- g: global , 全局匹配(查找所有匹配而非在找到第一个匹配后停止)
注意:
- 正则表达式中的修饰符可以组合使用
- 在正则表达式中,使用“\字符 ”来对字符进行转义
正则表达式的调用
exec函数
匹配字符串和正则表达式的方法,
- 匹配成功:返回一个数组 [匹配内容,index:匹配的起始位置,input:要匹配的字符串, group:undefined]
- 匹配失败:返回null
<script>
var str = 'world hello world hello';
var reg = /hello/g;
console.log(reg.exec(str))
//返回['hello', index: 6, input: 'world hello world hello', groups: undefined]
</script>
注意: 匹配内容为正则里的全部内容并且只匹配一个
test函数
测试待检测的字符串是或否能匹配到,匹配到返回true,否则返回false
var str = 'hello world hello';
var reg = /world/;//匹配world
console.log(reg.test(str))//返回true
字符串match函数
<script>
var str="The rain in SPAIN stays mainly in the plain"
var n=str.match(/ain/g)//加了g之后全局匹配
console.log(n)//ain,ain,ain
</script>
注意: match里面的g参数是全局匹配,加了之后返回所有匹配到的ain(区分大小写),如果换成gi则会不区分大小写全局进行匹配,会返回有4个ain的数组,若不加参数则只会返回1个ain
字符串search函数
有则返回第一次出现的索引,否则返回-1
<script>
var str="The rain in SPAIN stays mainly in the plain"
var n=str.search(/ain/)
console.log(n)//5
</script>
字符串replace函数
作用:将符合正则表达式的字符串用第二个字符串参数所代替
<script>
let str = '我爱背景天安门,但是背景雾霾太严重';
str = str.replace(/背景/g,'北京');
// 输出结果:我爱北京天安门,但是北京雾霾太严重
console.log(str);
</script>
正则表达式字符(选记)
符号 | 意义 |
* | 该字符在整个字符串中出现0次或多次 |
+ | 该字符在整个字符串中出现1次或多次 |
? | 该字符在整个字符串中出现0次或1次 |
. | 匹配除换行符\n和回车符之外任意字符 |
^ | []之外是匹配字符串开始位置[]内是否定符号 |
$ | 匹配字符串结束位置 |
[A-Z] | 在整个字符串中从A-Z中选择任意一个字符进行匹配 |
[0-9] | 从0-9范围内任何一个数字相匹配 |
[0-9][a-z] | 整个字符串中0-9之间任意一个紧接着是a-z之间任意一个进行匹配 |
{n} | 匹配字符出现连续出现n次 |
{n,} | 匹配字符连续出现至少n次 |
{n,m} | 匹配字符连续出现最少n次最多m次 |
Date
前言
js中的引用数据类型
创建事件对象:var time=new Date()
创建指定时间节点的时间对象如下
var time=new Date(年,月,日,时,分,秒)
注意:
- 创建的是当前终端的时间
- 第二种方式月份信息中0表示1月11表示12月
<script>
var time=new Date(2022,1,23,11,22,15)
console.log(time)
//Wed Feb 23 2022 11:22:15 GMT+0800
</script>
时间戳
时间常用方法
获取
设置
语法:事件对象.setTime(数字)
作用:获取时间对象的时间戳信息
返回值:时间对象的时间戳信息
数字常用方法
random()
语法:Math.random()
作用:获取0-1之间的随机小数,包含0,不包含1
返回值:0-1之间的随机小数
round()
语法:Math.round(数字)
作用:对数字四舍五入进行取整
返回值:四舍五入后的整数
pow()
语法:Math.pow(底数,指数)
作用:对数字进行取幂运算
返回值:取幂后的结果
sqrt()
语法:Math.sqrt(数字)
作用:对数字进行二次方运算
返回值:平方根后的结果,只保留正数部分
abs()
语法:Math.abs(数字)
作用:对数字进行绝对值运算
返回值:绝对值的运算结果
max()
语法:Math.max(数字1,数字2,……)
作用:获取若干数字的最大值
返回值:若干数字的最大值
min()
语法:Math.min(数字1,数字2,……)
作用:获取若干数字的最小值
返回值:若干数字的最小值
PI
语法:Math.PI
作用:得到一个近似圆周率的值
具体示例
<script>
//获得圆周率的值
console.log("圆周率的值为:"+Math.PI);
//生成0-1之间的一个随机的小数
let num=Math.random();
console.log("0-1之间的随机小数为:"+num);
//对该小数向上取整
console.log("向上取整为:"+Math.ceil(num));
//对该小数向下取整
console.log("向下取整为:"+Math.floor(num));
//对该小数进行四舍五入
console.log("四舍五入为:"+Math.round(num));
//返回3的2次方
console.log("3的2次方为:"+Math.pow(3,2));
//对9进行开放
console.log("9的开方为:"+Math.sqrt(9));
//计算-1的绝对值
console.log("-1的绝对值为:"+Math.abs(-1));
//获取最大值
console.log("最大值:"+Math.max(100,200,70));
//获取最小值
console.log("最小值:"+Math.min(100,200,70));
</script>
对象数据类型
对象:一个可以装很多数据的盒子
面向对象
面向对象:在开发过程中,我们看看有没有一个对象能帮助我们完成任务
面向过程:在开发过程中,我们要关注每一个细节,步骤、顺序
面向对象本质:别人给封装好的能解决你的问题你用就可以了,没必要自己二次开发,站在巨人的肩膀上
面向对象的核心:高内聚、低耦合(面向对象的高度封装)
创建对象的方式
<script>
//方式一:字面量方式创建对象——不符合批量制造的原则
var obj={name:"lin",sayHi:function(){console.log("Hi")}}
// 增加数据——方法1
obj.age=8
// 增加数据方法2
obj["flag"]=true
// 删除数据
delete obj.name; delete obj["obj"]
// 访问对象
alert(obj.flag)
obj.sayHi()
//方式二:自定义构造函数创建对象
// 1.自定义一个构造函数
// 2.使用自定义函数创建对象
function createObject(name,age){
//构造函数会自动创建对象
//手动向对象里面添加成员,这里的this指的是当前实例
this.name=name
this.age=age
this.sayHi=function(){console.log("hello world")}
//自动返回对象
}
//构造函数在使用时需要和new关键字连用才有自动创建对象自动返回对象的能力,如果不连用则没有意义
var obj1=new createObject("lili",8);
var obj2=new createObject("kate",9);
obj1.flag=true
console.log(obj1,obj2)
</script>
注意:
- 对象内部的数据以key:value形式展现
- 访问数据p['key']中key必须加引号
- 多个属性之间用,隔开
- 当多个函数名相同函数出现时,会发生覆盖现象无论参数列表是否相同
- 调用含参函数可以使无参同名函数生效,反之不行
静态属性的写法
<script>
function Person(name,age){
this.name=name
this.age=age
}
//添加静态成员以及方法
Person.a=100
Person.sayHi=function(){console.log("逃吧")}
console.log(Person.a)
Person.sayHi()
//静态属性不可以通过对象调用
// var b=new Person("linda",25)
// console.log(b.a)
// b.sayHi()
</script>
构造函数的使用
- 构造函数和普通函数没有区别,构造函数只不过在调用的时候和new关键字连用
- 书写构造函数名字的时候,函数名首字母大写,当你看到函数名字的时候就知道要和new连用
- 构造函数创建对象的过程我们称之为实例化
- 调用函数的时候,构造函数需要和new关键字连用,只有和new关键字连用的时候,这个函数才会自动创建和返回对象的能力
- 调用构造函数的时候,如果不需要传递参数可以不写最后的小括号,但是推荐写上
- 当你的函数名和new关键字连用时函数内部的this指向当前实例(new关键字前面的变量)
- 构造函数内部不要随便写return,当你return了基本数据类型,那么没有意义,因为取不到;当你return了一个复杂数据类型的时候,构造函数白写,return的是复杂数据类型
构造函数的不合理
当你在构造函数体内写方法的时候,只要创建一个对象,就会有一个函数占用空间,创建100次对象会有100个一摸一样的函数出现,但是其中99个是重复的
<script>
function createObj(name){
this.name=name
}
var a=new createObj("pp")
var b=new createObj("pp")
console.log(a==b)//false
</script>
<script>
function Person(name,age){
this.name=name
this.age=age
//在构造函数体内直接添加方法这个行为并不好
this.sayHi=function(){console.log("hello world ")}
}
var p1=new Person("jack",18)
var p2=new Person("lili",20)
console.log(p1)
console.log(p2)
p1.sayHi()
p2.sayHi()
console.log(p1.sayHi===p2.sayHi)//false
</script>
构造函数创建对象过程
- 在栈内开辟空间存放构造函数名变量
- 在堆内存里创建一个构造函数(函数里面写了代码)
- 构造函数名来指向构造函数对象
- 在栈内存开辟空间存放对象名
- 创建一个空对象
- 为新对象添加属性
__proto__
,将该属性链接至构造函数的原型对象 ; - 执行构造函数方法(会把函数内部的this指向创建的对象,会把函数体内的代码全部执行一遍)
- 将创建的对象交给对象名来保存
原型
定义:每一个函数天生自带一个属性,叫做prototype,是一个对象
注意:
- 构造函数也是函数,也会有这个自带的空间prototype对象
- 每个对象会天生自带一个"__proto__"属性,他指向所属构造函数的prototype
- 每一个对象,在你访问他的时候,如果自己没有这个属性就会去自己的__proto__上查找,又因为__proto__指向所属构造函数的prototype,所以会去所属构造函数的prototype上查找
<script>
function Person(){}
//直接向prototype添加一些成员
Person.prototype.a=100
Person.prototype.b=200
Person.prototype.sayHi=function(){console.log("hello world")}
var p=new Person()
console.log(p.__proto__===Person.prototype)//true
console.log(p.a)//100
a.sayHi()
b.sayHi()
/* a和b都是使用的原型的方法,我们只要在原型上加一些方法那么Person构造函数创建的所有实例都可使用就不会出现浪费空间的情况 */
</script>
原型链
含义:用__proto__串联起来的对象链状结构
作用:访问对象成员
前言:
- 在js中所有对象都是属于Object这个内置构造函数的实例
- 在js中所有函数对象都是属于Function这个内置构造函数的实例
- Object的prototype在js是顶级原型,不再有__proto__了,其__proto__指向null
对象访问机制
当你需要访问对象成员的时候,首先在自己身上查找,若有直接用,没有就去__proto__上查找,如此反复直到Object.prototype,若都没有,则返回undefined
<script>
function Person(){}
var p=new Person()
</script>
理解:
- p.__proto__指向Person.prototype
- Person.prototype是一个对象,所以Person.prototype的__proto__指向Object.prototype
- Person也是函数对象,其内部也有__proto__属性,其__proto__属性指向Function.prototype,(跨度指向)也指向Object.prototype
- Object.__proto__指向Function.prototype,(跨度指向)也指向Object.prototype
- Function.prototype的__proto__指向Object.prototype
- Function自己是自己的实例对象,Function所属的构造函数是Function
ES6类语法
内容
<script>
//类的书写
class Person{
constructor(name,age){
this.name=name
this.age=age
}
//直接写的就是原型prototype上的方法
sayHi(){console.log("hello world")}
}
//创建对象
var p=new Person("lili",8)
console.log(p)
p.sayHi()
</script>
注意:必须和new关键字连用,不和new关键字连用就会直接报错
静态属性及方法的书写
在类内加一个static关键字即可
<script>
//类的书写
class Person{
constructor(name,age){
this.name=name
this.age=age
}
static a=100
static sayGo(){console.log("running")}
//直接写的就是原型prototype上的方法
sayHi(){console.log("hello world")}
}
//创建对象
var p=new Person("lili",8)
console.log(p)
p.sayHi()
//使用静态属性和方法
console.log(Person.a)
Person.sayGo()
</script>
注意:这里的静态属性不能通过对象名直接调用
Object中的一些静态方法
Object.defineProperty方法
语法:Object.defineProperty(obj, prop, descriptor)
返回值:返回被传递给函数的对象obj
作用:会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象
参数:
- obj:属性所在的对象
- prop:属性的名字
- descriptor:一个描述符的对象
descriptor属性两种形式
- 数据描述符
- 存取描述符
数据描述符
- configurable:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性,默认值为false。
- enumerable:表示能否通过for in循环访问属性,默认值为false
- value:包含这个属性的数据值。默认值为undefined。
- writable:表示能否修改属性的值。默认值为false。
存取描述符
- configurable:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性,默认值为false
- enumerable:表示能否通过for in循环访问属性,默认值为false
- get方法:一个给属性提供 getter 的方法,如果没有 getter 则为 undefined。当访问该属性时,该方法会被执行,方法执行时没有参数传入,但是会传入this对象(由于继承关系,这里的this并不一定是定义该属性的对象)。默认为 undefined。
- set方法:一个给属性提供 setter 的方法,如果没有 setter 则为 undefined。当属性值修改时,触发执行该方法。该方法将接受唯一参数,即该属性新的参数值。默认为 undefined。
注意:
descriptor
要么是数据描述符,要么是存取描述符,不能同时包含数据描述符和存取描述符。- 数据描述符和存取描述符的共有属性(configurable、enumerable)
- 使用字面量创建对象中已经定义好的属性默认值configurable为true,enumerable默认值为true,value默认值看是否定义,writable默认值为true
案例
var obj={name:"lili"}
Object.defineProperty(obj,"age",{
value:8,
writable:false,
configurable:false,
enumerable:false
})
console.log(obj.name,obj.age);//lili 8,age不是undefined原因——value:8
delete obj.age
console.log(obj.age);//8——configurable:false原因
obj.age=89
console.log(obj.age);//8——writable:false原因
for(var key in obj){
console.log(obj[key]);
}
//lili,没有age原因——enumerable:false
var obj={name:"lili"}
Object.defineProperty(obj,"age",{
configurable:true,
enumerable:true,
//age属性被访问时触发
get:function(){
console.log("属性被访问了");
},
//age属性被修改时触发
set:function(){
console.log("属性被修改了");
}
})
console.log(obj.age);//属性被访问了=>undefined
obj.age=89//属性被修改了
console.log(obj.age);//undefined——默认的writable为false
console.log("----------------------------------------");
Object.defineProperty(obj,"name",{
get:function(){
console.log("属性被访问了");
},
set:function(){
console.log("属性被修改了");
}
})
obj.name="lala"
console.log(obj.name);//undefined——重新定义了name属性(原来的configurable默认为true)
var obj={name:"lili"}
Object.defineProperty(obj,"age",{
configurable:true,
enumerable:true,
//age属性被访问时触发
get:function(){
console.log("属性被访问了");
},
//age属性被修改时触发
set:function(){
console.log("属性被修改了");
}
})
Object.defineProperty(obj,"age",{
value:8,
writable:true
})
console.log(obj.age);//8,可以重新定义的原因:上一次定义configurable:true
//没有上面的访问修改提示了
Object.defineProperties方法
语法:Object.defineProperties(obj,propertiesObject)
返回值:返回被传递给函数的对象obj
作用:会直接在一个对象上定义多个新属性,或者修改一个对象的现有属性,并返回此对象
参数
- obj:在其上定义或修改属性的对象。
- propertiesObject:要定义其可枚举属性或修改的属性描述符的对象。
propertiesObject结构:{属性1:descriptor1,属性2:descriptor2,……}
var obj={name:"lili"}
Object.defineProperties(obj,{
age:{
value:23,
writable:true
},
flag:{
configurable:true,
get:function(){
console.log("属性被访问了");
},
set:function(){
console.log("属性被修改了");
}
}
})
console.log(obj.age);//23
obj.age=17
console.log(obj.age);//17
obj.flag=true//属性被修改了
console.log(obj.flag);//属性被访问了——undefined
Object.create方法
语法:Object.create(proto, propertiesObject)
返回值:在指定原型对象上添加新属性后的对象
作用:创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。
参数
- proto:此参数为必须的,是新创建对象的原型对象
- propertiesObject:此参数是可选的,是新创建对象的实例对象上的属性
案例
<script>
var a={name:"lili",age:66,
study:function(n){console.log(n+"在学习");}}
//注意:这里的a为原型对象,此原型对象里面有2个属性name、age
var b=Object.create(a,{
flag:{
value:true,
writable:true
},
name:{
value:"lala",
configurable:true
}
})
//注意:第二个参数为本对象的属性
console.log(b);//{flag: true, name: 'lala'}
console.log(b.name);//lala
b.study("cjc");//在原型中查找
var c=Object.create(null)
console.log(c);
//c为空对象里面也没有__proto__属性
</script>
对象合并
语法:Object.assign(对象1,对象2)
作用:将对象2的内容追加到对象1的后面
结果:对象1内容得到扩充
var a={name:"lili",age:8}
var b={flag:true,arr:[1,2,3]}
var c={}
Object.assign(c,a)
console.log(c);//{ name: 'lili', age: 8 }
Object.assign(c,b)
console.log(c);//{ name: 'lili', age: 8, flag: true, arr: [ 1, 2, 3 ] }
获取对象的key/value集
获取对象的key集
语法:var arr1=Object.keys(obj)
返回值:对象obj的所有key组成的数组
获取对象的value集
语法:var arr2=Object.values(obj)
返回值:对象obj的所有value组成的数组
var a={name:"lili",age:16,flag:true}
var arr1=Object.values(a)
console.log(arr1);//[ 'lili', 16, true ]
var arr2=Object.keys(a)
console.log(arr2[0]);//name
console.log(arr2);//[ 'name', 'age', 'flag' ]
对象的简写
因为对象的数据是key:value形式存在的
- 如果对象的key和变量的名字一致,则可以只定义一次即可
- 如果value是一个函数,可以把(:function)去掉不写,只剩下其余的即可
<script>
//对象的简写
var age=18
var name="lili"
var obj={
name,age,
//函数的简写
hello(){
console.log("hello world");
}
}
console.log(obj);
</script>
对象的遍历
使用for……in循环
var obj = {
name: 'lili',
age: 18,
flag:true
}
for (var key in obj) {
console.log(key);
console.log(obj[key]);
}
理解:遍历对象obj中的key,其中obj[key]为对象对应key的value,其为访问对象的第二种方式,obj对象里面的key必须为字符串类型
JSON
前言
含义:JS对象表示法,其就是一个字符串,用来完成浏览器和服务器之间的数据交换
注意:
- json规定了浏览器和服务器之间的数据格式:'"name":"jack"'
- 其基于JS规范的一个子级采用完全独立于编程语言的文本格式来储存和表示数据
理解:
JSON 是存储和交换文本信息的语法。当数据在浏览器与服务器之间进行交换时,这些数据只能是文本。JSON 属于文本,并且我们能够把任何 JavaScript 对象转换为 JSON,然后将 JSON 发送到服务器。我们也能把从服务器接收到的任何 JSON 转换为 JavaScript 对象。以这样的方式,我们能够把数据作为 JavaScript 对象来处理,无需复杂的解析和转译。
JSON语法
//JSON数据
var a='"name":"lili"'
//JSON对象
var b='{"name":"lucy","age":8,"boolean":true}'
//JSON数组
var c='[{"name":"lucy","age":8},{"name":"lili","age":7}]'
JSON格式
//对象格式
'{"name":"lili","age":100,"flag":true}'
//数组格式
'[100,"lili",true]'
//嵌套格式
'[100,true,["a",10,{"name":"lili","hobbys":["eat","sleep"]}]]'
注意:
- 对象格式的json串其key数据类型必须为字符串,值value类型可以为字符串、数值类型、布尔类型、null、数组、对象类型,并且这些类型可以嵌套
- json格式的数据总体为一个字符串
转换工具
使用JS里的内置对象JSON.用来把以 JSON 格式写的字符串 和 原生 JavaScript 对象互转.
给服务器发送数据: 将JS对象转成JSON字符串
语法:JSON.stringify(Js对象)
返回值:一个JSON串
接受服务器的数据: JSON字符串转成JS对象
语法:JSON.parse("json字符串")
返回值:一个js对象
注意:当把对象转化为JSON串时若原来的对象有方法,则方法不被转化为json数据,直接省略
<script>
function Person(name,age){
this.name=name
this.age=age
var fun=function(){console.log("hello world");}
}
var p=new Person("lili",8)
//对象转json串
var res=JSON.stringify(p)
console.log(p);
console.log(res);
var a='{"name":"kate","age":9,"flag":true}'
//json串转化为对象
var b=JSON.parse(a)
console.log(a);
console.log(b);
</script>
解构赋值
含义:快速的从对象或者数组中获取成员
解构赋值分为2种
数组的解构赋值
对象的解构赋值
<script>
//获取对象中的name/age值
//方式1:不去别名
var {name,age}={name:"lan",age:18,flag:true}
alert(name)
alert(age)
//方式2:取别名
var {name:x,age:y}={name:"lili",age:8,flag:true}
alert(x)
alert(y)
</script>
展开运算符
含义:用...展开数组的[]或者对象的{}
<script>
var arr=[100,200,300]
console.log(arr)
//展开运算符...
console.log(...arr)
</script>
作用
合并数组与对象
<script>
//合并数组
var arr1=[100,200,300]
var arr2=[400,500,600]
var arr3=[...arr1,...arr2]
console.log(arr3)
//合并对象
var obj1={name:"lili",age:18}
var obj2={flag:true,
hello(){
console.log("hello world");
}}
var obj3={...obj1,...obj2}
console.log(obj3);
</script>
给函数传递参数
<script>
var arr1=[100,200,300]
var max=Math.max(...arr1)
console.log(max)
</script>
对象传播
<script>
var person={
name:"lili",
age:18,
flag:true,
hello(){
console.log("hello world");
}
}
var {name,age,...person2}=person
console.log(person2);
//会把person中的除了name,age的元素都塞给person2
</script>
同步和异步
前言
同步:同一个任务结束后再执行后一个任务,程序的执行顺序与任务的排列顺序一致的、同步的。
比如做饭要用水,先烧水烧个10分钟,10分钟之后再开始切菜做饭(同步做饭)
异步:你在做一件事的时候,因为这件事情会花费很长时间,在做这件事的同时,你还可以去处理其他事情。
比如做饭的异步做法,烧水的同时,利用这10分钟,再去切菜,去炒菜
同步任务和异步任务的执行过程
同步任务:同步任务都放到主线程上来执行,形成一个执行栈
异步任务:js的异步任务是通过回调函数来实现的
异步任务常见有以下3种类型(回调函数)
- 普通事件:click、resize等
- 资源加载:load、error等
- 定时器:setInterval、setTimeout等
注意:
- 异步任务相关回调函数添加到任务队列中(任务队列也称消息队列)
- 异步任务队列分为宏任务队列和微任务队列
宏任务和微任务
常见的宏任务:setTimeout、setInterval、DOM事件、AJAX请求
常见的微任务:Promise、async/await
js的执行机制
- 先执行执行栈中的同步任务
- 异步任务(回调函数)放到任务队列中
- 一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取(轮询)任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈开始执行
setTimeout(function(){
console.log("炸弹来了!");
},3000)
//3秒之后将该回调函数放到任务队列中
console.log("我是个路过的");
console.log(1);
setTimeout(()=>{
console.log("3的settimeout");
},0)
Promise.resolve().then(()=>{
console.log("2的promise");
})
console.log(4);
// 1
// 4
// 2的promise
// 3的settimeout
理解:事件循环是一个不断进行循环的机制,其会不断地去寻找可以执行的任务来执行,在执行完同步任务以后也就是清空了调用栈以后 首先会先执行微任务队列的任务把微任务队列的任务清空以后才会去执行宏任务,每次宏任务结束后,事件循环就会先执行微任务直到微任务队列完全清空才会执行下一轮宏任务,并不会把宏任务全执行完再去执行微任务,这样就会避免因宏任务繁重而导致的任务阻塞
总结:微任务先于宏任务而执行,宏任务可以执行的前提是微任务队列此时没有微任务
最终顺序:微任务>DOM渲染>宏任务队列
JS异常
异常:当JS引擎执行JS代码时,发生了错误,导致程序停止运行
异常抛出:当异常产生,并且将这个异常生成的这个错误信息得到
异常的捕获
try{
发生异常的代码块;
}catch(err){
错误信息的处理;
}finally{
一定执行的代码;
}
throw语句:通过throw语句创建一个自定义的错误
注意:如果异常没有catch捕获封装则后面代码不执行
<script>
function fn(){
try{
//throw之后一定会抛出异常
throw "异常"
}
catch(e){
alert(e)
}
finally{
alert("一定执行")
}
}
fn()
alert("后面代码")
</script>
promise
异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理且更强大
promise有3个状态
- pending[待定]:初始状态
- fulfilled[实现]:操作成功
- rejected[拒绝]:操作失败
promise的使用
创建promise对象:var promise=new Promise(executor函数)
var promise=new Promise(function(resolve,reject){
//if里面判断事件状态
if(true){
resolve("事件成功")//表示事件成功时执行的函数
}else{
reject("事件失败")//表示事件失败时执行的函数
}
})
注意:
- executor函数的参数为两个回调函数,分别为状态成功时执行的函数以及状态失败时执行的函数
- promise状态改变时就会触发then()/catch()里的响应函数处理后续步骤
- promise状态的改变发生在resolve/reject函数中,这里面分别把状态改为成功/失败
状态改变以及执行的函数
- 从pending变为fulfilled
- 从pending变为rejected
注意:状态只能由pending到达fulfilled/rejected,并且状态只能改变一次
状态成功时执行函数:var p1=promise.then(函数)
状态失败时执行函数:var p2=promise.catch(函数)
无论如何都执行函数:var p3=promise.finally(函数)
注意:
- p1、p2、p3也为promise对象,这也是promise对象能够链式调用的原因
- finally的回调函数不接受任何参数
var flag=[true,false]
var r=Math.round(Math.random())
var promise=new Promise(function(resolve,reject){
//if里面判断事件状态
if(flag[r]){
resolve("事件成功")//表示事件成功时执行的函数
}else{
reject("事件失败")//表示事件失败时执行的函数
}
})
var p1=promise.then((res)=>{
console.log(res);//成功会返回resolve里面的value(事件成功)
})
var p2=promise.catch(err=>{
console.log(err);//失败则会返回reject里面的value(事件失败)
})
var p3=promise.finally(()=>{
console.log("一定执行");//不管成功与失败,最终一定会执行,finally回调函数不接受任何参数
})
回调地狱的解决
回调地狱:简单来说就是嵌套回调,如下
setTimeout(()=>{
console.log("回调1");
setTimeout(()=>{
console.log("回调2");
setTimeout(()=>{
console.log("回调3");
},3000)
},2000)
},1000)
promise解决回调地狱
function func() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('success')//状态改变时就会触发then
console.log("回调1");
}, 1000);
})
.then(() => {//里面不需要传参
return new Promise((resolve) => {
setTimeout(() => {
resolve('success')
console.log("回调2");
}, 2000);
})
})
.then(() => {
return new Promise((resolve) => {
setTimeout(() => {
resolve('success')
console.log("回调3");
}, 3000);
})
})
}
func()
Promise.all()
Promise.all可以将多个Promise实例以数组的形式包装成一个新的Promise实例,同时,成功和失败的返回值是不同的,成功的时候返回一个结果数组,而失败的时候则返回最先被reject失败状态的值
成功
var p1=new Promise(resolve=>{
resolve("成功了")
})
var p2=Promise.resolve("success")
Promise.all([p1,p2]).then(result=>{
console.log(result);
}).catch(err=>{
console.log(err);
})
//[ '成功了', 'success' ]
失败
var p1=new Promise(resolve=>{
resolve("成功了")
})
var p2=Promise.reject("失败了")
var p3=Promise.reject("不舒服")
Promise.all([p1,p2,p3]).then(result=>{
console.log(result);
}).catch(err=>{
console.log(err);
})
//失败了
Promise.race()
Promise.race([p1,p2,p3])里面哪个结果获得的快就返回哪个结果,不管成功与失败
let p1=new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve("我慢")
},3000)
})
let p2=new Promise((resolve,reject)=>{
setTimeout(()=>{
reject("我快")
},2000)
})
Promise.race([p1,p2]).then(res=>{
console.log(res);
}).catch(err=>{
console.log(err);
})
//我快
async/await
前言
- 用来处理异步的,其实是Generator函数的改进,背后原理就是promise
- async和await在干什么,async用于申明一个function是异步的,而await可以认为是async wait的简写,等待一个异步方法执行完成。
规则:
- async表示这是一个async函数,await只能用在这个函数里面不能单独使用
- await表示在这里等待promise返回结果后再往后继续执行
- await后面跟着的应该是一个promise对象(当然,其他返回值也没关系,只是会立即执行,不过那样就没意义了)
async
async function fun(){
return 88
}
fun().then(res=>{
console.log(res);//88
})
console.log(fun());//Promise { 88 }
由上面观之,async加在函数的前面使函数的返回值变成了一个promise对象并且返回值是状态成功时的value值
await
function fun(){
return new Promise((resolve)=>{
setTimeout(()=>{
resolve("3秒后")
},3000)
})
}
async function fun1(){
var a=await fun()//等待fun函数返回promise的成功时的值再执行后面操作
console.log(a);
console.log("我是路过的");
}
fun1()
函数内,碰到await下面代码阻塞掉,主程序内看到await则此函数被跳过添加到任务队列,当主线程执行完再轮询任务队列开始执行
async/await解决回调地狱问题
// 方法二:async和await
function time1() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('success')
console.log('调用1');
}, 1000)
})
}
function time2() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('success')
console.log('调用2');
}, 2000)
})
}
function time3() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('success')
console.log('调用3');
}, 3000)
})
}
// 使用async修饰函数
async function time() {
// 取代了之前的.then((data)=>{}),直接获取到异步数据
// 代码会按照你写的顺序执行,等待第一个完成再继续第二个
let one = await time1()
console.log(one);// success
let two = await time2()
console.log(two);// success
let three = await time3()
console.log(three);// success
}
time()
事件
内容:前端开发人员通过代码的方式和页面中的某些内容做好一个约定,用户触发指定行为时就会执行代码
事件绑定
事件绑定的三要素
- 事件源:和谁做好约定
- 事件类型:约定一个什么行为
- 事件处理函数:当用户触发行为时,执行什么代码
语法:事件源.on事件类型=事件处理函数
<body>
<div>看不见我</div>
</body>
<style>
div{
width: 200px;
height: 200px;
background: pink;
}
</style>
<script>
//获取div元素
var div=document.querySelector("div")
//绑定点击事件
div.onclick=function(){
alert("啊哈哈哈哈!")
}
</script>
事件的类型
事件对象
含义:当事件触发时,一个描述该事件信息的对象数据类型
属性:window.event
理解
在浏览器中,当你第一次触发事件的时候(不一定是点击事件)浏览器就会找一张纸(抽象的),记录下来本次事件的信息(对象),比如:什么事件,哪一个元素触发的事件,当第n此触发事件的时候,浏览器依旧会找一张纸记录下来这些相关的信息
事件对象内部的属性
- 事件对象.target:返回事件当前所在的节点(点击元素什么就打印什么元素)
- 事件对象.type:返回一个字符串,表示一个事件类型
<body>
<button id="btn">按钮</button>
</body>
<script>
btn.onclick=function(){
console.log(window.event.target);//<button id="btn">按钮</button>
console.log(window.event.type);//click
}
</script>
注意:当事件发生后,会产生一个事件对象作为参数传递给监听函数
拿到浏览器事件处理函数的对象
//方式1:直接使用属性获取事件对象
元素.onclick=function(){
console.log(window.event);//打印当前事件对象
}
//方式2:直接在事件处理函数时接受形参
元素.onclick=function(e){
console.log(e)
}
注意:直接在事件处理函数内接收形参,这样会在事件触发的时候由浏览器自动传递实参,浏览器传递的实参就是本次事件的事件对象
事件对象的信息
鼠标事件
坐标信息
- offsetX和offsetY相对于触发事件的元素的坐标点位
- clickX和clickY相对于浏览器可视窗口的坐标点位
- pageX和pageY相对于页面文档流的坐标位置
以上相对于什么就是在什么内生成坐标系
语法:事件对象.以上属性
<body>
<div>看不见我</div>
</body>
<style>
div{
width: 200px;
height: 200px;
background: pink;
}
</style>
<script>
//获取div元素
var div=document.querySelector("div")
div.onclick=function(e){
console.log(e)
console.log(e.offsetX)
console.log(e.clientX)
console.log(e.pageX)
}
</script>
键盘事件
语法:事件对象.keyCode
注意:keyCode属性记录的就是键盘编码,我们的常用键盘每一个按键都有一个固定的编码我们可以通过判断编码来确定按下的是哪一个按键
<script>
//打印键盘编码
document.onkeydown=function(e){
console.log(e.keyCode)
}
</script>
取消浏览器对当前事件的默认行为
语法:事件对象.preventDefault()
该方法用于取消浏览器对当前事件的默认行为,比如点击链接之后,浏览器默认会跳转到另一个页面,使用这个方法后就不会跳转了
<body>
<a href="https://a.maorx.cn" id="btn">点击</a>
</body>
<script>
btn.onclick=function(e){
console.log("点击了");
e.preventDefault();//加了这个方法就不会点击后自动跳转
console.log("点击结束")
}
</script>
事件传播
含义:浏览器响应事件的一种机制
浏览器的事件响应机制
注意:浏览器窗口最先知道事件的发生
- 捕获阶段:从window按照结构子级的顺序传递到目标
- 目标阶段:准确触发事件的元素接收到行为
- 冒泡阶段:从目标按照结构父级的顺序传递到window本次事件传播结束
理解:当你点击了inner元素,首先window窗口知道了你触发了点击行为,然后window会传播给document,document就知道了你的点击行为,之后document就会传播给html以此类推直到inner,然后inner才知道你点击了他,当inner知道点击行为发生了以后会再次向外传递再一次告诉center有人触发了点击行为以此类推,直到window,至此,浏览器对于你的点击行为就响应结束了
在这个事件模型中,我们管准确触发事件的元素叫事件目标对于从window到目标这个阶段称为事件捕获阶段,对于目标再次传递回到window的阶段叫做事件的冒泡阶段这便是浏览器的事件响应机制
事件冒泡和事件捕获
- 事件传递两种方式:冒泡与捕获
- 事件传递定义了元素事件触发的顺序
- 在冒泡中,内部元素的事件会被触发,然后再触发外部元素
- 在捕获中,外部元素的事件会被先触发,然后才会触发内部元素的事件
注意:
- 浏览器的传播机制默认是在冒泡阶段触发事件的
- 当在子级触发事件的时候也同时会触发父级的事件
阻止事件传播
语法:事件对象.stopPropagation()
<body>
<div class="outer">
<div class="center">
<div class="inner">
</div>
</div>
</div>
</body>
<script>
//绑定事件
var outer=document.querySelector(".outer")
var center=document.querySelector(".center")
var inner=document.querySelector(".inner")
outer.onclick=function(){console.log("我是outer元素")}
center.onclick=function(){console.log("我是center元素")}
inner.onclick=function(e){
//阻止事件传播
e.stopPropagation()
console.log("我是inner元素")}
</script>
<style>
div{
border: 1px solid red;
}
.outer{
width: 500px;
height: 500px;
}
.center{
width: 300px;
height: 300px;
}
.inner{
width: 200px;
height: 200px;
}
</style>
事件委托:利用事件冒泡的机制,把自己的事件委托给结构父级中的某一层
<body>
<ul>
<li>1</li>
<li>2</li>
</ul>
</body>
<style>
ul{
width: 500px;
height: 500px;
list-style: none;
border: 1px solid red;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto;
}
li{
width: 200px;
height: 200px;
border: 1px solid red;
text-align: center;
line-height: 200px;
font-size: 50px;
}
</style>
<script>
var ul=document.querySelector("ul")
ul.onclick=function(e){
if(e.target.tagName==="LI"){
console.log("你点击的是li")
}else{
console.log("你点击的是ul")
}
}
</script>
JS事件监听
addEventListener()添加事件监听方法
语法:元素.addEventListener("event", function, useCapture)
removeEventListener()移除事件监听
语法:元素.removeEventListener("event", function, useCapture)
- 参数event必填,表示监听的事件,例如 click, resize等,不加前缀on的事件。
- 参数 function必填,表示事件触发后调用的函数,可以是外部定义函数,也可以是匿名函数。不带参数。
- 参数 useCapture选填,填true或者false,用于描述事件是冒泡还是捕获触发,true表示捕获,默认false表示冒泡。
注意:要保证移除函数生效,需要保证添加监听器与移除监听器中的两个函数一样
<body>
<div id="a" onclick="move()">点我</div>
</body>
<style>
div{
width: 500px;
height: 500px;
background: orange;
text-align: center;
line-height: 500px;
color: aliceblue;
font-size: 30px;
}
</style>
<script>
var me=function(){console.log("hello world")}
a.addEventListener("mouseenter",me)
function move(){
a.removeEventListener("mouseenter",me)
}
</script>
BOM操作
一整套操作浏览器相关内容的属性和方法
- 操作浏览器历史记录
- 操作浏览器滚动条
- 操作浏览器页面跳转
- 操作浏览器标签页的开启和关闭
获取浏览器的窗口尺寸
获取可视窗口宽度:window.innerWidth
获取可视窗口高度:window.innerHeight
浏览器的弹出层
提示框:window.alert(‘提示信息’)
<script>
window.alert("hello world")
</script>
询问框:window.confirm(‘提示信息’)
<script>
/* 返回值为布尔类型,点击确定为true,点击取消为false */
var res=window.confirm("点赞了吗?")
if(res==true){
console.log("爸爸")
}else{
console.log("儿子")
}
</script>
输入框:window.prompt(‘提示信息’)
<script>
/* 返回值为输入的结果,若点取消会获得null */
var res=window.prompt("请输入您的银行密码供我盗窃")
console.log(res)
</script>
开启和关闭标签页
开启:window.open("url地址","target")
target属性
- _self:在当前页面打开
- _blank:在新页面打开
关闭:window.close()
<body>
<button id="on">开启页面</button>
<button id="off">关闭页面</button>
</body>
<script>
//必须为id
on.onclick=function(){
window.open("https://www.runoob.com/","_blank")
}
off.onclick=function(){
window.close()
}
</script>
window.parent属性
作用:获得父页面的BOM对象,一般用在同内嵌标签一起联用
具体案例
<body>
<div>
<h1>我是demo1.html界面</h1>
<iframe src="demo2.html"></iframe>
</div>
</body>
<body>
<div>
<h2>我是demo2.html界面</h2>
</div>
</body>
<script>
window.parent.location.href="https://www.csdn.net/"
</script>
结果:当运行demo1.html后,该页面会直接跳转到CSDN的首页
window.location.search属性
作用:获取请求页面后面携带的参数
具体案例
<body>
<div>
<h1>我是demo1.html界面</h1>
<iframe src="demo2.html?我是数据"></iframe>
</div>
</body>
<body>
<div>
<h2>我是demo2.html界面</h2>
</div>
</body>
<script>
let data=window.location.search
//对data进行解码(不然会乱码)
data=decodeURI(data)
//?我是数据
document.write(data)
</script>
结果:运行demo1.html页面后demo2.html会直接获取到demo1.html传过来的数据
window.location.href属性
作用:跳转到指定的页面
<body>
<div>
<h1>我是demo1.html界面</h1>
</div>
</body>
<script>
window.location.href="https://www.csdn.net/"
</script>
结果:执行该demo1.html文件会直接跳转到CSDN主页面
浏览器的常用事件
以下情况下触发
- 资源加载完毕:window.οnlοad=function(){}
- 可视尺寸改变:window.οnresize=function(){}
- 滚动条位置改变:window.οnscrοll=function(){}
浏览器的历史记录操作
回退页面:window.history.back()
前进页面:window.history.forward()
浏览器卷去的尺寸
获取卷去的高度
- document.documentElement.scrollTop(有<!DOCTYPE html>时使用)
- document.body.scrollTop(没<!DOCTYPE html>时使用)
获取浏览器卷去的宽度
- document.documentElement.scrollLeft(有<!DOCTYPE html>时使用)
- document.body.scrollLeft(没<!DOCTYPE html>时使用)
设置浏览器滚动条位置
滚动到:window.scrollTo()
参数方式1:window.scrollTo(left,top)
- left:浏览器卷去的宽度
- top:浏览器卷去的高度
参数方式2:window.scrollTo({
left:xx,top:yy,behavior:“smooth”
})
eval函数
执行n所表示的代码:window.eval(n)
<script>
var n="var a=3; var b=5; alert(a+b)"
window.eval(n)
</script>
JS定时器
间隔定时器
间隔定时器:按照指定周期(ms)去执行指定代码(每隔一段时间,执行一遍代码)
语法:setInterval(函数,时间)
时间:单位是ms
<script>
setInterval(function() {
console.log("你的闹钟又响了,嘿嘿!")
}, 1000);
</script>
延时定时器
延时定时器:在固定的时间(ms)后执行一次代码,只执行一次
语法:setTimeout(函数,时间)
时间:单位是ms
<script>
setTimeout(function() {
console.log("炸弹爆炸啦!")
}, 8000);
</script>
定时器的返回值
定时器的返回值不区分定时器种类,只是表示是当前页面的第几个定时器
<script>
var a=setTimeout(function() {
console.log("炸弹爆炸啦!")
}, 8000);
var b=setInterval(function() {
console.log("闹钟响了!")
}, 1000);
console.log(a)
console.log(b)
</script>
关闭定时器
- 语法1:clearInterval(要关闭定时器的返回值)
- 语法2:clearTimeout(要关闭定时器的返回值)
注意:定时器的关闭是不区分定时器种类的,都一种关闭方式都可以关闭2种定时器
DOM操作
一整套操作文档流相关内容的属性和方法
- 操作元素修改样式
- 操作元素修改属性
- 操作元素改变位置
- 操作元素添加事件
获取元素的方式
根据id获取元素:
语法:document.getElementById('id名称')
作用:获取文档流中id名对应的一个元素
返回值:若有id对应元素则返回这个元素,没有返回null
根据元素类型名获取元素
语法:document.getElementsByClassName('元素类名')
作用:获取文档流中所有类名对应的元素
返回值:必然是一个伪数组,若有类名对应的元素,则有多少获取多少,若没有,则获得空的伪数组
伪数组:长得很像数组,排列也按照索引排列只是不能使用数组常用方法
根据标签名获取元素
语法:document.getElementsByTagName('标签名')
作用:获取文档流中所有标签名对应的元素
返回值:必然是一个伪数组,若有此标签名对应的元素,则有多少获取多少,若没有,则获得空的伪数组
根据选择器获取一个元素
语法:document.querySelector('选择器')
作用:获取文档流中满足选择器的第一个元素
返回值:如果有选择器对应的元素,获取到第一个,若没有,则获得null
根据选择器获取一组元素
语法:document.querySelectorAll('选择器')
作用:获取文档流中所有满足选择器规则的元素
返回值:必然是一个伪数组,若有此选择器对应的元素,则有多少获取多少,若没有,则获得空的伪数组
操作元素内容
操作元素文本内容
- 获取:元素.innerText
- 设置:元素.innerText="新内容"
<script>
var e=document.querySelector("div")
var b=document.querySelector("button")
console.log(e.innerText)
b.onclick=function(){
e.innerText="新内容"
}
</script>
操作元素超文本内容
- 获取:元素.innerHTML
- 设置:元素.innerHTML="新内容"
<script>
var e=document.querySelector("div")
var b=document.querySelector("button")
console.log(e.innerHTML)
b.onclick=function(){
e.innerHTML="<b>新内容</b>"
}
</script>
innerText与innerHTML区别
- innerText:只能获取和修改获得到元素的文本内容
- innerHTML:能获取和修改获得到元素的超文本内容
操作元素属性
原生属性
标签本身自带的属性
- 获取:元素.属性名
- 设置:元素.属性名=“属性值”
<body>
<button>操作内容</button>
<div id="box">
<p>文本内容</p>
</div>
<input type="password">
</body>
<script>
var e=document.querySelector("div")
var i=document.querySelector("input")
var b=document.querySelector("button")
console.log(e.id)
console.log(i.type)
b.onclick=function(){
e.style.color="red"
i.type="text"
}
</script>
自定义属性
我门自己随便定义的一个属性
- 获取:元素.getAttribute('属性名')
- 设置:元素.setAttribute('属性名','属性值')
- 删除:元素.removeAttribute('属性名')
<body>
<button>操作属性</button>
<div id="box" hello="world">div标签</div>
</body>
<script>
//获取属性
var d=document.querySelector("div")
var b=document.querySelector("button")
//获取自定义属性
var res=d.getAttribute("hello");
console.log(res)
//修改自定义属性
b.onclick=function(){
d.setAttribute("hello","home")
var res=d.getAttribute("hello");
console.log(res)
d.removeAttribute("hello")
var res=d.getAttribute("hello");
console.log(res)
}
</script>
data-*属性
前言:dataset实际上是一个DOMStringMap,里面用json格式存储着所有data-自定义属性数据
注意:
- dom数据的存取在html5中直接使用data-自定义属性来存储数据的值
- 数据的获取需要配合js来获取
- dom中的数据一般都是临时使用的数据
- 使用data-自定义属性的数据可以通过js直接赋值来改变
- data-*后面的*如果有-再分割则后面的杠在js中用驼峰命名
<body>
<div id="a" data-app-cn="淘宝">我是一段话</div>
<button onclick="getData()">获取属性</button>
<button onclick="setData()">修改属性</button>
</body>
<script>
function getData(){
//这里的a相当于document.getElementById("a"),是此属性的唯一标识
var b=a.dataset.appCn
alert(b)
}
function setData(){
a.dataset.appCn="京东"
}
</script>
操作元素类名
- 获取:元素.className
- 设置:元素.className="新类名“
<body>
<button>操作类名</button>
<div class="content">div标签</div>
</body>
<script>
//获取元素
var box=document.querySelector("div")
var btn=document.querySelector("button")
//获取类名
console.log(box.className)
//给按钮绑定点击事件
btn.onclick=function(){
box.className="box"
console.log(box.className)
}
</script>
操作元素行内样式
- 获取:元素.style.样式名
- 设置:元素.style.样式名="样式值"
<body>
<button>操作类名</button>
<div style="width:100px; height:100px; background-color: aqua;">文本内容</div>
</body>
<script>
//获取元素
var box=document.querySelector("div")
var btn=document.querySelector("button")
//给按钮绑定点击事件
btn.onclick=function(){
box.style.width='200px'
box.style.height='300px'
/* 注意中间带横线的属性要用驼峰命名规则 */
box.style.backgroundColor="red"
}
</script>
注意:
- 带有中划线的属性名在js中的属性用驼峰命名规则
- 这种方式只能获取元素的行内样式
获取元素非行内样式
获取:window.getComputedStyle(元素).样式名
<body>
<button>操作类名</button>
<div style="width:100px; height:100px; background-color: aqua;">文本内容</div>
</body>
<script>
//获取元素
var box=document.querySelector("div")
var btn=document.querySelector("button")
//给按钮绑定点击事件
btn.onclick=function(){
console.log(window.getComputedStyle(box).width)
console.log(window.getComputedStyle(box).height)
//获取元素非行内样式
console.log(window.getComputedStyle(box).fontSize)
}
</script>
<style>
div{
font-size: 20px;
}
</style>
注意:可以获取行内样式,也可以获取非行内样式,单不可以设置非行内样式
节点操作
含义:通过我们的js代码来实现创建节点、插入节点、删除节点、替换节点、克隆节点
创建节点
含义:用js代码的方式创建一个内容(标签)来,不再是页面提前写好的,而是根本没有的内容
语法:document.creatElement("标签名称")
作用:创建一个指定的标签
返回值:创建出来的标签元素
<script>
var a=document.createElement("div")
console.log(a);
</script>
插入节点(2个语法)
含义:我们创建一个节点,插入到一个已经存在的结构内
语法1:父节点.appendChild(子节点)
作用:把该子节点放到父节点内,并且排列到最后的位置
<body>
<div>
<p>我就是一段话</p>
</div>
</body>
<script>
//创建一个span标签并赋予内容
var span=document.createElement("span")
span.innerText="我是span啊"
console.log(span)
//将span标签及内容放入div内部
var div=document.querySelector("div")
div.appendChild(span)
</script>
语法2:父节点.insertBefore(要插入的子节点,哪一个子节点的前面)
作用:把子节点插入到父节点的内部,并放在某一指定子节点的前面
<body>
<div>
<p>我就是一段话</p>
<p id="p">我就是二段话</p>
</div>
</body>
<script>
//创建一个span标签并赋予内容
var span=document.createElement("span")
span.innerText="我是span啊"
console.log(span)
var p2=document.getElementById("p")
//将span标签及内容放入div内部id为p标签的前面
var div=document.querySelector("div")
div.insertBefore(span,p2)
</script>
删除节点
含义:把一个已经存在的节点删除掉
语法1:父节点.removeChild(子节点)
作用:从父节点把该子节点删除掉
<body>
<div>
<p>我就是一段话</p>
<p id="p">我就是二段话</p>
</div>
</body>
<script>
var p2=document.getElementById("p")
var div=document.querySelector("div")
div.removeChild(p2)
</script>
语法2:节点.remove()
作用:把自己直接删除
<body>
<div>
<p>我就是一段话</p>
<p id="p">我就是二段话</p>
</div>
</body>
<script>
var p2=document.getElementById("p")
p2.remove()
</script>
替换节点
含义:用一个节点把另一个节点换下来
语法:父节点.replaceChild(换上节点,换下节点)
作用:在该父节点内使用换上节点替换到换下节点
<body>
<div>
<p>我就是一段话</p>
<p id="p">我就是二段话</p>
</div>
</body>
<script>
//创建一个span标签并赋予内容
var span=document.createElement("span")
span.innerText="我是span啊"
console.log(span)
var p2=document.getElementById("p")
var div=document.querySelector("div")
//将id为p的标签及内容用新节点替换
div.replaceChild(span,p2)
</script>
克隆节点
含义:把一个节点复制一份一摸一样的出来
语法:节点.cloneNode(是否克隆后代节点)
作用:把该节点复制一份一模一样的内容
返回值:克隆好的新节点
注意:参数类型为boolean类型,默认为false
<body>
<div>
我是个傻子
<p>我就是一段话</p>
</div>
</body>
<script>
//获取到div元素
var div=document.querySelector("div")
var clone1=div.cloneNode(true)//克隆后代节点
var clone2=div.cloneNode(false)//不克隆后代节点(包括里面的文字)
console.log(clone1)
console.log(clone2)
</script>
获取元素的尺寸
一个元素的盒子模型其实是由bolder也就是边框、padding内边距、content内容区域组成,获取元素的尺寸就是获取元素的宽度和高度
语法:
- 元素.offsetHeight
- 元素.offsetWidth
获取:元素内容+padding+boder区域的尺寸
语法:
- 元素.clientHeight
- 元素.clientWidth
获取:元素内容+padding区域尺寸
动态渲染数据:在我们代码里有一个已知的数据结构,我们通过代码的方式把这个数据渲染成一个表格显示在页面上,当然不一定非要渲染表格我们可以根据需求和数据渲染成各种各样的数据结构
页面输出
向页面输出内容
语法:document.write("数据")
注意:里面的数据如果是HTML文本也会生效
<script>
document.write("<b>hello</b>")//里面的标签会生效
</script>
JS由单线程到多线程的跨越
前言
js是单线程的原因:防止多线程同时操作dom元素
H5引入Worker多线程,但是不允许其同时操作dom
Worker局限性
- worker文件不能同时操作dom
- worker文件不能跨域加载
worker的使用
引入worker对象:var worker = new Worker(“子线程文件的地址”);
worker对象的方法
主文件内
主线程向子线程发送数据:worker.postMessage("向子线程文件发送的数据")
主线程断开连接:worker.terminate()
worker.onmessage事件:当子线程向主线程发送数据时触发,用来接收子线程发来的数据,接收数据采用-事件对象.data属性
var worker = new Worker('worker.js');
worker.postMessage("hello world");//将复杂计算交给子线程
worker.onmessage = function (e) {
console.log(e.data);//接收子线程返回来的数据
}
worker.js文件内
注意:self相当于子线程的全局对象相当于浏览器的window对象
子线程向主线程发送数据:self.postMessage("向主线程文件发送的数据")
子线程断开连接:self.close()
self.onmessage事件:当主线程向子线程发送数据时触发,用来接收主线程发来的数据,接收数据采用-事件对象.data属性
/*
* 响应主线程发过来的数据进行处理
*/
self.onmessage = function (e) {
var num = e.data;//接收从主线程传过来的值
num=num+"!";//假设做了一系列高难度计算工作
//注意:self——子线程的全局对象相当于浏览器的window对象
self.postMessage(num);//把计算结果传回给主线程
}
测试:安装Live Server插件后右击页面open with Live Server形式打开页面
fetch API
使用fetch会发送http请求给服务器在不刷新网页的前提下可以实现局部内容的更新
语法
var p=fetch("url地址",options对象)
p.then(response=>{return response.json()})//将后端的响应进行解析
.then(data=>{console.log(data);})//打印出来后端传过来的数据
.catch(err=>{console.log(err);})
注意:
- 第一个.then()后面必须设置返回值(为promise类型),否则第二个then接收不到数据
- 第一个then后面的response为收到后端发来的响应,将其转换为确定格式(如json)解析
- fetch函数的返回值p为promise对象
- get请求没有body
- options为一个对象
options对象属性
- method:http的请求方法,默认为get
- body:http的请求体
- headers:http的请求头
- mode:请求模式-跨域/不跨域/同源
- credentials:请求资格证书
credentials属性
- omit:默认值,忽略 cookie 的发送;
- same-origin:表示 cookie 只能同域发送,不能跨域发送;
- include:cookie 既可以同域发送,也可以跨域发送。
get请求
var p= fetch("http://localhost:3000?name=lili&age=18",{method:"get"})
p.then(response => {return response.json()})//response为获取到的响应内容,将响应转化为json格式
.then(data=>{console.log(data);})
//后端代码实现
var http=require("http")
http.createServer((req,res)=>{
const myurl=new URL(req.url,"http://127.0.0.1:3000")
var p=myurl.searchParams
res.writeHead(200,{"Content-Type":"application/json;charset=utf-8","access-control-allow-origin":"*"})
res.write(`{"name":${JSON.stringify(p.get("name"))},"age":${p.get("age")}}`)
res.end()
}).listen(3000,()=>{
console.log("server start");
})
post请求
var a=fetch("http://localhost:3000",{
method:"POST",
mode:"cors",
body:JSON.stringify({
name:"cjc",
age:"123456"
})
})
a.then(res=>{return res.json()})
.then(data=>{console.log(data);})
.catch(err=>{console.log(err);})
var http=require("http")
http.createServer((req,res)=>{
var post=""
req.on("data",chunk=>{
post+=chunk
})
req.on("end",()=>{
post=JSON.parse(post)
console.log(post);
res.writeHead(200,{"Content-Type":"application/json;charset=utf8","access-control-allow-origin":"*"})
if(post.name==="cjc"&&post.age==="123456"){
res.write(`{"ok":1}`)
}else{
res.write(`{"ok":0}`)
}
res.end()
})
}).listen(3000,()=>{
console.log("server start");
})
AJAX
前言
含义:(asynchronous javascript and xml)是一种无需重新加载网页的情况下就能够更新部分网页的技术
注意:ajax不是一种新的编程语言,而是一种用于创建更好更快以及交互性更强的web应用程序的技术
AJAX特点:局部刷新,异步访问。(依赖于AJAX引擎)
同步特点:一个线程依次加载执行,若数据没有加载完成则其他的数据处于等待状态
AJAX引擎
- 用户发起请求,交给ajax引擎处理,用户可以执行其他操作(局部刷新)
- ajax接收到用户请求后发起http请求访问目标服务器(异步访问)
- 后台服务器将数据返回给ajax引擎
- ajax引擎通过回调函数的方式交给用户处理
AJAX固定步骤
1.创建ajax对象
var xhr=new XMLHttpRequest()
2.配置本次请求信息
xhr.open("请求方式","请求地址","是否异步")
注意:是否异步默认为true
3.注册请求完成的事件
xhr.οnlοad=function(){
console.log(xhr.responseText)
}
注意:这个事件会在本次请求完成之后触发
4.把请求发送出去
xhr.send()
注意:这种方式为页面全部加载完可以获得响应数据,可以与readyStateChange事件类比
请求完成:本次请求发送出去,服务器收到我们的请求,并且服务器返回的信息已经回到了浏览器
拿到后端返回的信息:xhr.responseText
XMLHttpRequest()对象方法
XMLHttpRequest()对象属性
AJAX状态码
readyState === 0 : 表示未初始化完成,也就是 open 方法还没有执行
readyState === 1 : 表示配置信息已经完成,也就是执行完 open 之后
readyState === 2 : 表示 send 方法已经执行完成
readyState === 3 : 表示正在解析响应内容
readyState === 4 : 表示响应内容已经解析完毕,可以在客户端使用了
请求方式
注意:get请求的参数信息要用?拼接写在请求地址的后面,而post请求的参数信息要写在send的括号里面
<script>
//get请求
var a=new XMLHttpRequest()
a.open("get","http://localhost:8888/test/third?name=我是神",true)//默认就为true
a.onload=function(){
console.log(a.responseText);
}
a.send()
//post请求
var b=new XMLHttpRequest()
b.open("post","http://localhost:8888/test/fourth",true)
b.onload=function(){
console.log(JSON.parse(b.responseText));
}
//send后面的()就是书写请求体的位置,当你发送post请求并且需要携带参数的时候,需要进行特殊声明
//特殊声明语法:对象.setRequestHeader("content-type",你传递参数的格式)
b.setRequestHeader("content-type","application/x-www-form-urlencoded")
b.send('name=前端&age=18')
</script>
readyStateChange事件
- 在 ajax 对象中有一个事件,叫做 readyStateChange 事件
- 这个事件是专⻔用来监听 ajax 对象的 readyState 值改变的的行为
- 也就是说只要 readyState 的值发生变化了,那么就会触发该事件
- 所以我们就在这个事件中来监听 ajax 的 readyState 是不是到 4 了
- 只有readyState到4了,我们才能得结果
<body>
<!-- 点击时,使用ajax -->
<div onclick="change()">按钮</div>
</body>
<script>
function change() {
var xhr = new XMLHttpRequest();
//定义当 readyState 属性发生变化时被调用的函数
xhr.onreadystatechange = function () {
//3. status是200表示请求成功,readyState是4表示请求已完成且响应已就绪
if (this.status == 200 && this.readyState == 4) {
//到达指定状态后才能执行指定操作
//只有ajax发送完并得到结果,才可以从xhr中取得想要的数据
console.log(xhr.responseText);
}
}
//3.规定请求的类型(请求方式,文件位置,异步)
xhr.open('get', 'http://localhost:8888/test/second?name=lili', true);
xhr.send();
}
</script>
控制台打印
控制台打印表格
语法:console.table(对象)
<script>
var user={id:3,name:"lili"}
console.table(user)
</script>
控制台打印日志
打印普通日志:console.log(日志)
打印警告:console.warn(警告信息)
打印错误:console.error(错误信息)
注意:日志有优先级别,打印日志只会打印和自己优先级别一样和比自己优先级别高的日志
<script>
console.log("日志信息")
console.warn("警告信息");
console.error("错误信息");
</script>