ES6学习

垃圾回收机制

生命周期

1.内存分配:声明时

2.内存使用:读写内存,使用变量函数等

3.内存回收:使用完毕,由垃圾回收器自动回收

  • 全局变量一般不会回收

  • 局部变量的值不用就会自动回收

内存泄漏:程序中分配的内存由于某种原因程序未释放或无法释放交内存泄漏

栈:由操作系统自动分配释放,基本数据类型

堆:一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收。复杂数据类型

垃圾回收算法:引用计数法,标记清除法

1.引用计数法,看一个对象是否有指向它的引用

(1)跟踪记录被引用的次数

(2)如果引用一次就++

(3)减少引用--

(4)引用次数是0释放

如果两个对象相互引用,尽管他们不再使用,垃圾回收器不会进行回收,导致内存泄漏

2.标记清除法

从根部定期扫描对象,能查找到的就是使用的,查找不到的就要回收

闭包

闭包=内层函数+外层函数的变量

如果外层想要获取函数里面的值,可通过闭包实现,如下:要获取a的值,可调用outer()

 <script>
        function outer(){
         let a=0
         function fn(){
             a++
             console.log(a)
        }
         return fn
        }
        const fun=outer()
        fun()//10
     </script>

应用:实现数据私有,如上可统计函数被调用几次

可能会有内存泄漏

变量提升

var 只提升声明,不提升赋值

函数进阶

  • 函数提升

与变量提升类似

 <script>
        //1.会把所有函数声明提升到当前作用域的最前面
        //2.只提省函数声明,不提升函数调用
        fn()
        function fn(){
        console.log('函数提升')
        }
        fun()//报错,不提升赋值
        var fun=function(){
        console.log('函数表达式')
        }
    </script>
  • 函数参数

  <script>
        //写一个求和函数,传入多少参数都求和
        //arguments
        function getSun(){
        //arguments 动态参数 只存在于函数里面
        //是个伪数组
        console.log(arguments)
        let sum=0
        for(let i=0;i<arguments.length;i++){
            sum+=arguments[i]
        }
        console.log(sum)
        }
        getSun(2,3)
    </script>
  • 函数剩余参数

 <script>
        //arr是一个真数组
        function getSum(...arr){
        console.log(arr)
        }
        getSum(1,2,3)
        //至少传两个
        function getSum(a,b,...arr){
        console.log(arr)//a=1,b=2,arr只存入3
        }
        getSum(1,2,3)
    </script>
  • 展开运算符

 <script>
        const arr=[1,2,3]
        //展开运算符 可以展开数组
        console.log(...arr)
        //1.不会修改原数组
        //求数组最大(最小值),合并数组等
        console.log(Math.max(...arr))//3
        //合并数组
        const arr2=[3,4,5]
        const arr3=[...arr,...arr2]
        console.log(arr3)
    </script>
  • 箭头函数

1.基本语法

  <script>
        const f=function(){
 
        }
        //箭头函数,更简短的函数写法并且不绑定this
        //适用于那些本来需要匿名函数的地方
        const fn=(x)=>{
            console.log(x)
        }
        fn(1)
        //如果函数只有一个参数,小括号可以省略
        const fnn=x=>{
            console.log(x)
        }
        fnn(1)
        //只有一行代码的时候,可以省略大括号
        const fnnn=x=>console.log(x)
        fnnn(1)
        //只有一行代码的时候,可以省略return
        const fm=x=>x+x
        console.log(fm(1))
        //箭头函数可以直接返回一个对象
        const fmm=(uname)=>({name:uname})
        fmm('cc')
 
    </script>

2.箭头函数参数

 <script>
        //箭头函数没有arguments,但有剩余参数
        //1.利用箭头函数求和
        const getSum=(...arr)=>{
            let sum=0
            for(let i=0;i<arr.length;i++){
                sum+=arr[i]
            }
            return sum
        }
        const x=getSum(1,2,3)
        console.log(x)
         
    </script>

3.箭头函数的this

