前端学习笔记 | JS进阶

一、作用域

1、局部作用域

(1)函数作用域

(2)块作用域

let和const会产生块作用域  ,而var不会产生块作用域

2、全局作用域

script标签和js文件的【最外层】变量

3、作用域链

本质:底层的变量查找机制

4、JS垃圾回收机制(GC)

(1)内存的生命周期

  • 内存分配
  • 内存使用
  • 内存回收

(2)算法说明

  • 引用计数法:嵌套循环容易使内存泄漏
  • 标记清除法:从全局出发,找不到就回收

5、闭包

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

作用:外部访问局部变量、局部函数

function outer(){let i=1return function(){console.log(i)}
}
const fun = outer()
fun()

应用:实现数据的私有,外部无法直接修改变量

注:容易引起内存泄漏

6、变量提升

 JS的缺陷(使用var的时候):代码执行前会将所有的var声明的变量提升到当前作用域的最前面,只提升变量声明,不提升变量声明——不建议

二、函数进阶

1、函数提升

2、函数参数

(1)动态参数(不推荐)

数组arguments:不管拿多少变量,都能获取到。

方法:不用形参,函数内部直接使用arguments

缺点:伪数组

(2)剩余参数(推荐)

arr获取的是多余的实参,是真数组,可以使用数组方法

function getSum(a,b,...arr)

...arr是展开数组

3、箭头参数

(1)特点

替代匿名函数

属于表达式函数,不存在函数提升

(2)基本语法

//基本写法
const fn = () =>{ }//只有一个形参的时候可以省略小括号
const fn= x => { }//只有一个形参的时候可以省略大括号
const fn= x => console.log(x)//只有一行代码可以省略return
const fn= x => return x+x
const fn= x => x+x//箭头函数可以直接返回一个对象
const fn= (unname) => ({uname:uname})

(3)箭头函数参数

普通函数有arguments,箭头函数没有

(4)箭头函数this

this指的是对象

箭头函数的this指向上一层作用域的this

三、解构赋值

1、数组解构

将数组单元值快速批量赋值给变量的简洁语法

const arr = [100,60,80]
const [max,min,avg ] =arr
等同于
//const max=arr[0]
//const min=arr[1]
//const avg=arr[2]

典型应用:交换两个变量的值

let a=1
let b=2
;[b,a]=[a,b] //这里必须加分号

补充:必须加;的情况

  • 立即执行函数
(function(){})();
  • 数组的时候:数组开头的
const str='pink';
[1,2,3].map(function(item)){}

2、对象解构

将对象属性和方法快速批量赋值给变量的简洁语法

(1)基本

const[{uname,age}]=obj

(2)多级对象

复合对象需要在前面加一个名字

const pig={name:'佩奇'family:{mother:'猪妈妈'father:'猪爸爸'sister:'乔治'}age:6
}const [{name,family:{mother,father,sister}}]=pig

 四、数组forEach遍历和filter筛选

1、forEach语法

(1)语法

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

(2)作用

主要遍历数组——加强版for循环

和map(返回数组)的区别,不返回值

2、filter方法

(1)语法

const arr=[10,20,30]
arr.filter(funtion(item,index){return item>=20
})

(2)特点

用于筛选数组

函数返回生成一个新数组

 五、深入对象

1、创建对象三种方式

(1)通过字面量

const o={name:'佩奇'
}

(2)利用new Object创建对象

const o=new Object({name:'佩奇'})
console.log(o)

(3)利用构造函数创建对象

2、构造函数

(1)是什么

特殊函数,用于初始化对象

(2)语法

function pig(name){this.name=name
}
const peppa=new Pig('佩奇') //实例化

3、实例成员&静态成员

(1)实例成员

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

(2)静态成员

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

  • 静态成员只能构造函数来访问
  • 静态方法中的this指向构造函数

4、内置构造函数

(1)Object 

  • Object.keys(o) 
  • Object.values(o) 
  • Object.assign(新对象,原对象) 
const o={name:'佩奇',age:6}
Object.keys(o) //返回数组['uname','age']
Object.values(o) //返回数组['佩奇','6']

(2)Array

  • forEach
  • filter
  • map
  • join

  • reduce 返回累计处理结果,经常用于求和
arr.reduce(function(上一次值,当前值){},初始值)

如果需要累加的是对象数组,初始值必须写0

  • find

找出符合的对象

const arr=[
{name:'小米',price:1999},
{name:'华为',price:3999}
]const mi=arr.find(function(item)){return item.name==='华为'
}//返回{name:'小米',price:1999}
  • every

  • some
  • from

