前端学习小白打卡16-结束js

局部作用域分为函数作用域和块作用域
块作用域
在js中用{}包裹的代码被称为代码块,代码块内部声明的变量外部有可能无法被访问,var定义的变量除外
let,const声明的变量和常量会产生块作用域,var不会

全局作用域:
<script>标签和.js文件的最外层就是全局作用域,在此声明的变量在函数内部也能被访问
为window对象动态添加的属性默认也是全局的,但不推荐
函数中未使用任何关键字声明的变量也是全局变量,不推荐
尽可能少的声明全局变量,防止全局变量被污染

作用域链:
本质上是底层的变量查找机制
函数被执行时,会优先查找当前函数作用域中,查找变量
如果当前作用域查找不到则会依次逐级查找父级作用域直到全局作用域

垃圾回收机制  简称GC
js中内存的分配和回收都是自动完成的。内存在不使用的时候会被垃圾回收器自动回收

内存的生命周期
内存分配。内存使用。内存回收:使用完毕,由垃圾回收器自动回收不再使用的内存
内存泄漏:程序中分配的内存由于某种原因程序未释放或无法释放叫做内存泄漏
栈:有操作系统自动分配释放函数的参数值,局部变量等。基本数据类型都放栈里面 
堆:一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收,复杂数据类型放到堆里面

 引用计数:
 IE采用的引用计数算法,定义“内存不再使用”。就是看一个对象是否有指向它的引用,没有引用了就回收对象
 算法:
 跟踪记录被引用的次数,被引用一次,那么就记录次数1,多次引用则累加++,减少一个引用就减1--,若为0则释放
 存在问题,嵌套引用(循环),如果2个对象相互引用,尽管他们不再使用,但不会进行回收,导致内存泄漏
标记清楚法:
 现在的浏览器已经不再使用引用计数法了,但大多是基于标记清除的某些改进
 核心:
 标记清除将不再使用的对象,定义为无法达到的对象
 就是从根部出发定时扫描内存中的对象,凡是能从根部达到的对象,都还需要使用
 不能从根部出发触及到的对象被标记为不再使用,进行回收

 闭包:
 一个函数对周围状态的引用捆绑在一起,内层函数中访问到其外层函数的作用域
 闭包=内层函数+外层函数的变量

 function outer(){
    let a=10
    function fn()
    {
        console.log(a)
    }
    return fn
 }
 outer()

 闭包应用:实现数据私有

function fnf(){
    let i=0
    function fn(){
        i++
    }
    return fn()

}
const re=fnf()
re()
re()
闭包会有内存泄漏


变量提升
把所有的var声明的变量提升到当前作用域的最前面
只提升声明,不提升赋值
变量在未声明即被访问时会报语法错误
变量var声明之前即被访问,变量的值为undefined
let/const声明的变量不存在变量提升
变量提升出现在相同作用域中
实际开发中推荐先声明再访问变量

函数提升
把所有的函数声明提升到当前作用域的最前面
只提升声明,不提升调用
函数表达式必须先声明和赋值,后调用否则报错

动态参数
arguments是函数内部内置的伪数组变量,它包含了调用函数时传入的所有实参
剩余参数
剩余参数允许我们将一个不定数量的参数表示为一个数组
...是语法符号,置于最末函数形参之前,用于获取多余的实参
借助...获取的剩余实参是个真数组
开发中提倡剩余函数

展开运算符
...将一个数组进行展开
const arr=[1,2,3,4,5]
console.log(...arr)//1 2 3 4 5
不会修改原数组
典型应用场景:求数组最大值(最小值),合并数组
console.log(Math.maax(...arr))
const arr2=[6,7,8]
const arr4=[...arr,...arr2]

箭头函数
目的:引入箭头的目的是更简短的函数写法并且不绑定this,箭头函数的语法比函数表示式更简洁
使用场景:箭头函数更适用于那些本来需要匿名函数的地方
const fn=function(){
    console.log(12)
}
fn()
const f=()=>{
    console.log(1)
}
f()

// const f=(x)=>{
//     console.log(x)
// }
// f(1)
//只有一个形参的时候可以省略小括号
const f=x=>{
    console.log(x)
}
f(1)
只有一个形参,省大括号
const f=x=> console.log(x)
f() 
只有一个形参,省return
const f =x=>x+x
return 都可以省略
可以直接返回一个对象
const fn=(uname)=>({uname:uname})
箭头函数属于表达式函数,不存在函数提升
箭头函数没有arguments动态参数,但是有剩余参数...args
箭头函数不会创建自己的this,会沿用作用域链上一级的 
在开发中,事件回调函数使用箭头函数时,this为全局的window,DOM事件回调函数为了简便,不太推荐使用箭头函数