不会有自己的this,只会从自己的作用域链的上一层沿用this

 //以前this指向:谁调用的这个函数this就指向谁
        console.log(this)//window
        //普通函数
        function fn(){
            console.log(this)//window
        }
        window.fn()
        //对象方法里的this
        const obj={
            name:'andy',
            sayHi:function(){
                console.log(this)//obj
            }
        }
        obj.sayHi()
         
         
        //箭头函数this
        const fn=()=>{
            console.log(this)//window
        }
        fn()
         
         
         
          <script>
        //对象方法箭头函数this
        const obj={
            uname:'cc',
            sayHi:()=>{
                console.log(this)//this指向window
                let i=10
                const count=()=>{
                    console.log(this)//window
                }
                count()
            }
        }
        obj.sayHi()
 
        const obj={
            uname:'cc',
            sayHi:function(){
                console.log(this)//obj,普通函数
                let i=10
                const count=()=>{
                    console.log(this)//obj
                }
                count()
            }
        }
        obj.sayHi()
    </script>

解构赋值

<script>
//数组解构:将数组的单元值批量赋值给一系列变量的简洁语法
//数组解构
const [max,min,avg]=[100,60,80]
//const max=arr[0]原写法,太麻烦
console.log(max)
console.log(min)
console.log(avg)