把伪数组转换成真数组,可使用pop、push等

  • ...

(3)String

  • length
  • split('分隔符')  分割字符串
  • substring(需要截取的第一个字符的索引[,结束的索引号])  窃取字符串
  • startwith(检测字符串[,检测位置索引号]) 从索引值搜索是否以目标字符串开头
  • endwith(检测字符串[,检测位置索引号])  从索引值搜索是否以目标字符串结束
  • includes(搜索的字符串[,检测位置索引号])  判断是否包含  
  • ... 

(4)Number

  • toFixed(保留位数) 让数字指定保留的位数,默认整数

 六、深入面向对象

1、编程思想

  • 面向过程:面向函数
  • 面向对象
    • 封装性
    • 继承性
    • 多态性

2、构造函数

优点好用,缺点浪费内存——e.g一个对象相同方法但是不等

this指向实例化对象

3、原型对象prototype

能够利用原型对象实现方法共享——原型对象的函数和构造函数都指向实例化对象(this)

公共属性写在构造函数里

公共方法写在原型对象里

function Star(uname,age){this.uname=unamethis.age=age
}
Star.prototype.sing=function(){}

4、 constructor属性

指向原型对象的构造函数

prototype和__proto__均有

5、对象原型_proto_

对象都有一个属性_proto_指向构造函数的prototype原型对象

  • JS非标准属性
  • [[prototype]]和__proto__意义相同
function Star(){}
const ldh =new Star()
console.log(ldh.__proto__ === Star.prototype) //true

6、原型继承

const person={eyes:2,head:1
}
function Woman(){
}Woman.prototype=person
Woman.prototype.constructor=Woman

缺点:继承同一个person,新加方法会有问题

=>用构造函数的写法

7、原型链

基于原型对象的继承使得不同构造函数的原型对象关联在一起

什么是原型链?——一种查找规则:为对象成员查找机制提供一个方向

8、instanceof 

作用:判断对象属不属于原型链上

const ldh=new person()
console.log(ldh instanceof person) //true
console.log(ldh instanceof Object) //true

七、 模态框封装(案例)

1、modalBox 模态框属性

2、(打开模态框)设置open挂载点,页面显示模态框是在open里面

3、(关闭模态框)在open中添加关闭的绑定事件close

注:BUG-会打开多个——先判断,有就移除,没有就添加

box&&box.remove() //逻辑中断,有box则后面不执行,无则执行box.remove()

 八、深浅拷贝

1、深浅拷贝(只针对引用类型)

(1)浅拷贝——简单数据类型拷贝值,引用数据类型拷贝地址

  • 拷贝对象:Object.assign(新对象,旧对象) | 展开对象{...obj}
    • 缺点:复杂对象拷贝会出现问题
  • 拷贝数组 :Array.prototype.concat() | 展开数组[...arr]

(2)深拷贝——拷贝的是对象不是地址

  • 方法1:通过递归(=自己调自己)实现深拷贝
//递归函数
function getTime(){document.querySelector('div').innerHTML= new Date().toLocalString()setTimeout(getTime,1000)
}
getTime()
//深拷贝的方法——做到新对象不会影像旧对象
//1、运用函数递归的方法
//2、如果是普通的,则直接赋值;遇到数组,需要再次调用递归函数。遇到对象,同样再次调用递归函数。
//3、先Array后对象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]}}
}
  • 方法2:利用lodash
//1、引用lodash.min.js
<script src="./lodash.min.js"></script>
//2、用_cloneDeep(拷贝对象)方法进行深拷贝
<script>const obj={uname:'pink',age:18,hobby:['乒乓球','足球'],family:{baby:'小pink'    }
}const o =_.cloneDeep(obj)
</script>
  • 方法3:利用JSON
//利用JSON.stringify()把JSON转换为字符串
//JSON.parse可以将字符串转换为对象//因为通过对象转换成字符串再转为对象,和原来的对象已经不一样了,修改新对象不会被影响
const o=JSON.parse(JSON.stringify(obj))

九、 异常处理

1、throw 抛异常

//会自动抛出异常并中断程序
//经常配合Error使用function counter(x,y){if(!x || !y){throw new Error("没有参数传递过来")}return x+y
}
counter()

2、try/catch/finally 捕获异常

//可能发生错误的代码,要写到try
//拦截错误,提示浏览器提供的错误信息,但不中断程序的执行function fn(){try{const p=document.querSelector('.p')p.style.color='red'}catch(err){console.log(err.message)throw new Error("你看看,选择器错误了吧")}finally{//finally 不管你程序对不对,一定会执行的代码alert("执行")}
}

