widow对象
BOM
Brower Object Model浏览器对象模型
window对象是一个全局对象
定时器-延时函数
让代码延迟执行的函数,setTimeout,只执行一次
setTimeout(回调函数,等待的毫秒数)
清除延时函数
let timer=setTimeout(回调函数,等待的毫秒是)
clearTimeout(timer)
JS执行机制
渲染引擎+JS解析器
单线程,同一时间只能做一件事
创建多个线程:同步+异步
同步任务在执行栈中执行,
异步通过回调函数实现,放到任务队列
- 普通时间,如click/resize
- 资源加载,如load/error
- 定时器,包括setInterval/setTimeout
事件循环
主线程不断的重复获得任务、执行任务。再获取任务,再执行,这种机制
location对象
拆分并保存URL地址
属性
1/href经常利用JS方法跳转页面
location.href='http://www.baidu.com'
<a href="#">支付成功<span>5</span>秒后跳转</a>
<script>
const a=document.querySelector('a')
let num=5
//1秒后5才减去1
let id=setInterval(function(){
num--
//改变a内容
a.innerHTML=`支付成功</a><span>${num}</span>秒后跳转`
if(num==0)
//先清理定时器,再跳转
{clearInterval(id)
location.href="http:///www.baidu.com"}
},1000)
</script>
2/location.hash获得地址中的哈希值,符号#后面部分
后期vue路由的铺垫,经常用于不刷新页面,显示不同页面
console.log(location.hash)
方法
reload方法用来刷新当前页面,传入参数true表示强制刷新
<button class="reload">刷新</button>
<script>
const reload = document.querySelector(".reload");
reload.addEventListener("click", function () {
location.reload();
});
</script>
navigator对象
属性,userAgent检测浏览器版本及平台
赋值粘贴
相关介绍
histroy对象
主要管理历史记录,该对象与浏览器地址栏的操作相对应,如前进、后退、历史记录
<button >前进</button>
<button >后退</button>
<script>
const back=document.querySelector('button:first-child')
const f=back.nextElementSibling
back.addEventListener('click',function(){
history.forward()
history.go(1)
})
f.addEventListener('click',function(){
history.back()
history.go(-1)
})
</script>
本地存储
介绍
本地存储-localStorage
目标:使用localStorage把数据存储的浏览器中
- 作用:把数据永久存储在本地,除非手动删除,否则关闭页面也会存在、
- 特性:多窗口共享;以键值对的形式存储使用
存储数据
localStorage.setltem(key,value)
<script>
// uname加引号,不然当变量来看
localStorage.setItem('uname','pink')
</script>
获取数据
localStorage.getItem(key)
删除元素
localStorage.removeItem(key)
改变元素
localStorage.setItem('uname','pink')
localStorage.setItem('uname','blue')
打印
//本地存储只能存储字符串数据类型
localStorage.setItem('uname','pink')
console.log(localStorage.getItem('uname'));//最后得到的都是字符串
本地存储-sessionStorage
存储复杂数据类型
1、将复杂数据类型转换成JSON字符串,存储到本地
JSON.stringify()
<script>
const obj={
uname: 'pink',
age:18,
gender: 'nv'
}
localStorage.setItem('obj',JSON.stringify(obj))
console.log(localStorage.getItem('obj'));//{ "uname": "pink","age":"18","gender": "nv"}
</script>
JSON对象,无论是属性还是值都有双引号
2、字符串转化成对象
JSON.parse()
<script>
const obj={
uname: 'pink',
age:18,
gender: 'nv'
}
localStorage.setItem('obj',JSON.stringify(obj))
console.log(localStorage.getItem('obj'));//{ "uname": "pink","age":"18","gender": "nv"}
const str=localStorage.getItem('obj')
console.log(JSON.parse(str))
</script>
样例
map()/join()数组方法实现字符串拼接
map()遍历数组数据,并且返回新的数组
也称映射,两个元素的集之间元素相互对应的关系
重点是有返回值,forEach没有返回值
<script>
const arr=['red','blue','green']
const newArr=arr.map(function(ele,index){
//每次循环加上颜色,ele数组元素
return ele+'颜色'
})
console.log(newArr);//[ "red颜色", "blue颜色", "green颜色" ]
</script>
join()方法擦数组中的所有元素转换成一个字符串
<script>
const arr=['red','blue','green']
// 若小括号为空,默认以,隔开
console.log(arr.join());//red,blue,green
const newArr=arr.join('')//redbluegreen
console.log(newArr);
</script>
正则表达式
介绍
用来匹配字符串中字符组合的模式,也是对象
通常用于查找、替换那些符合正则表达式的文本
场景:
- 验证表单,匹配
- 过滤敏感词,从字符串中获取特定部分
语法
1、定义规则
- 定义正则表达式语法
const 变量名=/表达式/
//字面量
2、根据规则查找
规则.test(被检测的字符串)
<script>
const str='hhxhh'
//定义规则
const reg=/x/
//判断正则表达式(前)与指定字符串是否匹配
console.log(reg.test(str));//true
</script>
检索(查找)符合规则的字符串
exec()方法
匹配成功返回一个数组,否则null
<script>
const str='hhxhh'
//定义规则
const reg=/xh/
//判断正则表达式(前)与指定字符串是否匹配
console.log(reg.exec(str));//Array [ "xh" ]
0: "xh"
groups: undefined
index: 2
input: "hhxhh"
length: 1
<prototype>: Array []
</script>
</body>
元字符
普通字符:只能匹配和他们相等的字符
具有特殊意义的字符,提高灵活性和强大匹配功能
正则表达式测试工具:http://tool.oschina.net/regex
分类:
- 边界符:(表示位置,开头和结尾,必须用什么开头,用什么结尾)
- 量词(重复次数)
- 字符类(\d表示0-9)
1、边界符
^表示匹配行头的文本
$表示匹配行尾的文本
<script>
console.log(/h/.test('xhx'));//含有就是true
console.log(/^h/.test('xhx'));//false
console.log(/^h$/.test('h'));//true
console.log(/^h$/.test('hh'));//false,精确匹配,必须与前面完全一样
</script>
2、量词
设定某种模式的次数
*表示零次或者更多次
+重复一次或者更多次
?重复零次或者一次
量词{n},出现几次
{n,}重复n词=次或者更多次
{n,m}重复n到m次,不能有空格
<script>
console.log(/^h*$/.test(''));//true
console.log(/^h*$/.test('hh'));//true
console.log(/^h*$/.test('hxh'));//false只能有h
</script>
console.log(/^h+$/.test(''));//true
console.log(/^h+$/.test(''));//flase
console.log(/^h+$/.test('hh'));//true
console.log(/^h*$/.test('hxh'));//false,只能有h
console.log(/^h{4}$/.test('hhhh')) //true
3、元字符
- []匹配字符集合
后面字符只要包含abc中任意一个字符,都返回true
<script>
console.log(/^[abc]$/.test('a')) //true
console.log(/^[abc]$/.test('b')) //true
console.log(/^[abc]$/.test('bc')) //flase,abc只能选一个
console.log(/^[abc]{2}$/.test('bc'));//true
console.log(/^[abc]{2}$/.test('aa'));//true
</script>
1、[]里面加-连字符
表示一个范围
[a-z]表示a到z26个英文字母都可以
[a-a-Z]表示大小写都可以
[0-9]
console.log(/^[a-zA-Z0-9]$/.test(2));//true
console.log(/^[a-zA-Z0-9]$/.test('p'));//true
/^[1-9][0-9]{4,}$/首位1-9,后面0-9,重复四次
3、预定义类
修饰符
/表达式/修饰符
方法replace
字符串.replace(正则表达式,替换内容)
console.log(/^java$/i.test("JAvA")); //true
const str = "java是编程语言,学号java很不错";
str.replace(/java/i, "前端");
console.log(str); //java是编程语言
const re = str.replace(/java/i, "前端");
console.log(re); //前端是编程语言,学号java很不错
//或中间加|
const re1 = str.replace(/java|JAVA/gi, "前端");
console.log(re1); //前端是编程语言,学号前端很不错
样例,过滤
<body>
<textarea name="" id="" cols="30" rows="10"></textarea>
<button></button>
<div></div>
<script>
const tx = document.querySelector("textarea");
const btn = document.querySelector("button");
const div = document.querySelector("div");
btn.addEventListener("click", function () {
//替换敏感词
tx.value.replace(/激情/gi, "**");
div.innerHTML = tx.value; //直接这样不能过滤,可以重新设置变量或者直接赋值
div.innerHTML = tx.value.replace(/激情/gi, "**");
});
</script>
</body>
作用域
局部作用域
1、函数作用域
函数内部声明的变量只能在函数内部被访问,外部无法访问
2、块作用域
let/const声明变量和常量都会产生块作用域,
<script>
for(let i=0;i<3;i++)
{
console.log(i);
}
console.log(i);//i is not defined
for(let i=0;i<3;i++)
{
console.log(i);//可以,不相互影响每个大括号里面是单独是作用域
}
</script>
全局作用域
在script标签和.js文件的最外层就是所谓的全局作用域
## 作用域链
本质是是底层的变量查找机制
- 函数被执行时,优先查找当前函数作用域中查找变量
- 如果当前作用域查找不到会依次逐级查找父级作用域直到全局作用域
垃圾回收机制GC
Garbage Collection
JS内存的分配和回收都是自动完成的,内存在不使用的时候会被垃圾级回收器自动回收
分配内存,一般有如下生命周期:
说明:
全局变量一般不会回收(关闭页面回收)
一般情况下,局部变量的值,不用了,会自动被回收
内存泄漏
程序分配的内存由于某种原因程序未释放或者无法释放叫做内存泄漏
算法说明
栈:操作系统自动分配释放函数的参数值、局部变量,基本类型放到栈中
堆:一般由程序员分配释放,若不释放,由垃圾箱回收机制回收。复杂数据类型放在堆中
垃圾回收算法:引用计数法+标记清除法
1、引用计数
2、标记清除法
- 将“不再使用的对象”定义成“无法到达的对象”
- 从根部(在JS中就是全局对象)出发定时扫描内存中的对象。凡是能从根部到达的对象,都是还需要使用的
- 那些无法由根部出发触及到的对象标记为不再使用,稍后进行回收
闭包
概念:一个函数对周围状态的引用捆绑在一起,内层函数中访问到其外层函数的作用域
闭包=内层函数+外层函数
外部也可以访问函数内部的变量
基本形式:
<script>
function outer(){
let i=1
function fn(){
console.log(i);
}
return fn
}
const fun=outer()
fun()
</script>
简约写法
function()
//要外面使用i
function outer(){
let i=1
function fn(){
console.log(i);
}
return fn//fn是函数,outer接受fn,outer()===fn===function fn(){},outer里面装的是函数
}
const fun=outer()//fun接过函数
fun()
function outer(){
let i=1
return function(){
console.log(i);
}
}
const fun=outer()
fun()
//定义外层函数
function outer() {
const a = 1;
function fn() {
console.log(a); //里层函数加外层函数的变量捆绑到一起形成了闭包
}
//里层函数要在里面调用一下
fn();
}
outer();
闭包应用
因为i是全局变量,容易被修改,最好作为局部变量
变量上升
把var声明的变量提升到当前作用域的最前面
值提升变量,不赋值
log(num)//undefined
var num=10
var num
log(num)
num=10
函数进阶
1.函数提升
会把函数声明提升到当前作用域前面
只提升函数声明,不提升函数调用
fun()
function fun()
{
console.log('函数提升');
}
fun1()//不是一个函数
const fun1=function(){
console.log('函数表达式');
}
函数参数
1、动态参数
arguments是函数内部内置的伪数组
function getsum() {
//动态参数只在函数里面,只要传几个值都能传进来
console.log(arguments);
let sum = 0;
for (let i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
console.log(sum);
}
getsum(2, 3);
getsum(2, 4,3);
2、剩余参数
更加灵活,获得真数组
function config(baseURL, ...other) {
console.log(bassURL); //得到前面的,'hhhh'
console.log(other); //other 得到['hshdf','xxc']
}
config("hhhh", "hshdf", "xxc");
function getsum(a, b, ...arr) {
console.log(arr); //得到数组
}
getsum(2, 3, 4, 4);//Array [ 4, 4 ]
getsum(2, 3, 4);//Array [ 4 ]
展开运算符
将一个数组展开(…)
const arr=[1,2,3]
console.log(...arr);//1 2 3
不会修改原数组
1、求数组最大值
const arr=[1,2,3]
console.log(...arr);//1 2 3等价于1,2,3
// Math.max()里面必须是字符串的形式
console.log(Math.max(...arr));
2、合并数组
const arr1=[1,2,3]
const arr2=[1,2,3,4,5]
const arr=[...arr1,...arr2]
箭头函数(重要)
目的:更简短的函数写法并且不绑定this,表达式更简洁
更适用那些本来需要匿名函数的地方
- 基本语法
const fn=()=>{
}
fn()
相关省略
const fn = (x) => {
console.log(x);
};
fn(1);
//只有一个形参时,可以省略小括号
const fn = x => {
console.log(x);
};
fn(1);
//只有一行代码时,可以省略大括号
const fn = x => console.log(x);
fn(1);
const fn = x => {
return x + x;
};
console.log(fn(1));
//如果在一行,可以省略return
const fn = (x) => x + x;
console.log(fn(1));
加括号的函数体返回对象字面量表达式
对象要求,必须加()
//返回一个对象
const fn1 = (uname) => ({ name: uname });
console.log(fn1("xxc"));//Object { name: "xxc" }
- 箭头函数参数
1、普通函数有arguements动态参数
2、箭头函数没有arguements动态参数,但有剩余参数…args
const getsum = (...arr) => {
let sum = 0;
for (let i = 0; i < arr.length; i++) {
sum += arr[i];
}
return sum;
};
console.log(getsum(1,2,3));
- 箭头函数this
//普通函数谁调用,this指向谁
console.log(this);//window
function fn(){
console.log(this);//window
}
const obj={
name:'xxc',
sayHI:function (){
console.log(this);//obj
}
}
obj.sayHI();
const fn1=()=>{
console.log(this);//window,这个局部作用域没有this
}
fn1()
const obj1={
name:'xxc',
sayHI:()=>{
console.log(this);//window.obj,答案window
}
}
obj1.sayHI()
const obj2={
name:'xxc',
sayHI:function(){
let i=0
const count=()=>{
console.log(this);//Object { name: "xxc", sayHI: sayHI() }
}
count()
}
}
obj2.sayHI()
解构赋值
快速为变量赋值
数组解构
将数组的单元值快速批量赋值给一系列变量的简洁语法
基本语法:
1、赋值运算符=左侧的[]用于批量声明变量,右侧数组的单元值将被赋值给左侧的变量
2、变量的顺序对应数组单元值的位置依次进行赋值操作
const arr=[100,20,30]
const[max,min,average]=arr
console.log(max);
console.log(min);//30
交换变量
const str='pink'
const arr=[1,2,3]
arr.map(function(item){
console.log(item);
})
const str='pink'
[1,2,3].map(function(item){
console.log(item);
})
//会报错,会自动把前面连起来,所以要在前面结尾或者该开始加;表示结尾
情况,变量多单元值少
多的那个变量undefined,
变量少,单元值少,后面值没人接
解决:剩余参数
const[a,b,...c]=[1,2,3,4]
console.log(c);//[3,4]
防止undifined传递,可以设置默认值
const [a=0,b=0]=[1]
按需导入赋值
const [a,b,,d]=[1,2,3,4]
console.log(d);//4
支持多维数组的结构
const arr=[1,2,[3,4]]
console.log(arr[2][0]);//3
const [a,b,[c,d]]=[1,2,[3,4]]
console.log(c);//c
对象结构
1、基本语法
const obj={
uname:'pink',
age:18
}
const {uname,age}=obj
const{uname,age}={uname:'pink',age:18}
//等价于const uname=obj=uname,两个属性名字必须一模一样
//前面声明变量不能和变量一个名字
数组对象:
多级对象解构
用冒号
const obj={
uname:'pink',
age:18,
family: {
m:'xxv',
fd:'edsf'
},
sex:'nv'
}
const{uname,family:{m}}=obj
console.log(m);
const obj=[{
uname:'pink',
age:18,
family: {
m:'xxv',
fd:'edsf'
},
sex:'nv'
}]
const[{uname,family:{m}}]=obj
console.log(m);
const {data}=msg
function render(arr){
const {data}=arr;
}
render(msg)
function render({data:myData}){
console.log(myData);
}
render(msg)
forEach方法
用于调用数组的每个元素,并把元素传递给回调函数
遍历数组的每个元素
const arr=['xxv','ssd','saf']
const result=arr.forEach(function(item,index){
console.log(item);
console.log(index);
})
console.log(result);//undefined
解构对象名字可以乱序
综合案例:
筛选数组filter方法
创建一个新的数组,新数组的元素是通过检查指定数字中符合条件的所有元素,并返回筛选后元素的新数组
const arr=[10,20,30]
const newarr=arr.filter(function(item,index){
return item>=20//只能写><,不能写+-(map)可以
})
console.log(newarr);
const arr=[10,20,30]
const newarr=arr.filter(item=>item>=20)
console.log(newarr);
对象
深入对象
创建对象的三种方式
构造函数
特殊函数,初始化对象
快速创建多个类似的对象
实例成员
实例成员
实例对象上的属性和方法属于实例成员
静态成员
构造函数的属性和方法
比如Date.now()、
function PIG(name){
this.name=name
}
PIG.eyes=2//静态属性
内置构造函数
const str='pink'
const str=new String('pink')//JS底层完成,把简单数据类型包装成复杂数据类型,所以这个字符串可以利用属性
其实字符串、数值、布尔、等基本类型都有专门的构造函数,这些称为包装类型
JS几乎所有数据都是基于构造函数创建
内置构造函数
Object
创建普通对象
常用静态方法(只有构造函数才能调用)
Object.keys静态方法获取对象中的所有属性(键)
Object.values静态方法获取对象中的所有属性值
返回一个数组
Object.assign()静态方法常用于对象拷贝,常用于给对象添加属性
const o={name:'xxc',age:18}
console.log(Object.keys(o))//括号里面放对象,[ "name", "age" ]
console.log(Object.values(o))//获得属性值,[ "xxc", 18 ]
const o={name:'xxc',age:18}
const oo={}
Object.assign(oo,o)
Object.assign(oo,{gender:'nv'})
console.log(oo);
实例方法
reduce返回累计处理的结果,常用于求和等
arr.reduce(function(){},起始值)
arr.reduce(function(上一次值,当前值{},初始值)
reduce执行过程
- 如果没有初始值,则上一次值以第一个数组元素的值
- 每一次循环,把返回值给作为下一次循环的上一次值
- 如果有初始值,初始值为上一次值
如果有起始值,则把初始值累加到里面
prev上一个值,下一个值
const arr=[1,5,8]
const total=arr.reduce(function(prev,current){
return prev+current
})
console.log(total);
arr.reduce(function(prev,current){
return prev+current
},10)
console.log(total);
//箭头函数
arr.reduce((prev,current)=>prev+current,10)
console.log(total)
针对对象数组
const arr=[{name:'张三',salary:100},{name:'哈哈哈',salary:200},{name:'xxc',salary:10000}]
arr.reduce((prev,current)=>{
console.log(prev);//得到的是第一个对象,所以第二个参数不能省略,让初始值为0
})
const arr=[{name:'张三',salary:100},{name:'哈哈哈',salary:200},{name:'xxc',salary:10000}]
total=arr.reduce((prev,current)=>{
return prev+current.salary
},0)
console.log(total)
数组常用方法
//find查找数据
const arr = ["red", "blue", "green"];
const re = arr.find(function (item) {
return item === "blue";
});
console.log(re);
const arr1 = [
{ name: "小米", price: 19 },
{ name: "华为", price: 19 },
{ name: "vivo", price: 19 },
];
//找到对象,并且返回这个对象
const mi = arr1.find(function (item) {
return item.name === "小米";
});
console.log(mi);
检测数组,返回布尔值
字符常用方法
split将字符创变成数组
字符串.split(‘分隔符’)
substring()截取字符串
stratWith()判断是否以什么开头
ar str = "To be, or not to be, that is the question.";
alert(str.startsWith("To be")); // true
alert(str.startsWith("not to be")); // false
alert(str.startsWith("not to be", 10)); // true,在下标10开头
includes()判断数组是否有某一元素、
也可以判断字符串,方法执行区分大小写的搜索,以确定是否可以在另一个字符串中找到一个字符串,并根据情况返回 true 或 false。
如果有数字,则表示从哪开始计算
const gift='50g的茶叶,清洗球'
//拆分为数组
// console.log(gift.split(''))
//根据数组元素生成span,item是数组元素,再用join()转换成字符串
const str=gift.split(',').map(function(item){
return `<span>[赠品]${item}</span></br>`
}).join('')
document.querySelector('div').innerHTML=str
数字型
Number.toFixed()保留位数,四舍五入
const a=2.564
console.log(a.toFixed(1))//2.6
console.log(a.toFixed(2))//2.56
Number.toString()转换成字符串
173
面向对象
编程思想
- 面向过程
分析出解决问题所需要步骤,利用函数将这些步骤一步一步实现
- 面向对象oop
把事物分成一个一个对象,然后又对象之间分工和合作,以功能划分问题,而不是步骤
特性:封装性、继承性、多态性
构造函数
JS面向对象可以通过构造函数实现封装
构造函数体现体现面对对象的封装
原型
解决浪费内存的问题
function Sta(uname,age){
this.name=uname
this.age=age
}
Sta.prototype.sing=function(){
console.log('嫦娥');
}
const hh=new Sta('xxc',19)
const hx=new Sta('xw',39)
hh.sing()
原型对象和构造函数的this都是指向实例对象
let that;
function Sta(uname) {
that = this;
this.name = uname;
}
Sta.prototype.sing=function(){
console.log('xxc');
}
hh.sing()//原型对象和构造函数的this都是指向实例对象
const hh = new Sta("xxc");
console.log(that); //就是对象hh
![在这里插入图片描述](https://img-blog.csdnimg.cn/3a67769295854268a02c3bcf16dae28f.png
const arr = [1, 2, 3];
//等同于const arr=new Arr(1,2,3)
//要接参数
Array.prototype.max = function () {
//return Math.max(1,2,3)要把数组中的数据以这样形式放进去,运用展开运算符
return Math.max(...this); //this指向实例对象arr,将实例对象展开
};
console.log(arr.max());
console.log([1, 5, 4].max());
//求和
Array.prototype.sum = function () {
return this.reduce((prev, item) => prev + item, 0);
};
console.log([1, 2, 3].sum());
constructor属性
每个原型对象都有该属性
作用:该属性指向该原型对象的构造函数,
function Sta(name){
name=name
}
Sta.prototype.sign=function(){
console.log('xxc');
}
Sta.prototype={
constructor:Star,
sing: function(){
console.log('hhh');
},
dance:function(){
console.log('xxc');
}
}//原型对象被赋值,失去了constructor属性,重新指回构造函数,所以有constructor:Star
const arr=new Sta('xxc')
arr.prototype
对象原型
在实例对象都有一个属性,__proto__
指向构造函数的prototype原型对象,该属性只读,不能改
function Sta(){
}
const hh=new Sta()
console.log(hh.__proto__===Sta.prototype)//true
对象原型也有constructor指向构造函数
原型继承
封装:抽取公共部分
//公共部分放到原型对象上
const person = {
eyes: 2,
head: 1,
};
function woman() {}
//通过原型继承person
woman.prototype = person;
//指回构造函数
woman.prototype.constructor = woman;
function man() {}
man.prototype = person;
man.prototype.constructor = man;
const red = new woman();
console.log(red);
但是如果给woman添加属性,man 也会
woman.prototype.baby=function()//man也会有这个方法
解决:利用构造函数创建多个对象,每次都不一样
function person() {
(this.eyes = 2), (this.head = 1);
}
function woman() {}
woman.prototype = new person();
woman.prototype.constructor = woman;
function man() {}
man.prototype = new person();
man.prototype.constructor = man;
woman.prototype.baby=function()
const red = new woman();
const blue = new man();
console.log(red);
console.log(blue);
原型链
查找规则,先自身,再往上一层
基于原型对象的继承使得不同构造函数的原型对象关联在一起,并且这种关联的关系是一种链状的结构
intanceof()
function person(){
}
const hh=new person()
console.log(person.prototype.__proto__===Object.prototype)//true
console.log(hh instanceof person);//true
console.log(hh instanceof Object);//true
console.log(hh instanceof Array);//false
console.log(Array instanceof Object);//true