前端面试自学笔记

文章目录

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 中可定义多个根节点:这样就不用担心样式嵌套深层次的问题

如何实现数据的持久化存储

虚拟列表怎么实现的

  1. 监听容器元素滚动
  2. 获取容器元素滚动距离scrollTop
  3. 获取滚动距离下首个需要渲染元素索引
  4. 计算展示的数据viewData
  5. 清除可是区域内上一次展示的数据,使用新数据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树
  • 样式计算
  • 布局阶段
  • 分层
  • 绘制
  • 分块
  • 栅格化
  • 合成
  • 关于回流、重绘、合成
  1. 渲染进程将HTML内容转换为DOM树
  2. 渲染引擎将CSS样式转换为styleSheets,计算出DOM节点的样式;
  3. 创建布局树,并计算出布局树的布局信息(几何信息);
  4. 对布局树进行分层,生成分层树;
  5. 每个图层生成绘制列表,提交至合成线程;
  6. 合成线程将图层分为图块,并在光栅化线程池中将图块转换为位图, 中间可能伴随有GPU加速;
  7. 合成线程发送 DrawQuad给浏览器进程。
  8. 浏览器进程根据命令消息生成页面,显示到显示器上。

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));

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值