3、debugger

打断点——可以直接跳转到改行代码调试

十、处理this

1、this指向

(1)普通函数的指向:谁调用指向谁

//1、指向window
(1)
console.log(this) //指向window
(2)
function fn (){console.log(this)
}  //指向window
(3)
setInterval(function(){console.log(this)
},1000) //指向window
(4)
<button>点击</button>
document.querySelector('button').addEventLisener('click',function(){console.log(this)
}) //指向window//2、指向对象
const obj={sayHI:function(){console.log(this)
}
}
obj.sayHI() //指向obj

(2)箭头函数的指向

与普通函数不同,箭头函数this不受调用方式的影响

箭头函数不存在this,沿用的是上一级的

  • 不适用:构造函数,原型函数,dom事件函数等等
//箭头函数中断this为函数声明函数的this一致
const user={name:'小明'walk:()=>{console.log(this)}
}
user.walk() //指向window

!!!注:原型对象最好不 要用箭头函数,否则this不指向实例对象

2、改变this

(1)call() - 了解

调用函数,同事只当被调用函数的this的值

fn.call(thisArg,arg1,arg2,...)

const obj={uname:'pink'
}
function fn (x,y){console.log(this)//指向windowconsole.log(x+y)
}  fn.call() //单纯调用fn,指向window
fn.call(obj,1,2) //调用fn,改变this,指向obj

(2)apply() -理解

fn.call(thisArg,[argsArray]) 第二个参数必须是数组

const obj={uname:'pink'
}
function fn (x,y){console.log(this)//指向windowconsole.log(x+y)
}  
fn.call(obj,[1,2])//指向obj,打印3

使用场景:求数组的最大值

1、用数组遍历

2、扩展运算符

Math.max(...[arr])

3、用apply方法

Math.max/min.apply(Math/null,数组名)

//传统写法
const max = Math.max(1,2,3) 
console.log(max)//数组求最大值
const arr=[1,2,3]
const max = Math.max.apply(Math,arr)
const min = Math.min.apply(null,arr)

(3)bind()

call()、apply() 会调用函数,但bind()不会调用函数

会改变函数内部this指向

返回值是一个函数,这个函数的this是更改的obj

const obj={age:18    
}function fn(){console.log(this)
}const fun=fn.bind(obj)
fun() //打印obj对象

应用:有一个按钮,点击立马禁用,2s后开启