//交换两个数
let a=1
let b=2;//一定要加分号,1.立即执行函数要加,2.数组前要加
[b,a]=[a,b]
//原因:
const str='cc'
[1,2,3].map(function(item){
console.log(item)
})//报错,因为没分号,编译器会连起来看,所以要加分号隔开
const str='cc'[1,2,3].map(function(item){
console.log(item)
}
</script>


//防止undefined传递单元值的情况
const [a='手机',b='华为']=['小米']
console.log(a)//小米
console.log(b)//华为


//按需导入赋值
const [a,,c,d]=[1,2,3,4]
console.log(a)//1
console.log(d)//4

const arr[1,2,[3,4]]
console.log(arr[0])
console.log(arr[2][0])//3

const [a,b,c]=[1,2,[3,4]]
a:1
b:2
c:[3,4]

const [a,b,[c,d]]=[1,2,[3,4]]
a:1
b:2
c:3
d:4

对象解构

  • 属性名,变量名要相同,冲突可后面改名

 //对象解构
const obj={
uname:'cc',
age:18
}
const {uname,age}=obj//等价const uname=obj.uname,注意变量名不能冲突
//对象解构的变量名可重新改名----旧变量名:新变量名
const {uname:username,age}={uname:'cc',age:18}


//2.解构数组对象
const pig=[{
uname:'佩奇',
age:18
}]
const [{uname,age}]=pig

//多级对象解构
const pig={
name:'佩奇',
family:{
m:'猪妈妈',
f:'猪爸爸',
s:'乔治'
},
age:6
}
const {name,family:{m,f,s},age}=pig


//只提取data值
const msg={
"code":200,
"msg":"成功",
"data":[
{
"id":1,
"title":233,
"count":58
},
{
"id":2,
"title":233,
"count":58
},
]
}
//const {data}=msg
function rendr({data}) {
console.log(data)
}
rendr(msg)

 

forEach

主要用于遍历数组,当前数组元素必写,索引号可选,不返回值,加强版for循环

  被遍历的数组.forEach(function(当前数组元素,当前数组索引号){
//函数体
})


const arr=['red','green','pink']
arr.forEach(function(item,index){
console.log(item)
console.log(index)
})

filter

  • 筛选数组符合条件的元素,并且返回新数组

 const arr=[10,20,30,40]
let ar=arr.filter(function(item,index){
return item>20
})
console.log(ar)

创建对象的三种方式

//两个约定:1.命名以大写字母开头  2.只能由“new”操作符执行
//1.利用对象字面量创建对象
const o={
name:'cc'
}
//2.new Object(了解)
const ob=new Object({name:'cc'})//或
ob.name='cc'
//3.构造函数,一种特殊函数,主要用来初始化对象
//普通
const Peppa={
name:'佩奇',
age:'6',
gender:'女'
}
//构造函数
function Pig(name,age,gender){
this.name=name
this.age=age
this.gender=gender
}
const Peppa=new Pig('佩奇',6,'女')

实例成员&静态成员

实例成员:用构造函数创建的对象称为实例对象,实例对象中的属性和方法称为实例成员

静态成员:构造函数的属性和方法称为静态成员

内置构造函数

Object,Array,String,Number

  • Object:Object.keys静态方法获取对象中所有属性(键),返回的是一个数组

    const o={uname:'pink',age:18}
    //获取所有属性名
    console.log(Object.keys(o)) //['uname','age']
    //获取所有属性值
    console.log(Object.values(o))//['pink',18]
    //拷贝对象
    const oo={}
    Object.assign(oo,o)//把o拷贝给oo
    Object.assign(o,{gender:'女'})//向o添加新的gender属性
  • Array

reduce:累计器:返回累计处理的结果,经常用于求和

1.没有起始值,则上一次值以数组的第一个元素的值

2.每次循环,把返回值给下一次循环的上一次值

3.有起始值,则起始值为上一次值

arr.reduce(function(){},起始值)
arr.reduce(function(上一次值,当前值){},初始值)

//求和,无初始值
const arr=[1,5,8]
const n=arr.reduce(function(prev,current){
return prev+current
})
console.log(n)
//有初始值
const m=arr.reduce(function(prev,current){
return prev+current
},10)
console.log(m)
//箭头函数的写法
arr.reduce((prev,current)=>prev+current,10)

案例:求对象中工资总和

<script>
const arr=[{
name:'张三',
salary:10000
},{
name:'李四',
salary:10000
},{
name:'王五',
salary:5000
}]
const total=arr.reduce((prev,current)=>{
return prev+current.salary
},0)
console.log(total)
</script>
  • Array

join
find
every//检测数组所有元素是否都符合指定条件,如果有所有元素通过返回true,否则false
some//与every类似,区别是如果有元素满足返回true,否则false
concat//合并两数组
sort
splice//删除或替换原数组
reverse//反转数组
findIndex//查找元素的索引值

伪数组转换为真数组Array.from()

 const spec={size:'40cm*40cm',color:'黑色'}
//Object.velues得到的是字符串数组
console.log(Object.values(spec).join('/'))
//伪数组转化为真数组
const lis=document.querySelectorAll('ul li')
console.log(lis)
const liss=Array.from(lis)
console.log(liss)
  • String

length
split()
substring字符串截取
startsWith检测是否以某字符开头
includes
toUpperCase
toLowerCase
indexOf是否包含某字符
endsWith是否已某字符串结尾
replace用于替换字符串
match用于查找字符串
例:
<script>
const g='50g茶叶,清洗球'
document.querySelector('div').innerHTML=g.split(',').map(item=>`<span>赠品:${item}</span></br>`).join(' ')
</script>
  • Number

toFixed
<script>
const num=10.923
console.log(num.toFixed())//11,四舍五入
const num2=10.925
console.log(num2.toFixed(2))//10.93,四舍五入,保留两位小数
const num3=10
console.log(num3.toFixed(2))//10.00,保留两位小数
</script>

原型

<script>
//构造函数
//公共属性写到构造函数里
function Star(uname,age){
this.uname=uname//this指向创建的实例
this.age=age
}
//公共的方法写到原型对象身上
Star.prototype.sing=function(){
console.log('唱歌')
}
const cc=new Star('cc',20)
const zz=new Star('zz',21)
cc.sing()
zz.sing()
console.log(cc.sing===zz.sing)
</script>



<script>
Array.prototype.max=function(){
return Math.max(...this)
}
Array.prototype.sum=function(){
return this.reduce((prev,current)=>prev+current,0)
}
const arr=[1,2,3]
console.log(arr.max())
console.log(arr.sum())
</script>

constructor

<script>
//constructor构造函数
function Star(){
}
const ldh=new Star()
Star.prototype={//直接赋值了,覆盖了constructor
//重新指回创造这个原型对象的构造函数
constructor:Star,
sing:function(){

},
dance:function(){

},
}
console.log(Star.prototype)//constructor该属性指向原型构造函数,指向父亲

</script>

proto

image-20230717142838195

<script>
//__proto__指向构造函数的prototype原型对象,[[prototype]]和__proto意义一样
//对象原型
function Star(){}
const cc=new Star()
//对象原型__proto__,包含在实例对象里
//原型对象prototype,由构造函数创造出的
//对象原型里面有constructor 指向 构造函数 Star
console.log(cc.__proto__===Star.prototype)

</script>

原型继承

<script>
//原型继承
//父构造函数(父类) 总构造函数(子类)
//子类的原型=new 父类
function Person(){
this.eyes=2
this.head=1
}
function Woman(){

}
Woman.prototype=new Person()
Woman.prototype.constructor=Woman
Woman.prototype.bb=function(){
console.log('22')
}
function Man(){

}
Man.prototype=new Person()
Man.prototype.constructor=Man
const ma=new Man()
const red=new Woman()
console.log(red.bb())
</script>

原型链

查找规则

1.当访问一个对象属性时,首先查找这个对象自身有没有该属性

2.如果没有就查找他的原型(也就是_ proto_ 指向的prototype原型对象)

3.如果还没有就查找原型对象的原型(Object的原型对象)

4.以此类推一直找到Object为止(null)

5._ _proto __对象原型的意义就在于为对象成员查找提供一个方向

6.可以使用instanceof运算符用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上

例子:
[1,2,3] instanceof Array//true

综合案例:36-综合案例close封装以及小结哔哩哔哩bilibili

p34

<script>
function Modal(title=' ',message=' '){
this.modalBox=document.createElement('div')
this.modalBox.className='model'
this.modalBox.innerHTML=`
<div class="header">${title}<i>×</i></div>
<div class="body">${message}</div>
`
console.log(this.modalBox)
}
Modal.prototype.open=function(){
const box=document.querySelector('.model')
box&&box.remove()
document.body.append(this.modalBox)
this.modalBox.querySelector('i').addEventListener('click',()=>{
this.close()
})
}
Modal.prototype.close=function(){
this.modalBox.remove()
}
document.querySelector('#delete').addEventListener('click',()=>{
const del=new Modal('温馨提示','您没有删除权限')
del.open()
})
document.querySelector('#login').addEventListener('click',()=>{
const opn=new Modal('友情提示','您还没有登录')
opn.open()
})

</script>

深浅拷贝

  • 浅拷贝


<script>

const obj={
name:'cc',
age:'18',
family:{
bb:'yy'
}
}
let o=obj//浅拷贝,拷贝地址,改变o时obj也会改变
const ob={...obj}//浅拷贝,改变ob时obj不会改变,但family.bb会改变
Object.assign(objj,obj)//浅拷贝,改变objj时obj不会改变,但family.bb会改变
//拷贝对象之后,里面的属性值是简单数据类型直接拷贝值,引用数据类型则拷贝地址

</script>
  • 深拷贝

<script src="../node_modules/lodash/lodash.js"></script>
<script>
//1.通过递归实现深拷贝
//2.lodash/cloneDeep
//3.通过JSON.stringify()实现

const obj={
uname:'cc',
age:18,
hobby:['篮球','足球'],
family:{
baby:'cc'
}
}
const o={}
//1.通过递归实现,拷贝函数,先数组再对象
function deepCopy(newObj,oldObj){
for(let k in oldObj){
if(oldObj[k] instanceof Array){
newObj[k]=[]
deepCopy(newObj[k],oldObj[k])
}else if(oldObj[k] instanceof Object){
newObj[k]={}
deepCopy(newObj[k],oldObj[k])
}else{
newObj[k]=oldObj[k]
}
}
}
deepCopy(o,obj)

//2.lodash
//下载:1. 在项目 终端 先初始化 npm init -y
//2.安装 lodash : npm install lodash
//使用要在前面先引入
const ob=_.cloneDeep(obj)


//3.JSON.stringify()把对象转换为JSON字符串,转换为简单数据类型再复制转换
const objj=JSON.parse(JSON.stringify(obj))//JSON.parse把字符串转换为对象
console.log(objj)
</script>

异常处理

<p>123</p>
<script>
//throw
function fn(x,y){
if(!x||!y){
throw new Error('用户没有参数传递进来')
}
return x+y
}
console.log(fn())//下面代码就不执行了,中断

//try/catch
function fnn(){
try{
//可能发生错误的代码要写到try
const p=document.querySelector('.p')
p.style.color='red'
}catch(err){
//拦截错误,提示浏览器提供的错误信息,但是不中断
console.log(err.message)
//1.加return终端程序
//2.throw new Error('中断')
}
finally{
//不管你程序对不对,一定会执行的代码
}
}
fnn()
//debugger,相当于打一个断点
debugger//直接到这

</script>

处理this

普通函数this:谁调用指向谁

严格模式:指向undefined

箭头函数默认绑定外层this,和外层this一样,一层一层往外找,直到找到window

  • 改变this

 <script>
//call()调用函数,同时指定被调用函数中的this的值
//fun.call(thisArg,arg1,arg2)

//apply()
//fun.apply(thisArg,[argArray])传递的值必须包含在数组里,返回值就是调用函数的返回值

//bind()不会调用函数
//fun.bind(thisArg,arg1,arg2)
const obj={
age:18
}
function fn(){
console.log(this)
}
//bind 不会调用函数,改变this指向
const fun=fn.bind(obj)//返回值是个函数,但是函数中的this是被更改过的
</script>

防抖

单位时间内,频繁触发事件,只执行最后一次

<script>
//1.lodash提供的防抖来处理
// _.debounce(mouseMove,500)要执行函数,间隔多少秒
const box=document.querySelector('.box')
let i=1
function mouseMove(){
box.innerHTML=i++
//如果里面存在大量操作可能卡顿

}
//box.addEventListener('mousemove', _.debounce(mouseMove,500))

//2.手写一个防抖函数来处理
//核心是用定时器来实现的(setTimeout)
//1.声明定时器变量
//2.每次鼠标移动时判断是否有定时器,如果有先清除以前的定时器
//3.没有则开启定时器,存入到定时器变量里
//4.定时器里面写函数调用
function debounce(fn,t){
let times
return function(){//写return的原因是,如果不返回一个方法,
//debounce(mouseMove, 500)立即调用了debounce函数,并将结果作为mousemove事件的事件监听函数。这意味着debounce函数在事件绑定时只调用一次。
if(times)clearTimeout(times)
times=setTimeout(function(){
fn()
},t)
}
}
box.addEventListener('mousemove',debounce(mouseMove,500))
</script>

补充setTimeout

当调用 setTimeout 函数时,它会返回一个唯一的计时器标识符(一个数字)。这个标识符可以用于后续对计时器的操作,比如取消计时器。

setTimeout 函数用于在一定的时间延迟后执行指定的代码或函数。它接受两个参数:要执行的代码或函数以及延迟的毫秒数。例如:

javascriptCopy codeconst timerId = setTimeout(() => {
console.log("Delayed function");
}, 1000);

在上述代码中,setTimeout 函数会在 1000 毫秒(1秒)后执行传入的箭头函数,并返回一个唯一的计时器标识符,将其赋值给 timerId 变量。

要取消计时器的执行,可以使用 clearTimeout 函数,并传入相应的计时器标识符。例如:

javascriptCopy code
clearTimeout(timerId);

上述代码将取消之前创建的计时器,阻止其执行。注意,需要传入的参数是之前调用 setTimeout 时返回的计时器标识符。

通过使用 setTimeoutclearTimeout 结合,可以在指定的时间间隔后执行代码,并在需要时取消执行。这在实现诸如防抖(debounce)或节流(throttle)等操作时非常有用。

节流

单位时间内,频繁触发事件,只执行一次

高频事件:鼠标移动,页面缩放,滚动条等

<script>
//1.lodash节流函数
const box=document.querySelector('.box')
let i=1
function mouseMove(){
box.innerHTML=i++
}
//box.addEventListener('click',_.throttle(mouseMove,1000))

//2.手写
function throttle(fn,t){
let times=null
return function(){
if(!times){
times=setTimeout(function(){
fn()
times=null//在setTimeout中无法删除定时器,因为定时器还在运作,所以使用times=null
},t)
}
}
}
box.addEventListener('mousemove',throttle(mouseMove,500))
</script>
  • ontimeupdate

  • onloadeddata

posted @ 2023-07-04 09:30  l希尔瓦娜斯l  阅读(28)  评论(0)    收藏  举报