文章目录
- JS原型
- JS中对原型的修改和重写
- ES6中for...of 和 for...in的区别
- JS 如何判断一个属性是属于实例对象还是继承于构造函数
- JS中bind 和 call 、apply的作用和区别
- 判断数据类型
- 构造函数和构造函数实例之间的关系
- 内存泄露
- 如何解决深拷贝中循环引用的问题
- vue3相比于vue2做了哪些更新
- vue3更新根节点的目的
- 如何实现数据的持久化存储
- 虚拟列表怎么实现的
- Axios怎么封装的
- 路由相关,用户改ul进入页面怎么阻止的
- Vue双向绑定的原理
- 三栏布局怎么实现?写一个float实现的三栏布局
- 怎样减少页面的回流和重绘
- es6 set和map的区别
- 讲一讲红黑树是什么,红黑树有什么优势
- 事件冒泡
- 什么是原形链?
- 如何创建一个函数, new一个函数的时候发生了什么?
- 怎么画出一个三角形
- 防抖节流并写出任意一个手写代码
- 存储大量数据时,使用map还是对象
- 浏览器架构与渲染原理是什么
- vue3渲染更新的颗粒度是什么
- vue2与vue3的响应式原理是怎么实现的
- watch与computed的区别和原理
- vue-router的模式有哪些以及实现原理,history模式需要后端怎么配合微前端的介绍
- 组件库的架构设计与实现,webpack做了哪些优化
- 用户权限的设计及用户拥有大量权限,请求很慢时如何优化
- 创建对象create与{}字面量区别
- $nextick的作用和原理?
- 数组转树形结构
- webpack打包优化
- 怎么捕获错误
- let 不会被挂载到window上
- 代码题
- map & forEach 的区别
- 你知道的前端性能优化手段有哪些
- Vue中父子组件的更新顺序,销毁顺序![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/728f19e81a7bda4f608d1399d8cef915.png)
- 实现一个Promise.all
JS原型
function Person(){
//构造函数Person,JS解析器自动添加prototype属性(显式原型)
//prototype属性默认指向一个空对象(原型对象)
}
var per = new Person() //对象
显式原型:每个函数都有一个prototype属性,即显示原型
隐式原型:每个实例对象都有一个_proto_(创建对象时候自动添加)
Person.prototype === per._proto_
JS中对原型的修改和重写
function Person(name){
this.name = name
}
//修改原型
Person.prototype.getName = function(){
console.log(this.name)
}
var per = new Person('张三‘)
//per.constructor(对象.constructor 等于 Person)
console.log(p._proto_ === Person.prototype) // true
console.log(p._proto_ === per.constructor.prototype) //true
// 重写原型
Person.prototyp = {
getName:function(){
console.log(this.name)
}
}
var per = Person('张三’) // per的构造函数指向根构造函数的Object
console.log(p._proto_ === Person.prototype) // true
console.log(p._proto_ === per.constructor.prototype) //false
per.constructor = Person (让per.constructor的指向重新指向Person)
ES6中for…of 和 for…in的区别
for … of 遍历获取对象的键值,for … in获取对象的键名
for … of 只遍历当前对象的键值;for … in 遍历整个原型链的键名
数组的遍历
for … of 返回数组下标对应的属性值;for … in返回数组中所有可枚举的属性(不适合数组遍历)
function Person(name, age, sex){
this.name = name
this.age = age
this.sex = sex
}
Person.prototype.height = 188
var p = new Person()'张三‘, 18, '男')
p[Symbol.interator] = funciton(){
var keys = object.keys(this)
var index = 0
return{
next(){
if(index<keys.length){
return {value:p[keys[index++]],done:false}
}else{
return { value:indefined,deone:true}
}
}
}
}
//遍历
for(let var of p){
console.log(value) //张三 18 男
}
for(let key in p){
console.log(key) // name age sex height
}
// 数组遍历
var arr = [1,2,3,4,5,6]
for(let i of arr){
console.log(i) // 1 2 3 4 5 6 属性值
}
for(let i in arr){
console.log(i) // 0 1 2 3 4 5 可枚举的下标
}
JS 如何判断一个属性是属于实例对象还是继承于构造函数
hasOwnProperty()//检测一个属性是否属于自身对象,还是继承于原型链上的
function Person(name, age){
this.name = name
this.age = age
}
Person.prototype.sex = '男'
var p = new Person('张三',18)
p.phone = 12345;
p.height = 188
console.log(p.hasOwnProperty("phone")) // true
console.log(p.hasOwnProperty("sex")) // false
// 使用for...in遍历对象自身的属性名
for(let i in p){
if(p.hasOwnProperty(i))
console.log(p[i])
}
JS中bind 和 call 、apply的作用和区别
作用:改变函数运行时的this的指向
bind 绑定this不执行函数
call 改变函数this指向,并且执行函数call(this,参数1,参数2…)
apply 改变this指向,参数接收的是数组 apply(this,arr)
判断数据类型
- typeof (null为object;不能细分对象类型) 判断基本类型方法
- instanceof (不能检测原始值类型,原型链可以重构,导致结果不准确)判断对象方法
- constructor (可以检测原始值类型,但是只会基于原型链上的直属类检测)
- Object.prototype.tostring.call() 最准
构造函数和构造函数实例之间的关系
构造函数实例通过new构造函数
内存泄露
原因:程序的某些内存被占用得不到释放,造成的内存浪费
哪些会引起内存泄漏:
- 被遗忘的定时器和回调函数;
- 闭包;【闭包的使用错误导致.】
- 全局变量;【非严格模式下全局变量是根据定义无法被垃圾回收机制收集】
- DOM引用;【保留了DOM节点的引用,导致GC没有回收】
垃圾回收算法:垃圾回收机制不可预测
- 引用计数 【没有引用指向该对象(零引用),对象将被垃圾回收机制回收。】
- 标记清除 【从root开始的所有对象如果是可达的,它就不被当作垃圾。】
如何解决深拷贝中循环引用的问题
循环引用造成了递归的栈溢出
解决方法:需要一个存储容器存放当前对象和拷贝对象的对应关系(适合用key-value的数据结构进行存储,也就是map),当进行拷贝当前对象的时候,我们先查找存储容器是否已经拷贝过当前对象,如果已经拷贝过,那么直接把返回,没有的话则是继续拷贝。
if (map.get(target)) {
return map.get(target)
}
map.set(target,cloneTarget)
vue3相比于vue2做了哪些更新
vue3 全面深入原理讲解掘金
Tree-shaking支持 ( 按需加载 )
静态树提升
静态属性提升
虚拟 DOM 重构
插槽优化
Suspense、Fragment、Teleport
支持TS ( 原生Class Api 和 TSX )
基于 Proxy 的新数据监听系统(Composition API)
自定义渲染平台(Custom Render)
生命周期的不同
…
- 静态属性提升;
- 预字符串化 ;【vue3的编译器遇到大量的连续的静态节点, 会直接将其编译为一个普通的字符创节点。预字符串化的性能提升不紧紧在第一次创建时的提升, 当在 render 函数重新渲染时的提升减少了大量的虚拟节点的对比时间(非常恐怖)】
- 缓存事件处理函数;
- Block Tree;【对虚拟节点树时,vue3标记了节点类型,静态节点跳过对比】
- PatchFlag; 【标记该内容是动态的, 所以在进行对比时就只对比 内容 是否变化, 就极大的缩短了对比时间(恐怖如斯)】
vue3更新根节点的目的
在 Vue2.x 中组件只有一个根节点
在 Vue3.x 中可定义多个根节点:这样就不用担心样式嵌套深层次的问题
如何实现数据的持久化存储
虚拟列表怎么实现的
- 监听容器元素滚动
- 获取容器元素滚动距离scrollTop
- 获取滚动距离下首个需要渲染元素索引
- 计算展示的数据viewData
- 清除可是区域内上一次展示的数据,使用新数据viewData重新填充
Axios怎么封装的
路由相关,用户改ul进入页面怎么阻止的
Vue双向绑定的原理
三栏布局怎么实现?写一个float实现的三栏布局
怎样减少页面的回流和重绘
- 减少对 dom 的操作;
- 使元素脱离文档流;【页面部分元素是有持续性的动画效果的,所以会一直触发回流和重绘,此时可以使这些元素脱离文档流,以此减少页面回流和重绘的次数;】
- 避免访问或减少访问某些属性;【某些操作会导致浏览器强制刷新队列:scrollTop,offsetTop等】
- 避免对 css 进行单个修改;
es6 set和map的区别
set:是一组key的集合,与Map类似。但是区别是Set不存储value,并且它的key不能重复,结构类似于数组,且没有重复的值。;
Map 对象是键值对集合;
讲一讲红黑树是什么,红黑树有什么优势
事件冒泡
浏览器从用户点击事件开始,自下往上依次至window,逐个触发事件处理函数
e.stopPropagation()
什么是原形链?
当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去它的__proto__隐式原型上查找,即它的构造函数的prototype,如果还没有找到就会再在构造函数的prototype的__proto__中查找,这样一层一层向上查找就会形成一个链式结构,我们称为原型链。
如何创建一个函数, new一个函数的时候发生了什么?
- 创建一个空对象;
- 将构造函数的作用域赋值给空对象;
- 执行构造函数,为新对象添加属性;
- 返回实例对象;
怎么画出一个三角形
<div class="border"></div>
<style>
.border {
width: 0;
height: 0;
border: 50px solid;
border-color: transparent transparent red;
} //原理是让一个元素没有宽高,但是给其边框设置足够的宽度,并让其中三条边框的背景色为透明transparent。
</style>
防抖节流并写出任意一个手写代码
// 节流(一段时间执行一次之后,就不执行第二次)
function throttle(fn, delay){
let canUse = true
return function(){
if(canUse){
fn.apply(this, arguments)
canUse = false
setTimeout(()=>canUse = true, delay)
}
}
}
const thro = throttle(()=>console.log('hi'))
throttled()
thr()
// 防抖(一段时间会等,然后带着一起做了)
function debounce(fn, delay){
let timerId = null
return function(){
const context = this
if(timerId){window.clearTimeout(timerId)}
timerId = setTimeout(()=>{
fn.apply(context, arguments)
timerId = null
},delay)
}
}
const debo = debounce(()=>console.log('hi'))
debounced()
debo()
存储大量数据时,使用map还是对象
- 储存大量的数据时,选择 Map,因为它占用的内存更小
- 只是简单的数据结构时,选择 Object,因为它在数据少的时候占用内存更少,且新建时更为高效
浏览器架构与渲染原理是什么
- 构建DOM树
- 样式计算
- 布局阶段
- 分层
- 绘制
- 分块
- 栅格化
- 合成
- 关于回流、重绘、合成
- 渲染进程将HTML内容转换为DOM树
- 渲染引擎将CSS样式转换为styleSheets,计算出DOM节点的样式;
- 创建布局树,并计算出布局树的布局信息(几何信息);
- 对布局树进行分层,生成分层树;
- 每个图层生成绘制列表,提交至合成线程;
- 合成线程将图层分为图块,并在光栅化线程池中将图块转换为位图, 中间可能伴随有GPU加速;
- 合成线程发送 DrawQuad给浏览器进程。
- 浏览器进程根据命令消息生成页面,显示到显示器上。
vue3渲染更新的颗粒度是什么
Vue3通过 Proxy 响应式 + 组件内部 vdom + 静态标记
vue2与vue3的响应式原理是怎么实现的
Vue2实现双向数据绑定原理,是通过es5的 Object.defineProperty;
Vue3使用了ES2015的更快的原生proxy 替代 Object.defineProperty。
watch与computed的区别和原理
computed值有缓存,值没有发生变化时从缓存中拿取,需要计算并且依赖于其他数据;
watch:没有缓存值,随时监听数据变化,并且支持异步。
vue-router的模式有哪些以及实现原理,history模式需要后端怎么配合微前端的介绍
常用的路由模式有两种:(1)hash;(2)history
原理:hash 模式基于锚点,以及 onhashchange 事件。 history 模式是基于 HTML5 中的 history 模式。
history模式需要后端怎么配合微前端的介绍:history 模式下,刷新页面会向服务器进行网络请求,后端处理 history 模式,需要将默认的 html 文件返回给前端,前端获取到文件后再根据路由自行处理。
组件库的架构设计与实现,webpack做了哪些优化
用户权限的设计及用户拥有大量权限,请求很慢时如何优化
创建对象create与{}字面量区别
字面量和new关键字创建的对象是Object的实例,原型指向Object.prototype,继承内置对象Object。
Object.create(arg, pro)创建的对象的原型取决于arg,arg为null,新对象是空对象,没有原型,不继承任何对象;arg为指定对象,新对象的原型指向指定对象,继承指定对象。
$nextick的作用和原理?
$nextick作用:下次DOM更新之后回调的代码。在修改数据之后立即使用这个方法,获取更新后的 DOM。
数组转树形结构
webpack打包优化
怎么捕获错误
- try…catch
- window.onerror 【浏览器在window对象上还自带了一个onerror的方法】
- window.addEventListener(‘error’)
- window.addEventListener(‘unhandledrejection’)
let 不会被挂载到window上
- let创建的全局变量会从window中脱离,在script中形成了一个块级作用域,所以通过window访问不到, 直接访问即可;
- let没有变量提升
代码题
let promise=new Promise((resolve,reject)=>{
console.log(1);
resolve('promise1 resolve')
})
const promise2=promise.then(res=>{
console.log(res);
return new Promise((resolve)=>resolve(3))
})
console.log('2',promise2)
console.log('2',promise2);
map & forEach 的区别
- map 的返回新数组,数组个数不变;forEach它没有返回值,即它返回的是 undefined。
- 当你想基于一个原数组返回一个新数组,可以选择 map,当你只是想遍历数据不需要考虑返回时可以选择 forEach。
你知道的前端性能优化手段有哪些
核心都是在围绕两个点,如何让静态资源(HTML\CSS\JS\图片\音视频等)更快的发送到浏览器,如何让浏览器更快的渲染这些元素
掘金参考资料
- 合理利用缓存:cookie,localStorage
- 内存缓存:将常用的数据放到浏览器内存缓存中
- http缓存:强缓存,协商缓存
- 静态资源:压缩资源
- 减少资源大小:精简html代码、压缩html、js、css代码,压缩图片
- 合理放置资源加载顺序:优先加载css,后加载js
- 资源按需加载:如 Vue 的路由懒加载、图片懒加载等
Vue中父子组件的更新顺序,销毁顺序
实现一个Promise.all
let arr1 = [1, 2, 5,7,8,9];
let arr2 = [1, 3, 4, 2];
function compare(arr1, arr2) {
return arr1.map((v) => {
if(arr2.indexOf(v) !== -1){
console.log(v);
return v
}
});
}
console.log(compare(arr1, arr2));