<button>按钮</button>
const btn=document.querySelector('.button')
btn.addEventListener('click',function(){this.disabled=truewindow.setTimeout(function(){// this.disabled=false //无法打开按钮//btn.disabled=false //可以打开按钮},2000)//或者window.setTimeout(function(){// this.disabled=false //无法打开按钮//btn.disabled=false //可以打开按钮}.bind(btn),2000)//或者window.setTimeout(function(){// this.disabled=false //无法打开按钮//btn.disabled=false //可以打开按钮}.bind(this),2000) //上一层的this指向btn//或者window.setTimeout(=>{this.disabled=false //可以打开按钮,箭头函数没有this,沿用上一层的this},2000) //上一层的this指向btn})

(4)改变this的三种方法及区别(面试常考)

 十一、性能优化

1、防抖 debounce

(1)特点

  • 单位时间内,频繁触发事件,只执行最后一次
  • 王者回城,只要被打断,就需要重新来

(2)语法:_.debounce(fun,时间) 

(3)使用场景

  • 搜索框搜索输入,只需要用户最后一次输入完,再发送请求
  • 手机号、邮箱验证输入检测

(4)案例

要求:鼠标在盒子上移动,里面的数字就会变化+1

const box=document.querySelector('.box')
let i=1
function mousemove(){box.innerHTML=i++
}
box.addEventListener('mousemove',mousemove) //数字变化很快

(改造:不是移动1像素就+1)
方法1、lodash提供的防抖函数 _.debounce(func,[wait=0],[option=])

<script src="./lodash.min.js"></script>
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、定时器里面写函数调用const box=document.querySelector('.box')let i=1function mousemove(){box.innerHTML=i++
}function(fn,t){let timer//这里用return是因为要反复调用该函数 return function(){if(timer) clearTimeout(timer)timer=setTimeout(function{fn()},t)}
}box.addEventListener('mousemove',_.debounce(mousemove,500))

2、节流

(1)特点

  • 单位时间内,频繁触发事件,只执行一次
  • 王者荣耀技能冷却,期间无法继续释放技能

(2)语法:_.throttle(fun,时间)

(3)使用场景

高频事件:鼠标移动mousemove、页面尺寸缩放resize、滚动条滚动scroll等等

(4)案例

要求:鼠标再盒子上移动,不管移动多少次,每隔500ms才+1

方法1:使用lodash库实现节流,500ms之后采取+1

<script src="./lodash.min.js"></script>
const box=document.querySelector('.box')
let i=1
function mousemove(){box.innerHTML=i++
}box.addEventListener('mousemove',_.throttle(mousemove,500))

方法2:手写节流函数

//核心:利用setTimeout进行实现
//1、声明定时器变量
//2、每次鼠标移动(事件触发)就判断是否有定时器,如果有就先清除定时器
//3、没有就开启定时器,存入到定时器变量里面
//4、定时器里面写函数调用const box=document.querySelector('.box')let i=1function mousemove(){box.innerHTML=i++
}function(fn,t){let timer//这里用return是因为要反复调用该函数 return function(){if(!timer) {timer = setTimeout(function(){fn()timer=null //在setTimeout函数中不能用clearTimeout(timer),因为定时器在运行},t)}
}box.addEventListener('mousemove',_.debounce(mousemove,500))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/768112.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Docker(二):Docker常用命令

docker 查看docker支持的所有命令和参数。 ➜ ~ docker Management Commands:config Manage Docker configscontainer Manage containersimage Manage imagesnetwork Manage networksnode Manage Swarm nodesplugin Manage pluginssecret …

《手把手教你》系列技巧篇(四十九)-java+ selenium自动化测试-隐藏元素定位与操作(详解教程)

1.简介 对于前端隐藏元素&#xff0c;一直是selenium自动化定位元素的隐形杀手&#xff0c;脚本跑到隐藏元素时位置时报各种各样的错误&#xff0c;可是这种隐藏的下拉菜单又没有办法避免&#xff0c;所以非常头痛&#xff0c;这一篇只为交流隐藏元素自动化定位处理方法以及宏哥…

Docker进阶:Docker-cpmpose 实现服务弹性伸缩

Docker进阶&#xff1a;Docker-cpmpose 实现服务弹性伸缩 一、Docker Compose基础概念1.1 Docker Compose简介1.2 Docker Compose文件结构 二、弹性伸缩的原理和实现步骤2.1 弹性伸缩原理2.2 实现步骤 三、技术实践案例3.1 场景描述3.2 配置Docker Compose文件3.3 使用 docker-…

微软开源Garnet高性能缓存服务安装

Garnet介绍 Garnet是一款微软研究院基于C#开发而开源的高性能缓存服务&#xff0c;支持Windows、Linux多平台部署&#xff0c;Garnet兼容Redis服务API&#xff0c;在性能和使用架构上较Redis有很大提升&#xff08;官方说法&#xff09;&#xff0c;并提供与Redis一样的命令操…

Rust egui(3) 增加多个tab

话说不知道咋写&#xff0c;要不直接上git patch吧。代码都是移植的官方demo&#xff0c;核心改动就是把原来的line_demo换成了plot_demo&#xff0c;里面实现多个ui&#xff0c;然后点击tab标题会切换不同的ui。 如下图&#xff0c;Lines和Markers两个不同的标签对应不同的ui。…

力扣HOT100 - 11. 盛最多水的容器

解题思路&#xff1a; 双指针&#xff0c;从左右两边往内侧夹逼&#xff0c;遍历后得到最大值 class Solution {public int maxArea(int[] height) {int i 0, j height.length - 1, res 0;while(i < j) {res height[i] < height[j] ? Math.max(res, (j - i) * heig…

【C++】关联式容器——map和set

1 关联式容器 STL中我们常用的部分容器&#xff0c;比如&#xff1a;vector、list、deque、forward_list(C11)等&#xff0c;这些容器统称为序列式容器&#xff0c;因为其底层为线性序列的数据结构&#xff0c;里面存储的是元素本身。 那什么是关联式容器呢&#xff1f;它与序…

qt Qt Remote Object(QtRO)实现进程间通信

简介 Qt Remote Object简称QtRO&#xff0c;这是Qt5.9以后官方推出来的新模块&#xff0c;专门用于进程间通信&#xff08;IPC&#xff09;。是基于Socket来封装的&#xff0c;兼容LPC和RPC。LPC即Local Process Communication&#xff0c;而RPC是指Remote Process Communicat…

Camera入门基础知识

一、camera介绍 1.1 camera硬件组成 camera一般由Lens、VCM音圈马达、底座支架、Sensor、Driver IC、output interface组成。如下图: 这里面要注意的是有些摄像头模组有VCM,有些则没有,有些output interface输出的是CSI信号,有的输出的是串行信号,需要接解串器。…

全新的分布式锁,功能简单且强大

分布式锁是分布式系统中一个极为重要的工具。 目前有多种分布式锁的设计方案&#xff0c;比如借助 redis&#xff0c;mq&#xff0c;数据库&#xff0c;zookeeper 等第三方服务系统来设计分布式锁。 tldb 提供的分布式锁&#xff0c;主要是要简化这个设计的过程&#xff0c;提…

面向对象-继承-使用细节

面向对象-继承-使用细节 1、子类继承了父类所有的属性和方法&#xff0c;非私有的属性和方法可以在子类中直接访问&#xff0c;但是私有的属性和方法不能在子类中直接访问&#xff0c;要通过父类提供公共的方法去访问。 2、子类必须调用父类的构造器&#xff0c;完成对父类的初…

PCB布线中晶振电容、电源大小电容、电源电容的设计细节

嵌入式软硬件爱好者 一张手册走天下。嵌入式单片机/Linux/Openwrt/电子电路技术交流分享。//主打一个技术层面的剑走偏锋&#xff0c;直击众人重视和不重视的重点//专注基础&#xff0c;才能走的更远 晶振电容 晶振旁边的电容在电路设计中不是用于滤波的。实际上&#xff0c;…

RIP,EIGRP,OSPF的区别

1.路由协议 能否选择出最优路径 2.路由协议 是否能够完成故障切换/多久能够完成故障切换 3.路由协议 是否会占用过大硬件资源 -- RIP -- 路由信息协议 跳数:一次三层设备的转发算一跳 中间隔的设备数量 不按照链路带宽来算 Rip认为路径一样,这个时候。 下面这个跳数不…

每日一题 --- 反转链表[力扣][Go]

反转链表 题目&#xff1a;206. 反转链表 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1]示例 2&#xff1a; 输入&#xff1a;head [1,2] 输出&a…

阿里云服务器价格购买价格表,2024新版报价查询

2024年腾讯云服务器优惠价格表&#xff0c;一张表整理阿里云服务器最新报价&#xff0c;阿里云服务器网整理云服务器ECS和轻量应用服务器详细CPU内存、公网带宽和系统盘详细配置报价单&#xff0c;大家也可以直接移步到阿里云CLUB中心查看 aliyun.club 当前最新的云服务器优惠券…

(Linux 学习十二)文件查找和文件压缩

一.文件查找 which 命令查找 也可以用 whereis find 文件查找&#xff0c;针对文件名 locate 文件查找&#xff0c;依赖数据库alias 别名 alias yyy ls --colorauto -l yyy //相当于别名 查看文件which ls //查找ls 命令位置 whereis vim //也是查找命令locate …

Jackson 2.x 系列【2】生成器 JsonGenerator

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 本系列Jackson 版本 2.17.0 源码地址&#xff1a;https://gitee.com/pearl-organization/study-seata-demo 文章目录 1. 前言2. 案例演示2.1 创建 JsonFactory2.2 创建 JsonGenerator2.3 写入操作2.4 查…

pta-洛希极限

科幻电影《流浪地球》中一个重要的情节是地球距离木星太近时&#xff0c;大气开始被木星吸走&#xff0c;而随着不断接近地木“刚体洛希极限”&#xff0c;地球面临被彻底撕碎的危险。但实际上&#xff0c;这个计算是错误的。 洛希极限&#xff08;Roche limit&#xff09;是一…

javase day11笔记

第十一天课堂笔记 构造代码块 { } 给 所有对象 共性特点 进行初始化操作 创建对象时在堆区对象中存放实例变量,同时执行构造代码块 执行顺序:静态代码块—>非静态代码块—>构造方法 继承★★★ 将多个类中相同的实例变量和实例方法 , 单独存放到一个类中,成为父类…

基于Java中的SSM框架实现快餐店线上点餐系统项目【项目源码+论文说明】计算机毕业设计

基于Java中的SSM框架实现快餐店线上点餐系统演示 摘要 随着计算机互联网的高速发展。餐饮业的发展也加入了电子商务团队。各种网上点餐系统纷纷涌现&#xff0c;不仅增加了商户的销售量和营业额&#xff0c;而且为买家提供了极大的方便&#xff0c;足不出户&#xff0c;就能订…