本文主要是介绍前端个人总结(奥利给),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
事件循环—eventloop
js是单线程的。也就是说,同一个时间只能做一件事。作为浏览器脚本语言,与它的用途有关。
JavaScript的主要用途是和用户互动,以及操作DOM。这决定了它只能是单线程。
比如有一个添加节点,一个删除节点,肯定不能同时进行,还没添加怎么删除呢,所以是先添加DOM节点后删除DOM节点。
有些任务是耗时的,会阻塞代码的执行:
console.log(1)
setTimeout(function () {
console.log(2)
},2000)
console. 1og(3)
我们可以把代码分为同步代码(同步任务)和异步代码(同步代码)
同步代码:
console.log(1)
console. 1og(3)
同步代码:
setTimeout(function () {
console.log(2)
},2000)
异步代码除了setTimeout(一次性定时器)还有:
setlnterval(定时器)
jax/Fetch
事件绑定
异步代码的共同特点都是耗时的
重点:
同步代码:立即放入JS引擎(JS主线程)执行,,并原地等待结果
异步代码:先放入宿主环境(浏览器/Node),不必原地等待结果,并不阻塞主线程继续往下执行,异步结果在将来执行
执行过程:
执行栈只要一执行完,就会反复到任务队列里面去看,有没有异步的任务需要去执行,执行栈到任务队列里面反复查找的过程就叫做事件循环
总结:
1.JS是单线程,防止代码阻塞,我们把代码(任务):同步和异步
2.同步代码给js引擎执行,异步代码交给宿主环境
3.同步代码放入执行栈中,异步代码等待时机成熟送入任务队列排队
4.执行栈执行完毕,会去任务队列看是否有异步任务,有就送到执行栈执行,反复循环查看执行,这个过程是事件循环(eventloop)
事件循环-宏任务和微任务
代码可能有3种:执行顺序依次往下
1.同步代码(js 执行栈/回调栈)
2.微任务的异步代码(js引擎)
process.nextTick ( node)
Promise.then() catch()
Async/Await
object.observe等等
Promise本身同步, then/catch的回调函数是异步的微任务
3.宏任务的异步代码(宿主环境)
script(代码块)
setTimeout/setInterval定时器
setImmediate定时器
什么是原型和原型链?
原型:每个函数都有prototype属性称之为原型,因为这个属性的值是个对象,也称为原型对象
作用:
1.存放一些属性和方法
2.在JavaScript中实现继承
proto:每个对象都有_proto_属性
作用:这个属性指向它的原型对象
1.原型:函数都有prototype属性,称之为原型,也称为原型对象
原型可以放一些属性和方法,共享给实例对象使用
原型可以做继承
2.原型链:对象都有_proto_属性,这个属性指向它的原型对象,原型对象也是对象,也有_proto_属性,指向原型对象的原型对象,这样一层一层形成的链式结构称为原型链,最顶层找不到则返回null
防抖和节流
防抖:
就是指连续触发事件但是在设定的一段时间内中只执行最后一次
例如:设定1000毫秒执行,当你触发事件了,他会1000毫秒后执行,但是在还剩500毫秒的时候你又触发了事件,那就会重新开始1000毫秒之后再执行
记忆核心:从新开始
应用场景:
搜索框搜索输入
文本编辑器实时保存
let timerId = null 1首先把定时器设置为null
document.queryselector( ".ipt " ).onkeyup = function () { 2做了一个事件:键盘弹起的时候
//防抖
if (timerId !== null){ 3来判断是不是null,如果不是则清除定时器,第一次执行条件不满足
clearTireout(timerId)
}
timerId = setTimeout(() =>{ 4定时器一旦执行就会返回一个数字,timerId就有数字了,如果此时又做了一个键盘弹起事件,就会回到3清除定时器,清除完毕又会执行4
console.log(‘我是防抖')
},1000)
}
节流:
就是指连续触发事件但是在设定的一段时间内中只执行一次函数。
例如:设定1000毫秒执行,那你在1000毫秒触发在多次,也只在1000毫秒后执行一次
记忆方法:不要打断我
应用场景:
高频事件 例如 快速点击、鼠标滑动、resize事件、scroll事件
下拉加载
视频播放记录时间等
let timerId = null 1把timerId设置为空
document.queryselector( ".ipt ' ).onmouseover = function () { 2做了一个鼠标经过的事件
//节流
if (timerId !== null){ 3第一次执行是不满足的,所以不执行return
return
}
timerId = setTimeout(()=>{ 4定时器一开启就会把一个数字赋值给id
console.log("我是节流')
timerId = null 除非定时器执行完了,一执行完之后,把id值变为null,再次触发时第一个条件不满足,所以不退出
},100) 5如果在100毫米再次触发了鼠标事件,就会在第3步return,就不会影响下面的代码的执行
}
总结:
1.防抖:单位时间内,频繁触发事件,只执行最后一次
典型场景:搜索框搜索输入
代码思路是利用定时器,每次触发先清掉以前的定时器(从新开始)
2节流:单位时间内,频繁触发事件,只执行一次
典型场景∶高频事件快速点击、鼠标滑动、resize事件、scroll 事件
代码思路也是利用定时器,等定时器执行完毕,才开启定时器(不要打断)
其实,我开发一般用lodash库,利用里面的debounce(防抖)和throttle(节流)来做的
什么是闭包?
里层函数加上外层函数这个变量。
作用:实现数据的私有
经常使用一个函数包裹住闭包结构,对变量起到保护作用
return的主要目的是把这个局部变量返回到外面来,这样外面的人也可以使用这个值了。
普通函数形式在外面修改i值log输出的结果也会变化
闭包后i是私有变量,我们在外面是无法修改的,还是可以拿到i值,闭包实现了数据的私有
闭包-内存泄漏
谁会存在内存泄漏?Count变量
借助于垃圾回收机制的 标记清除法可以看出:
1.result 是一个全局变量,代码执行完毕不会立即销毁:
2.result使用fn函数
3. fn用到 fun函数
4. fun函数里面用到count
5.count被引用就不会被回收,所以一直存在此时:闭包引起了内存泄漏
注意:
1.不是所有的内存泄漏都要手动回收的
2.比如react里面很多闭包不能回收的
浏览器模型BOM
BOM(Browser Object Model) 浏览器对象模型,大概就是平时你能想到跟js运行没啥关系但是需要浏览器或者说窗口有关系的一些操作的这样一个对象。
1.window对象,
BOM的核心对象,第一重身份是JavaScript运行的全局对象,所有用var声明的全局变量和函数都可以通过window.xxx调用,(let、const声明不会,因为是块级作用域)。
第二重身份是浏览器窗口的js接口很多浏览器API和构造函数都是挂在window对象上面,还有一些全局方法,比如定时器setTimeout,可以用window.setTimeout去调用,返回的是一个定时器id
1.1窗口关系:window.top window.parent window.self分别表示获取当前窗口的顶层、父级、自己的窗口对象。
1.2窗口位置和像素比:window.screenLeft和window.screenTop获取当前窗口相对于屏幕的左边距和顶部的距离,对应可以用window.moveTo和window.moveBy将当前窗口移动到指定坐标和相对距离。
1.3视口滚动:window.scrollTo和window.scrollBy,这是滚动当前视口,一般在页面过长可以用这个滚动刀指定高度或者相对高度。
1.4窗口大小:window.innerWidth/innerHeight和window.outerWidth/outerHeight分别表示内部页面视口大小(不包括工具栏和浏览器边框)和整个窗口自身的大小。设置窗口大小:window.resizeTo()和Window.resizeBy()。
1.5导航和打开新窗口:window.open()导航到指定url,也可用于打开新窗口。
1.6系统对话框:alert()警告框、confirm()确认框有两个按钮取消和确认、prompt()提示框。
2.location对象
提供当前窗口文档的加载信息以及通常的导航功能,它既是Window的属性也是document的属性。location对象不仅保存着当前加载文档的信息也保存着把url解析为离散片段后能够通过属性访问的信息。
3.navigator浏览器信息对象
navigator.userAgent()这个属性获取一个包含了用户代理信息的字符串,然后对这个字符串做一些关键字的区分,就能知道是苹果浏览器还是安卓浏览器。
navigator.getUserMedia()获取设备媒体的能力,一般一些媒体流比如麦克风摄像头这样的一些网站会需要。
navigator.plugins可以获取浏览器安装的所有插件,返回值是一个数组。
4.window.screen
一般用来获取客户端显示器信息,比如宽高和像素高度。
5.window.history历史记录对象
当前窗口从打开到调用的所有历史记录对象,为了安全不会暴露用户访问过的URL,window.history.go(1)入参是一个数字,整数表示浏览器记录前进几页,负数返回几页。可以通过它在不知道实际URL的情况下前进和后退
vue中计算属性computed和function、watch的区别
先说computed和function:
1、计算属性有缓存,有且仅有计算属性内部的属性值发生变化时才会被调用,数据没有发生变化就不会重新求值,性能上会有很大的提升;所以如果返回的数据不经常发生变化,那么使用计算属性的性能会比使用函数的性能高。
函数没有缓存,每次执行都会被调用;
2、计算属性默认只有get函数,没有set,只支持单向,若想使用双向可进行手动添加;
函数只有单向;
computed和watch的区别
computed:是计算属性,并且computed的值具有缓存,只有他依赖的属性发生变化,下一次获取computed的值才会重新计算属性的值。
适用场景:当我们需要进行计算,并且依赖其他数据时,应该使用computed,可以利用computed的缓存特性,避免每次获取值时都要重新计算(购物车计算价格的案例)。
watch:(侦听器)没有缓存性,更多的是观察的作用,可以监听某些数据执行回调。当我们需要深度监听对象中的属性时,可以打开deep:true选项,这样便会对对象中的每一项进行监听。一个数据影响多个数据。
使用场景:在数据变化时执行异步或者开销较大的操作时,应该使用watch。 watch允许异步操作 (比如:浏览器自适应、监控路由对象、监控自身属性变化)。
v-bind和v-model的区别
1.v-bind是单向绑定,用来绑定数据和属性以及表达式,数据只能从data流向页面。
v-model是双向绑定,数据能从data流向页面,也能从页面流向data。
2.v-bind可以给任何属性赋值,v-model只能给表单类,也就是具有value属性的元素进行数据双向绑定,如text、radio、checkbox、selected。
从页面流向data,v-model是捕获用户的输入值,如果没有value,捕获不了,所以这个流向没有意义,v-model就是收集value值。
vue2和vue3的区别
一. 根节点不同
- vue2中必须要有根标签。
- vue3中可以没有根标签,会默认将多个根标签包裹在一个fragement虚拟标签中,有利于减少内存。
二. 组合式API和选项式API
- 在vue2中采用选项式API,将数据和函数集中起来处理,将vue3样式穿透功能点切割了当逻辑复杂的时候不利于代码阅读。
- 在vue3中采用组合式API,将同一个功能的代码集中起来处理,使得代码更加有序,有利于代码的书写和维护。
三. 生命周期的变化
创建前:beforeCreate -> 使用setup()
创建后:created -> 使用setup()
挂载前:beforeMount -> onBeforeMount
挂载后:mounted -> onMounted
更新前:beforeUpdate -> onBeforeUpdate
更新后:updated -> onUpdated
销毁前:beforeDestroy -> onBeforeUnmount
销毁后:destroyed -> onUnmounted
异常捕获:errorCaptured -> onErrorCaptured
被激活:onActivated 被包含在中的组件,会多出两个生命周期钩子函数。被激活时执行。
切换:onDeactivated 比如从 A 组件,切换到 B 组件,A 组件消失时执行
四. v-if和v-for的优先级
在vue2中v-for的优先级高于v-if,可以放在一起使用,但是不建议这么做,会带来性能上的浪费
在vue3中v-if的优先级高于v-for,一起使用会报错。可以通过在外部添加一个标签,将v-for移到外层
五. diff算法不同
vue2中的diff算法
遍历每一个虚拟节点,进行虚拟节点对比,并返回一个patch对象,用来存储两个节点不同的地方。
用patch记录的消息去更新dom
缺点:比较每一个节点,而对于一些不参与更新的元素,进行比较是有点消耗性能的。
特点:特别要提一下Vue的patch是即时的,并不是打包所有修改最后一起操作DOM,也就是在vue中边记录变更新。(React则是将更新放入队列后集中处理)。
vue3中的diff算法
在初始化的时候会给每一个虚拟节点添加一个patchFlags,是一种优化的标识。
只会比较patchFlags发生变化的节点,进行识图更新。而对于patchFlags没有变化的元素作静态标记,在渲染的时候直接复用。
六. 响应式原理不同
vue2通过Object.definedProperty()的get()和set()来做数据劫持、结合和发布订阅者模式来实现,Object.definedProperty()会遍历每一个属性。
vue3通过proxy代理的方式实现。
proxy的优势:不需要像Object.definedProperty()的那样遍历每一个属性,有一定的性能提升proxy可以理解为在目标对象之前架设一层“拦截”,外界对该对象的访问都必须通过这一层拦截。这个拦截可以对外界的访问进行过滤和改写。
当属性过多的时候利用Object.definedProperty()要通过遍历的方式监听每一个属性。利用proxy则不需要遍历,会自动监听所有属性,有利于性能的提升
七. 插槽方式不同
默认插槽相同
具名插槽使用方式不同:vue2使用slot name=‘’ person",vue3使用v-slot:''person"
作用域插槽使用方式不同:vue2中在父组件中使用slot-scope=“data"从子组件获取数据,vue3中在父组件中使用 #data 或者 #default=”{data}"获取
八. 样式穿透
1.vue2中:
/deep/ .类名{}
::v-deep .类名{}
2.vue3中:
:deep (.类名{})
::v-deep(.类名{})
hash和history的区别
前端路由 vue-router 有两种模式,
1.hash路由再地址栏URL上有“#”,而history路由没有,外观上比hash 模式好看些
2.hash模式在每次刷新页面时是直接更改“#”后的东西,history每次刷新会重新像后端请求整个网址,也就是重新请求服务器。如果后端没有及时响应,就会报错404!。
3.hash支持一些低版本的浏览器。兼容到IE8,而history不支持。兼容到IE10。
由于 hash 值变化不会导致浏览器向服务器发出请求,而且 hash 改变会触发 hashchange 事件(hashchange只能改变 # 后面的url片段);虽然hash路径出现在URL中,但是不会出现在HTTP请求中,对后端完全没有影响,因此改变hash值不会重新加载页面,基本都是使用 hash 来实现前端路由的。
hash原理: hash通过监听浏览器的onhashchange()事件变化,查找对应的路由规则
history原理: 利用H5的 history中新增的两个API pushState() 和 replaceState() 和一个事件onpopstate监听URL变化
js如何获取文档对象?如何获取页面中的元素 ?
1.通过id获取:getElementById
2.通过类名获取:getElementsByClassName
3.通过标签名获取:getElementsByTagName
4.HTML5新增方法
直接利用类,id,和标签名的特征获取
var box =document.querySelector("#box");
var box =document.querySelector(".box");
var box =document.querySelector("div");
//在使用类和标签名中可能遇到多个对象,这时会返回第一个元素对象
querySelectorAll
var box =document.querySelectorAll(".box");
var box =document.querySelectorAll("div");
这篇关于前端个人总结(奥利给)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!