数组解构
数组解构是将数组的单元值快速批量给一系列变量的简洁语法
语法:
赋值运算符=左侧的[]用于批量声明变量,右侧数组的单元值将被赋值给左侧的变量
变量的顺序对应数组单元值的位置依次进行赋值

典型应用:数据交换
let a=1
let b=2;//必须有分号
[b,a]=[a,b]

js前面必须加分号情况
1.立即执行函数
(function t(){})();
或则
;(function t(){})()
2.数组解构
;[b,a]=[a,b]

const [a,b,...c]=[1,2,3,4]
防止undefined传递
const [a=0,b=0]=[]

按需传值
const [a,b, ,d]=[1,2,3,4]
多维数组
const [a,b,c]=[1,2,[3,4]]
const [a,b,[c,d]]=[1,2,[3,4]]

const {uname,age}={uname:'pink',age:18}
要求属性名和变量名必须一致才行
可以重新改名
const {uname:username ,age}={uname:'pink',age:18}
旧变量:新变量

const [{uname,age}]=[{
    uname:'佩奇',
    age:6
}
]
const pig={
    name:'佩奇',
    family:{
        mother:'猪妈妈',
        father:'1',
        sister:'3'
    }
    age:5
}
const {name,family:{mother,father,sister}}=pig

遍历数组foreach
forEach()方法用于调用数组的每个元素,并将元素传递给回调函数
语法:
被遍历的数组.forEach(function(当前数组元素,当前数组元素索引号){
})
const arr1=['h','2','r']
arr1.forEach(function(item,index){
    console.log(item)
    console.log(index)
})
参数当前数组元素是必须要写的,索引号可选
不返回值

const ar=[10,20,30]
const newAr=arr.filter(function(item,index)
{
    return item>=20
})
console.log(newAr)[20,30]
筛选数组filter方法
filter()方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素
参数:currentValue必须写,(item),index可选


创建对象的三种方式
1.利用对象字面量创建对象
const o={
    name:'佩奇'
}
2.利用new object创建对象
const o=new Obeject({name:'喷漆'})
3.利用构造函数创建对象

构造函数:
特殊的一种函数,主要用来初始化对象
函数命名以大写字母开头
只能由"new"操作符来执行
function Pig(uname,age){
    this.uname=uname
    this.age=age
}
const p=new Pig('佩奇',6)

使用new关键字调用函数的行为被称为实例化
实例化构造函数时没有参数可以省略()
构造函数内部无需写return,返回即为新创建的对象
构造函数内部的return返回的值无效
new Object() new Date() 也是实例化构造函数

通过构造函数创建的对象称为实例对象,实例对象中的属性和方法称为实例成员(实例属性和实例方法)
静态成员:
构造函数的属性和方法被称为静态成员(静态属性和静态方法)

内置构造函数
字符串,数值,布尔,等基本类型也都有专门的构造函数,这些我们称为包装类型
js中几乎所有的数据都可以基于构成函数创建
静态方法就是只有构造函数Object可以调用
eg:
const o={name:'佩奇',age:6}
for(let k in o)
{
    console.log(k)//属性,name age
    console.log(o[k])//值 佩奇 6
}

Object.keys静态方法获取对象中所有属性(键)
values获得属性值
语法:
const o={name:'佩奇',age:6}
const arr=Obeject.key(o)
console.log(arr)//['name','age']
const arr=Obeject.values(o)//'佩奇',6
返回的是一个数组

Object.assign 静态方法常用于对象拷贝,也可以追加属性
const o={name:'佩奇',age:6}
const obj={}
Obeject.assign(obj,o)

Array
是内置的构造函数,用于创建数组
const arr=new Array(3,5)
console.log(arr)//[3,5]
创建数组建议使用字面量创建,不用Array构造函数创建
核心方法
forEach 遍历数组 不返回数组,经常用于查找遍历数组元素
filter 过滤数组 返回新数组,返回的是筛选满足条件的数组元素
map 迭代数组 返回新数组,返回的是处理之后的数组元素,想要使用返回的新数组
reduce 累计器 返回累计处理的结果,经常用于求和
语法:arr.reduce(function(){},起始值)
arr.reduce(function(上一次值,当前值){},初始值)

const earr=[1,5,8]
const total=earr.reduce(function(prev,current){
    return prev+current
})
//14
const total1=earr.reduce(function(prev,current){
    return prev+current
},10)//24

// 箭头函数
const total2=earr.reduce((prev,current)=>prev+current,10)//24

如果没有初始值,则上一次值以数组的第一个数组元素的值
每一次循环,把返回值给作为下一次循环的上一次值
如果有起始值,则起始值作为上一次值

如果是对象数组,则reduce第二个参数一定不能省略(为0)
const ar=[
    {
        name:'w',
        salary:100
    },{
        name:'e',
        salary:200
    }
]
const total=ar.reduce((prev,current)=>{
    return prev+current.salary
},0)

2.数组常见方法-其他方法
5.实例方法join 数组元素拼接为字符串,返回字符串(重点)
6.实例方法 find 查找元素,返回符合测试条件的第一个数组元素值,如果没有符合条件的则返回undefined(重点)
7.实例方法every 检测数组所有元素是否都符合指定条件,如果所有元素都通过检测返回true,否则返回 false(重点)
8.实例方法 some 检测数组中的元素是否满足指定条件 如果数组中有元素满足条件返回true,否则返回 false
9.实例方法 concat合并两个数组,返回生成新数组
10.实例方法 sort 对原数组单元值排序
11.实例方法 splice 删除或替换原数组单元
12.实例方法 reverse 反转数组
13.实例方法 findIndex 查找元素的索引值

string  常见实例方法
1.实例属性length 用来获取字符串的度长(重点)
2.实例方法 split('分隔符')用来将字符串拆分成数组(重点)
3.实例方法 substring(需要截取的第一个字符的索引[,结束的索引号]) 用于字符串截取(重点)
结束的索引号,不包括在截取的字符串内
4.实例方法 startswith(检测字符串[,检测位置索引号])检测是否以某字符开头(重点)
5.实例方法 includes(搜索的字符串[,检测位置索引号])判断一个字符串是否包含在另一个字符串中,根据情况返回true或false(重点)
6.实例方法 toUppercase 用于将字母转换成大写
7.实例方法toLowerCase 用于将就转换成小写
8.实例方法indexof检测是否包含某字符
9.实例方法 endsWith 检测是否以某字符结尾
10.实例方法 replace用于替换字符串,支持正则匹配
11.实例方法 match 用于查找字符串,支持正则匹配

number 是内置的构造函数,用于创建数值
方法:
toFixed()设置保留小数位的长度 ,保留2位,四舍五入
关于小数精度问题:
0.1+0.2=?
解决方案:转换为整数
(0.1*100+0.2*100)/100=0.3

面向对象的特性
封装性,继承性,多态性

function Star(uname,age){
    this.uname=uname
    this.age=age
    this.sing=function(){
        console.log('cangge')
    }
}
const ldh= new Star('刘德华',19)
封装,构造函数实例化创建的对象彼此独立,互不影响
存在浪费内存的问题

原型 可以规避内存浪费的问题
原型
构造函数通过原型分配的函数时所有对象所共享的
js规定,每一个构造函数都有一个prototype属性,指向一个对象,所以我们称为原型对象
这个对象可以挂在函数,对象实例化不会多次创建原型上函数,节约内存
可以把不变的方法,直接定义在prototype对象上,这样所有的对象的实例就可以共享这些方法
构造函数和原型对象中的this都指向实例化对象

function Star(uname,age){
    this.uname=uname
    this.age=age
}
Star.prototype.sing=function(){
    console.log('唱歌')
}
const ldh= new Star('刘德华',19)
ldh.sing()

公共的属性写到构造函数里面
公共的方法写到原型对象里面

每个原型对象里面都有constructor属性(constructor构造函数)
该属性指向该原型对象的构造函数 

Star.prototype={
    siang:function(){},
    dang:function(){}
}
这个赋值操作会把constructor顶掉,需要重新指回指向对象
Star.prototype={
    constructor:Star,
    siang:function(){},
    dang:function(){}
}

对象都有一个属性 _proto_指向构造函数的prototype原型对象,之所以我们对象可以使用构造函数prototype原型对象的属性和方法,就是因为对象有 _protp原型的存在
_proto_是js非标准属性
[[prototype]]和_proto意义相同
对象原型_proto_指向该构造函数的原型对象
_proto_对象原型里面也有一个construct属性,指向创建该实例对象的构造函数

js 通过原型对象来实现继承
function Person(){
    this.eyes=2
    this.head=1
}
function Woman(){

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


原型链
基于原型对象的继承使得不同构造函数的原型对象关联在一起,并且这种关联的关系是一种链状的结构,将对原型对象的链状结构关系称为原型链
查找规则
1当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。
2如果没有就查找它的原型(也就是__proto__指向的prototype原型对象)
3如果还没有就查找原型对象的原型(Object的原型对象)
40依此类推一直找到Object 为止(null)
5 _proto_对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线
⑥可以使用 instanceof运算符用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上

1.1浅拷贝
首先浅拷贝和深拷贝只针对引用类型
浅拷贝:拷贝的是地址
常见方法:
1.拷贝对象:Object.assgin()/展开运算符{...obj}拷贝对象
2.拷贝数组:Array.prototype.concat()或者 [...arr]

如果是简单数据类型拷贝值,引用数据类型拷贝的是地址(单层对象没问题,多层就有问题)

直接赋值的方法,只要是对象,都会相互影响,直接拷贝地址

1.2 深拷贝
首先浅拷贝和深拷贝只针对引用类型深拷贝:拷贝的是对象,不是地址常见方法:
1.通过递归实现深拷贝
2. lodash/cloneDeep
js库lodash里面cloneDeep内部实现了深拷贝
3.通过JSON.stringify()实现

throw抛异常
异常处理是指预估代码执行过程中可能发生的错误,然后最大程度的避免错误的发生导致整个程序无法继续运行

function fnn(x,y){
    if(!X||!y)
    {
        throw new Error('没有参数传入')
    }
    return x+y
}

1.throw抛出异常信息,程序也会终止执行
throw 后面跟的是错误提示信息
Error对象配合throw使用,能够设置更详细的错误信息

try/catch 捕获错误信息
try 试试 catch 拦住 finally 最后
//<p>123<p>
function d1(){
    try{
        //可能发生错误的代码 写进try
        const p=document.querySelector('.p')
        p.slyle.color='red'
    }catch(err)
    {//拦截错误,提示浏览器提供的错误信息,但是不中断程序执行
        console.log(err.message)
        throw new Error('你看看,选择器错误了')
        //需要加return中断
        //return
    }
    finally{
        //不管程序对不对,一定会执行的代码
        alert('111')
    }
}

debugger
在程序中写入这句,浏览器中跳转到代码处,进行调试

严格模式
在js前加一句
'use strict'
在该模式下,若没有调用者时this的值为undefined
this在箭头函数下是一层一层的找
注意情况:
在开发中,使用箭头函数需要考虑函数中this的值
事件回调函数使用箭头函数时,this为全局window
因此DOM时间回调函数如果里面需要DOM对象的this,则不推荐使用箭头函数
改变this指向
js中还允许了指定函数中this的指向,有3个方法可以动态指定普通函数中的this指向
call()
fun.call(thisArg,arg1,arg2,.....)
thisArg:在fun函数运行时指定的this值
arg1,arg2:传递的其他参数(原函数的)
返回值就是函数的返回值,因为它就是调用函数

apply()
使用apply方法调用函数,同时指定被调用函数中this的值
fun.apply(thisArg,[argsArray])
thisArg:在fun函数运行时指定的this值
argsArray:传递的值,必须包含在数组里面
返回值就是函数的返回值,因为它就是调用函数
因此apply主要跟数组有关系,比如使用Math.max()求数组的最大值

bind()
bind()方法不会调用函数,但是能改变函数内部的this指向
fun.bind(thisArg,arg1,arg2,...)
thisArg:在fun函数运行时指定的this值
arg1,arg2:传递的其他参数(原函数的)
返回由指定的this值和初始化参数改造原函数拷贝(新函数)
因此当我们只是想改变 this指向,并且不想调用这个函数时,可以用bind(),比如改变定时器内部的this指向

防抖
防抖:单位时间内,频繁触发事件,只执行最后一次
使用场景:
搜索框搜索输入,只需用户最后一次输入完,再发送请求
手机号,邮箱验证输入检测
实现方式:
lodash提供了防抖处理
手写防抖函数处理 
防抖的核心就是利用定时器(setTimeout)来实现

//防抖函数
function debounce(fn,t)
{
    let timer
    return function(){
        if(timer) clearTimeout(timer)
        timer=setTimeout(function(){
            fn()
        },t)
     }
}


lodash库需要安装npm


节流-throttle
节流:单位时间内,频繁触发事件,只执行一次
例子:
王者荣耀中技能冷却期间无法继续释放技能
使用场景:高频事件:鼠标移动mousemove,页面尺寸缩放resize,滚动条滚动scroll

在setTimeout中是无法删除定时器的,因为定时器还在运作,所有使用timer=null

//节流
function throttle(fn,t)
{
    let timer=null
    return function(){
        if(!timer)
        {
            timer =setTimeout(function(){
                fn()
                timer=null
            },t)
        }
    }
}

js

function getSum()
{
    let sum=0
    for(let i=0;i<arguments.length;i++)
    {
        sum+=arguments[i]
    }
}
getSum(1,2)
getSum(1,2,2,2,22,2,1)


function getSu1m(a,b,...arr)
{
console.log(arr)
}
getSu1m(1,2)
getSu1m(1,2,2,2,22,2,1)

// const fn=function(){
//     console.log(12)
// }
// fn()
// const f=()=>{
//     console.log(1)
// }
// f()
// const f=(x)=>{
//     console.log(x)
// }
// f(1)
//只有一个形参的时候可以省略小括号
// const f=x=>{
//     console.log(x)
// }
// f(1)

// const f=x=> console.log(x)
// f()
const f =x=>x+x

const fn=(uname)=>({uname:uname})

const arr=[100,20,60]
const [m,n,b]=arr
const [max,min,avg]=[100,60,80]

const arr1=['h','2','r']
arr1.forEach(function(item,index){
    console.log(item)
    console.log(index)
})

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

function Pig(uname,age){
    this.uname=uname
    this.age=age
}
Pig.eyes=2//静态属性
Pig.saiHi=function(){//静态方法
    console.log(this)
}
const p=new Pig('佩奇',6)


const earr=[1,5,8]
const total=earr.reduce(function(prev,current){
    return prev+current
})
//14
const total1=earr.reduce(function(prev,current){
    return prev+current
},10)//24

// 箭头函数
const total2=earr.reduce((prev,current)=>prev+current,10)//24

// Array.from(Lis) 把伪数组转换为真数组
const lis = document.querySelectorAll('ul li')// console.log(Lis)
// Lis.pop() 报错
const liss = Array.from(lis)
liss.pop()
console.log(liss)

function Star(uname,age){
    this.uname=uname
    this.age=age
    // this.sing=function(){
    //     console.log('cangge')
    // }
}
Star.prototype.sing=function(){
    console.log('唱歌')
}
const ldh= new Star('刘德华',19)
ldh.sing()




// const Person={
//     eyes:2,
//     head:1
// }

// function womam(){

// }
// //通过原型来继承person
// womam.prototype=Person
// womam.prototype.constructor=woman
// const red=new woman()
 
function Person(){
    this.eyes=2
    this.head=1
}
function Woman(){

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


const obj={
    uname:'pink',
    age:18
}
const o={}
function deepcopy(newObj,oldObj){
    for(let k in oldObj)
    {
        newObj[k]=oldObj[k]
    }
}
deepcopy(o,obj)
console.log(o)
o.age=20
console.log(obj)

function deepcopy(newObj,oldObj){
    for(let k in oldObj){
    if (oldObj[k] instanceof Array)//oldObj[k]是否属于数组 
    {
        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]
    }
    }
}

const o=JSON.parse(JSON.stringify(obj))


function fnn(x,y){
    if(!X||!y)
    {
        throw new Error('没有参数传入')
    }
    return x+y
}

//<p>123<p>
function d1(){
    try{
        //可能发生错误的代码 写进try
        const p=document.querySelector('.p')
        p.slyle.color='red'
    }catch(err)
    {//拦截错误,提示浏览器提供的错误信息,但是不中断程序执行
        console.log(err.message)
        throw new Error('你看看,选择器错误了')
        //需要加return中断
        //return
    }
    finally{
        //不管程序对不对,一定会执行的代码
        alert('111')
    }
}


//防抖函数
function debounce(fn,t)
{
    let timer
    return function(){
        if(timer) clearTimeout(timer)
        timer=setTimeout(function(){
            fn()
        },t)
     }
}

//节流
function throttle(fn,t)
{
    let timer=null
    return function(){
        if(!timer)
        {
            timer =setTimeout(function(){
                fn()
                timer=null
            },t)
        }
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

白潏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值