2024年最全总结(前端面试题)_property ‘vuex‘ of undefined,物联网嵌入式开发基础视频教程

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

​ 1,新增语义化标签

img

​ 2,新增表单类型

​ 3,表单元素

​ 4,表单属性

​ 5,表单事件

​ 6,多媒体标签:video,audio,source,embed,track

网页中有大量图片加载很慢 你有什么办法进行优化

​ 1,图片懒加载,在图片未可视区域加一个滚动条,判断图片的位置与浏览器顶端和页面的距离,如果前者小于后者,优先加载

​ 2,图片预加载,将当前展示图片的前一张和后一张先下载

​ 3,使用csssprite或者svgsprite

Px,rem,em的区别

​ 1,px,绝对长度单位,像素px是相对于显示器屏幕分辩率来说的

​ 2,em,相对长度单位,相当于当前对象内文本的字体大小

​ em的值并不是固定的,会继承父级元素的字体大小,字体大小参照与父元素的大小决定

​ 3,rem,相对于HTML根元素的font-size

​ 1em=1rem=16px

​ 在body中加入font-size:62.5% 这样直接就是原来的px数值除以10加上em就可以

请简述媒体查询

​ 媒体查询扩展了media属性,根据不同媒体类型设置不同的css样式,达到自适应的目的

Css继承特性主要是文本方面

​ 1,所有元素可继承:visibility,cursor

​ 2,块级元素可继承:text-indent,text-align

​ 3,列表元素可继承:list-style,list-style-type,list-style-position,list-style-image

​ 4,内联元素可继承:letter-spacing,word-spacing,line-height,color,font,font-family,font-size,Font-style,font-variant,font-weight,text-decoration,text-transform,direction

link标签和import标签的区别

​ 1,link属于HTML,而@import属于css

​ 2,页面被加载时,link会同时被加载,而@import引用的css会等页面加载完成后加载

​ 3,link是HTML标签,所有没有兼容性,而@import只有IE5以上可以识别

​ 4,link方式样式的权重高于@import

画一条0.5px的线

移动端开发时,由于屏幕retina,即高清屏幕, 当写 1px 时, 实际的线宽为 2px. 会显得很粗。此时就有了 0.5px 的需求: 主要应对 iPhone

<style>
 .parent{
 position:relative;
 &:after{
 /\*绝对定位到父元素最低端,可以通过left/right的值控制边框长度或者定义width:100%\*/
 position:absolute;
 bottom:0;
 left:0;
 right:0;
 /\*初始化边框\*/
 content:'';
 box-sizing:border-box;
 height:1px;
 border-bottom:1px solid rgba(0,0,0,0.2);
 /\*以上代码实现了一个边框为1px的元素,下面实现0.5边框\*/
 /\*元素y方向缩小为原来的0.5\*/
 transform:scaley(0.5); 
 /\*css属性让你更改一个元素变形的原点\*/
 transform-origin:0 0;
 }
 }
</style>

用css画一个三角形
<style>
 #triangle-up{
 width:0;
 height:0;
 border-left:50px solid transparent;
 border-right:50px solid transparent;
 border-bottom:100px solid red;
 }
</style>
<body>
    <div id="triangle-up"></div>
</body>

JS篇

Js中null与undefined区别

​ null:一个值被定义了,但是是空值

​ undefined:变量声明未赋值

​ 相同点:用if判断时,都会被转换成false

​ 不同点:number转换值不同。 number(null)==0,number(undefined)==NaN

继承

​ 说一说 JS 中的常用的继承方式有哪些?以及各个继承方式的优缺点

​ 1,原型继承,把父类的实例作为子类的原型

​ 缺点:子类的实例共享了父类构造函数的引用类型,不能传参

​ 2,组合继承,在子函数中运行父函数,要利用call改变this,再在子函数的prototype里面new father(),使farther的原型中的方法也得到继承,最后改变son的原型中的constructor

​ 缺点:调用两次父类的构造函数,造成了不必要的消耗,父类方法可复用

​ 优点:可以传参,不共享父类引用属性

​ 3,寄生组合继承,

​ 4,es6的extend 子类只有继承父类,可以不写constructor,一旦写了,则在constructor中的第一句话必须是super

原型

​ 原型分为隐式原型和显示原型,每个对象都有一个隐式原型,指向自己构造函数的显示原型

原型链

​ 多个_ _proto__组成的集合成为原型链。由多级父对象,逐级继承,形成的链式结果。

​ 所有实例的_ _proto__都指向他们构造函数的prototype

​ 所有的prototype都是对象,自然它的_ _proto__指向的是object()的prototype

​ 所有的构造函数的隐式原型指向Function()的显示原型

​ object的隐式原型是null

this指向

​ 1,obj.fun() this—>obj

​ 2,fun() , (function(){…})() , 多数的回调函数,定时器函数 this—>window

​ 3,new Fun() this—>new正在创建的新对象

​ 4,类项名.prototype.共有方法=function(){…} this—>将来谁调用指谁

​ 5,箭头函数中的this —>箭头函数外部作用域中的this

​ 6,DOM或JQ中事件处理函数中的this—>当前正在触发事件的DOM元素对象

​ 7,jQuery.fn.自定义函数=function(){…} this—>将来调用这个函数的.前的 JQ子对象

​ 8,new Vue()中 methods 中的函数中的this —>当前new Vue()对象

设计模式

​ 单例模式,不管创建多少个对象都只有一个模式

​ 工厂模式,代替new创建一个对象,这个对象想工厂制作一样 ,批量制作属性相同的实例对象

​ 构造函数模式,

​ 发布订阅者模式,

​ 迭代器模式,

​ 代理模式

call, apply, bind, new

​ 1,call实现思路:

​ 判断是否是函数调用,不是则抛异常

​ 通过新对象(context)来调用函数

​ 给context创建一个fn设置为需要调用的函数

​ 结束调用后删除fn

Function.prototype.myCall=function(context){
	//先判断调用myCall是否是一个函数
  	//这里的this就是调用myCall的
	if(typeof this !== 'function'){
		throw new TypeErrr('Not a Function')
	}
	//不传参默认为window
	contetx=context||window;
	//保存this
	context.fn=this;
	//保存参数
  	//Array.from把伪数组对象转化为数组
	let args=Array.from(arguments).slice(1);
	//调用函数
	let result=context.fn(...args);
	//删除fn
	delete context.fn;
	return result;
}

2,apply的实现思路:

​ 判断对象是否是函数调用,不是抛异常

​ 通过新对象(context)来调用函数

​ 给context创建一个fn设置为需要调用的函数

​ 结束调用后删除fn

Function.prototype.myApply=function(context){
	if(typeof this !=='function'){
		throw new TypeError('Not a Function')
	}
	 //不传参默认为window
	let context =context||window;
	//保存this
	context.fn=this;
	let result;
	
	// 需要判断是否存在第二个参数
	if(arguments[1]){
		result=context.fn(...arguments[1])
	}else{
		result=context.fn()
	}
	delete context.fn;
	return result;
}

3,bind 的实现思路:

​ 判断是否是函数调用,不是抛异常

​ 返回函数

​ 判断函数的调用方法,是否是被new出来的

​ new出来的返回空对象,但是实例的_ proto__指向 _this的 prototype

​ 完成函数柯里化

​ Array.prototype.slice.call()

Function.prototype.myBind=function(context){
	// 判断是否是一个函数
	if(typeof this !=='function'){
		throw new TypeError('Not a Function')
	}
	
	// 保存调用bind的函数
	const_this=this;
	// 保存参数
	const args=Array.prototype.slice.call(arguments,1)
	
	// 返回一个函数
	return function F(){
		// 判断是不是new出来的
		if(this instanceof F){
			// 如果是new出来的
      		// 返回一个空对象,且使创建出来的实例的__proto__指向_this的prototype,
      		//且完成函数柯里化
			return new_this(...args,...arguments);
		}else{
			// 如果不是new出来的改变this指向,且完成函数柯里化
			return _this.apply(context,args.concat(...arguments))
		}
	}
}

​ 4,new 的实现思路:

​ 字面量创建对象和new创建对象的区别,new内部都实现了什么

​ 字面量:更简单,方便阅读,不需要作用域解析,速度快

​ new内部:创建一个新对象,使用对象的_ _proto__指向原函数prototype

​ 改变this的指向,并执行该函数,执行结果保存起来,作为result

​ 判断执行函数的结果是不是null或者undefined,

​ 如果是返回之前的新对象,不是返回result

function myNew(fn,...args){
	 // 创建一个空对象
	let obj={};
	// 使空对象的隐式原型指向原函数的显式原型
	obj.__proto__=fn.prototype;
	// this指向obj
	let result=fn.apply(obj,args);
	//判断执行函数的结果是不是null或者undefined
	//如果是返回之前的新对象,不是返回result
	return result instanceof Object?result:obj;
}

防抖截流实现

​ 防抖:n秒后再执行该事件,若n秒内被重复触发,则重新计时

//防抖:只要不是最后一次触发,就不执行异步请求
function debounce(func,ms){
	let timer;
	return function(...args){
		//如果timer不是undefined,就清除,然后再次执行setTimeOut
		if(timer) clearTimeOut(timer);
		//重新开始下一轮等待
		timer=setTimeOut(()=>{
			func.apply(this,args)
		},ms)
	}
}

​ 节流:n秒内只运行一次,若在n秒内反复触发,只生效一次

//节流:第一次发送请求后,只要响应没有回来。就不能发送第二次请求
function throttle(func,ms){
	//开关变量
	let canRun=true;
	return function(...args){
		if(!canRun) return;
		//点击后,需要把开关关上
		canRun=false;
		setTimeOut(()=>{
			func.apply(this,args)
			canRun=true;
		},ms)
	}
}

var let const 有什么区别

​ var

​ var声明的变量可进行变量提升,let和const不会

​ var可以重复声明

​ var在非函数作用域中定义是挂载到window上的

​ let

​ let声明的变量只在局部起作用

​ let防止变量污染

​ let声明的变量不可再声明

​ const

​ 具有let的所有特征

​ 不可被修改

​ 如果使用const声明的是对象的话,可以修改对象里面的值

事件循环(event loop)

​ 1,执行宏任务script

​ 2,进入script后,所有的同步任务主线程执行

​ 3,所有的宏任务放入宏任务执行队列

​ 4,所有的微任务放入微任务执行队列

​ 5,先清空微任务队列

​ 6,再取一个宏任务执行,再清空微任务队列

​ 7,依次循环

​ 宏任务:script,setTimeOut,setInterval,setImmediate

​ 微任务:promise.then,process.nextTick,Object.observe,mutationObserver

promise使用及实现

​ promise对象代表一个异步操作,有三种状态:

​ 1,pending :初始状态,不是成功或者失败的状态

​ 2,fulfilled :意味操作成功完成

​ 3,rejected:意味操作失败

​ 优点:

​ 1,将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数,避免回调地狱

​ 2,promise对象提供统一的接口,使得控制异步操作更加容易

​ 缺点:

​ 1,无法取消promise,一旦新建就会立即执行,无法中途取消

​ 2,如果不设置回调函数,promise内部抛出的错误,不会反映到外部

​ 3,当处于pending状态时,无法得知进展到哪一个阶段

function 前一项任务(){ //不要写回调函数的形参变量了!
	return new Promise(
		function(door){
			原异步任务代码
			原异步任务最后一句话执行完:
			door()开门!->自动执行后续.then()中的下一项任}
		)
	}
//调用时只要后一项任务也返回new Promise()对象,则可以继续.then: 
//前一项任务().then(后一项任务).then(下一项任务)...

//简易版promise
class MyPromise {
      constructor(executor) {
        // 规定状态
        this.state = "pending"
        // 保存 `resolve(res)` 的res值
        this.value = undefined
        // 保存 `reject(err)` 的err值
        this.reason = undefined
        // 成功存放的数组
        this.successCB = []
        // 失败存放的数组
        this.failCB = []


        let resolve = (value) => {
          if (this.state === "pending") {
            this.state = "fulfilled"
            this.value = value
            this.successCB.forEach(f => f())
          }
        }
        let reject = (reason) => {
          if (this.state === "pending") {
            this.state = "rejected"
            this.value = value
            this.failCB.forEach(f => f())
          }
        }

        try {
          // 执行
          executor(resolve, reject)
        } catch (error) {
          // 若出错,直接调用reject
          reject(error)
        }
      }
      then(onFulfilled, onRejected) {
        if (this.state === "fulfilled") {
          onFulfilled(this.value)
        }
        if (this.state === "rejected") {
          onRejected(this.value)
        }
        if (this.state === "pending") {
          this.successCB.push(() => { onFulfilled(this.value) })
          this.failCB.push(() => { onRejected(this.reason) })
        }
      }
    }


//Promise.all函数
Promise.all=function(promise){
	let list=[];
	let count=0;
	function handle(i,data){
		list[i]=data;
		count++;
		if(count == promise.lenght){
			resolve(list)
		}
	}
	return Promise(resolve,reject)=>{
		for(let i=0;i<promise.lenght;i++){
			promise[i].then(res=>{
				handle(i,res)
			},err=>reject(err))
		}
	}
}

promise并行执行和顺序执行

​ 1,Promise.all并行执行promise

​ (1)getA和getB并行执行,然后输出结果,如果有一个错误,就抛出错误

//每一个promise都必须返回resolve结果才正确
//每一个promise都不处理错误
const getA=new Promise((resolve,reject)=>{
	//模拟异步任务
	setTimeout(function(){
		resolve(2);
	},1000)
})
.then(result=>result)

cosnt getB=new Promise((resolve,reject)=>{
	setTimeout(function(){
		//resolve(3)
		reject('Error in getB')
	},1000)
})
.then(result=>result)

Promise.all([getA,getB]).then(data=>{
	console.log(data)
})
.catch(e=>console.log(e))

​ (2)getA和getB并行执行,然后输出结果,总是返回resolve结果

//每一个promise自己处理错误
const getA=new Promise((resolve,reject)=>{
	//模拟异步任务
	setTimeout(function(){
		resolve(2);
	},1000)
})
.then(result=>result)
.catch(e=>e)

const getB =new Promise((resolve,reject)=>{
	setTimeout(function(){
		//resolve(3)
		reject('Error in getB')
	},1000)
})
.then(result=>result)
.catch(e=>e)

Promise.all([getA,getB]).then(data=>{
	console.log(data)
})
.catch(e=>console.log(e))

​ 2,顺序执行promise

​ (1)先getA然后执行getB ,最后addAB

//连续使用then链式操作
function getA(){
      return  new Promise(function(resolve, reject){ 
      setTimeout(function(){     
            resolve(2);
        }, 1000);
    });
}
 
function getB(){
    return  new Promise(function(resolve, reject){       
        setTimeout(function(){
            resolve(3);
        }, 1000);
    });
}
 
function addAB(a,b){
    return a+b
}

function getResult(){
    var  obj={};
    Promise.resolve().then(function(){
        return  getA() 
    })
    .then(function(a){
         obj.a=a;
    })
    .then(function(){
        return getB() 
    })
    .then(function(b){
         obj.b=b;
         return obj;
    })
    .then(function(obj){
       return  addAB(obj['a'],obj['b'])
    })
    .then(data=>{
        console.log(data)
    })
    .catch(e => console.log(e));

}
getResult();


//使用promise构建队列
function getResult(){
    var res=[];
    // 构建队列
    function queue(arr) {
      var sequence = Promise.resolve();
      arr.forEach(function (item) {
        sequence = sequence.then(item).then(data=>{
            res.push(data);
            return res
        })
      })
      return sequence
    }

    // 执行队列
    queue([getA,getB]).then(data=>{
        return addAB(data[0],data[1])
    })
    .then(data => {
        console.log(data)
    })
    .catch(e => console.log(e));

}

getResult();


//使用async、await实现类似同步编程
function getResult(){
 async function queue(arr) {
  let res = []
  for (let fn of arr) {
    var data= await fn();
    res.push(data);
  }
  return await res
}

queue([getA,getB])
  .then(data => {
    return addAB(data[0],data[1])
  }).then(data=>console.log(data))

}

闭包

​ 什么是闭包?闭包的作用?闭包的应用?

​ 既重用一个变量,又包含变量不被篡改的一种编程方法。外层函数的作用域对象,因为受到内存函数引用和保护,称为闭包对象

​ 作用:

​ 保护——避免命名冲突

​ 保存——解决循环绑定引发的索引问题

​ 变量不会被销毁——外层函数的变量因为受到内存函数的引用,所以不会被垃圾回收机制回收

​ 应用:

​ 设计模式中的单例模式,for循环中的保留i的操作,防抖,节流,函数柯里化

​ 缺点:

​ 会出现内存泄露

​ 解决:

​ 一旦一个闭包不再使用,应该尽快释放,赋值为null

​ 鄙视题: 闭包形成的原因: 外层函数调用后,因为内层函数引用着外层函数的作用域对象,导致外层函数的作用域对象无法释放,形成了闭包!

垃圾回收和内存泄漏

​ 内存泄露:

​ 指不再使用的内存没有被及时的释放,导致该段内存无法被使用

​ 为什么会导致的内存泄漏

​ 我们无法再通过js访问某个对象,而垃圾回收机制却认为该对象还在被引用,因此垃圾回收机制不会释放该对象,导致该内存永远无法释放,积少成多,系统会越来越卡以至于崩溃

​ 垃圾回收机制都有哪些策略?

​ 标记清除法:

​ 垃圾回收机制获取并标记他们,然后访问并标记所有来自他们的引用,然后再访问这些对象并标记他们的引用,如此递进结束后发现没有标记的,就删除,进入执行环境的不能删除

​ 引用计数法:

​ 当声明一个变量并给该变量赋值一个引用类型的值的时候,该值的计数+1,当该值赋值给另一个变量的时候,该计数+1,当该值被其他值取代时,该计数-1,当计数变为0时,说明无法访问该值,垃圾回收机制清除该对象

事件委托

​ 事件委托就是利用事件冒泡,只制定一个时间处理程序,就可以管理某一类型的所有事件。

​ 事件委托就是把原本需要绑定在子元素的响应事件委托给父元素,让父元素担当事件监听的职务,事件委托的原理是DOM元素的事件冒泡

axios的特点有哪些

​ 1,axios是一个基于promise的HTTP库,支持promise所有的API

​ 2,它可以拦截请求和响应

​ 3,它可以转换请求数据和响应数据,并对响应回来的内容自动转换成JSON类型的数据

​ 4,安全性更高,客户端支持防御xsrf(XSS+CSRF)

typescript
重绘和回流

​ 回流:render树中一部分或全部元素需要改变尺寸、布局、或着需要隐藏而需要重新构建,这个过程叫做回流。回流必将引起重绘

​ 重绘:render树中一部分元素改变,而不影响布局的,只影响外观的,比如颜色。该过程叫做重绘

​ 页面至少经历一次回流和重绘(第一次加载的时候)

箭头函数和普通函数的区别

​ 1,箭头函数是匿名函数,不能作为构造函数,不能使用new

​ 2,箭头函数不能绑定arguments,要有rest参数解决

​ 3,箭头函数没有原型属性

​ 4,箭头函数的this永远指向其上下文的this

​ 5,箭头函数不能绑定this,会捕获其所在上下文的this值,作为自己的this值

如何对网站的文件和资源进行优化

​ 1,文件合并(减少HTTP请求)

​ 2,文件压缩(减少文件下载体积)

​ 3,使用cdn托管资源

​ 4,使用缓存

​ 5,gzip压缩js和css文件

​ 6,mate标签优化,heading标签优化,alt优化

​ 7,反向链接,网站外链接优化

深浅拷贝是什么如何实现

​ 深拷贝:指针赋值,并且拷贝内容

//简易版
function deepClone(obj){
	let obj2={}
	for(var i in obj){
		if(typeof obj[i]==='object'){
			obj2[i]=deepClone(obj[i])
		}else{
			obj2[i]=obj[i]
		}
	}
	return obj2
}

//把一个对象的属性和方法一个一个找出来,在另一个对象中开辟对应的空间,一个个存储到另一个对象中
var obj1={
	age:10,
	sex:'女',
	car:['奔驰','宝马'],
	cat:{
		name:'lulu',
		age:5
	}
}
//声明一个空对象
var obj2={};
//通过函数实现,把对象a中的所有数据深拷贝到对象b中
//使用递归函数
function deepCopy(obj,targetObj){
	for(let i in obj){
		let item = obj[i]
		if(item instanceof Array){
			targetObj[i]=[];
			deepCopy(item,targetObj[i])
		}else if(item instanceof Object){
			targetObj[i]={};
			deepCopy(item,targetObj[i])
		}else{
			targetObj[i]=obj[i]
		}
	}
}

deepCopy(obj1,obj2);
console.dir(obj1);
console.dir(obj2)

​ 浅拷贝:只指针赋值

//第一种
//把一个对象里面的所有属性值和方法都复制给另一个对象
let a ={boss:{name:'lala'}}
let b =Object.assign({},a)
b.boss.name='lala'
console.log(a)   //lala

//第二种
//直接把一个对象赋值给另一个对象,使得两个都指向同一个对象
let a ={age:11}
let b =a;
b.age=22;
console.log(a)   //22

//或者是解构的方法
let c ={...a}

Vue篇

vue数据双向绑定原理

​ 数据劫持:vue.js是采用数据劫持+发布者-订阅者模式的方法,通过object.defineProperty()来劫持各个属性的setter,getters,在数据变动时发布消息给订阅者,触发相应的监听回调

​ vue的绑定原理:访问器属性+虚拟dom树

​ 变量被修改时,访问器属性发出通知,虚拟dom树扫描并仅更新受影响的元素

vue computed

​ computed:计算属性,有时页面上要显示的值,后端并没有直接给出,但是却可以根据给出的其它变量值经过复杂的计算过程动态计算获得。computed的值会有缓存。避免重复计算——效率高

computed和watch的区别

​ computed:计算属性,依赖其他属性,当其他属性改变的时候下一次获取computed值时也会改变,computed的值会有缓存

​ watch:类似于数据改变后的回调,如果想深度监听的话,后面加一个deep:true,如果想监听完立马运行的话,后面加一个immediate:true

生命周期

​ vue的生命周期就是vue实例创建到实例销毁的过程。期间会有8个钩子函数的调用

​ 1,beforeCreate 创建之前,此时还没有data和method

​ 2,Created 创建完成,此时data和method可以使用

​ 在Created之后beforeMount之前,如果没有el选项,生命周期结束

​ 3,beforeMount 在渲染之前

​ 4,mounted 页面已经渲染完成,并且VM实例中已经添加完$el了,已经替换掉那些dom 元素了,这个时候可以操作dom了,但是获取不了元素的高度等属性,如 果想要获得,需要使用nextTick()

​ 5,beforeUpdate data改变后,对应的组件重新渲染之前

​ 6,updated data改变后,对应的组件重新渲染之后

​ 7,beforeDestory 在实例销毁之前,此时实例仍然可以使用

​ 8,destoryed 实例销毁后

vue组件通信

​ 1,父传子

​ 子组件设置props + 父组件设置v-bind: / :

​ 2,子传父

​ 子组件的$emit + 父组件设置v-on / @

​ 3,$bus

​ 任意组件通信,新建一个空的全局Vue对象,利用emit发送,on接收

​ 4,ref

​ ref被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的$refs对象上。

​ 如果在普通的dom元素上使用,引用指向就是dom元素。

​ 如果用在子组件上,引用就组件实例。

​ 父模板:

​ 父访问子:父组件:this.$refs.子名称.子数据/方法名()

​ 子访问父:子组件:this.$parent.子数据/方法名()

​ 5,Vuex

​ state:存储数据的,state里面存放的数据是响应式的,state数据发生改变,对应这个数据的组件也会发生改变 用this.$store.state.xxx调用

​ getters:相当于store的计算属性,主要是对state中数据的过滤,用this.$store.getters.xxx调用

​ mutations:处理数据逻辑的方法全部放在mutations中,当触发事件想改变state数据的时候使用mutations,用this.$store.commit调用,给这个方法添加一个参数,就是mutation的载荷(payload

​ actions:异步操作数据,但是是通过mutation来操作 用this.$store.dispatch来触发,actions也支持载荷

mvvm模式、mvc模式理解

​ MVC:

​ 模型视图控制器,视图是可以直接访问模型,所以,视图里面会包含模型信息,mvc关注的是模型不变,所以,在mvc中,模型不依赖视图,但是视图依赖模型

​ MVVM:

​ 模型 视图 和vm, vm是作为模型和视图的桥梁,当模型层数据改变,vm会检测到并通知视图层进行相应的修改

diff

​ diff算法是指对新旧虚拟节点进行对比,并返回一个patch对象,用来存储两个节点不同的地方,最后利用patch记录的消息局部更新dom

虚拟DOM的优缺点

​ 缺点:首次渲染大量dom时,由于多了一层虚拟dom计算,会比innerHTML插入慢

​ 优点:减少了dom操作,具备局部更新的能力

v-for为什么必须绑定:key

​ 如果不绑定:key,则每删除数组中的一个元素,v-for都会删除所有的副本,重建整个列表,绑定:key是给每个元素副本添加一个唯一标识,在删除数组元素时,根据这个唯一的标识,找到对应的元素对象,删除即可,其他元素不受影响。

vuex

​ Vuex 是一个专为 Vue.js 应用程序开发的 状态管理模式

​ 它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
使用场景:

​ 1,组件间的状态共享: 登录状态

​ 2,组件间的数据共享: 购物车的数据, 登录的token

​ 5个核心属性

​ 1,state: 数据存放

​ 2,getters: 相当于计算属性

​ 3,mutation: 同步操作, 修改数据

​ 4,action: 异步操作

​ 5,modules: 模块化

原理

1,vuex实现了一个单项数据流,在全局又有一个state存放数据,
2,当组件要更改state中的数据时,必须通过mutation进行,mutation同时提供了订阅者模式供外部插件调用获取state数据的更新
3,而当所有异步操作(常见于调用后台接口异步获取更新数据)或者批量同步操作需要走action
4,但action也是无法直接修改state的,还是需要通过mutation来修改state的数据
5,最后根据state的变化,渲染到视图上

vue-router

​ 通过hashHistory interface两种方式实现前端路由,更新视图但不重新请求页面”是前端路由原理的核心之一,目前在浏览器环境中这一功能的实现主要有两种方式

​ hash模式:

​ 利用onhashchange事件实现前端路由,利用URL中的hash来模拟一个hash,以保证URL改变时,页面不会重新加载

​ history模式:

​ 利用pushstate和replacestate来将URL替换但不刷新,但是一旦刷新,可能出现404,因为没有当前真正的路径,需要后端配合,将不存在的路径重定向到入口文件

Vue-router有哪几种钩子函数

​ beforEach(to,from,next)

​ afterEach(to,from,next)

​ beforRouterLeave(to,from,next)

Vue优化方式

​ 图片懒加载,路由懒加载,为减少重新渲染和创建dom节点的时间,采用虚拟dom

Vue中的nextTick

​ nextTick:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。

​ 应用:

​ 想要在Vue生命周期函数中的created()操作DOM可以使用Vue.nextTick()回调函数

​ 在数据改变后要执行的操作,而这个操作需要等数据改变后而改变DOM结构的时候才进行操作,需要用到nextTick

为什么虚拟dom会提高性能

​ 虚拟dom相当于在JS和真实的dom中间加了一个缓存,利用dom,diff 算法避免了没有必要的dom操作,从而提高性能

React篇

dom-diff

​ 虚拟dom通过js的object对象模拟dom中的节点,然后再通过特定的渲染方法将其渲染成真实的dom节点

​ 频繁的操作dom,或大量造成页面的重绘和回流

​ diff算法把树形结构按照层级分解,只比较同级元素,给列表结构的每个单元添加唯一的key值,方便比较

react diff原理

​ 1,tree diff web UI 中dom节点跨层级的移动操作特别少,可以忽略不计

​ 2,component diff 拥有相同类的两个组件将会生成相似的树形结构,拥有不同类的两个组件会生成不同的树形结构

​ 3,element diff 对于同一层级的一组子节点,他们可以通过唯一的id进行区分

列表key属性

key是用来帮助react 识别哪些内容被更改、添加或者删除。如果 key值发生了变更,react 则会触发 UI 的重渲染。key就是元素的唯一标识,相当于身份证一样。

jsx原理
react-router原理

​ 实现URLUI界面的同步。其中在react-router中,URL对应Location对象,而UI是由react components来决定的,这样就转变成locationcomponents之间的同步问题

redux原理

img

​ 1,找到最上面的state

​ 2,在react中state决定了视图(ui),state的变化就会调用react的render()方法,从而改变视图

​ 3,用户通过一些事件(点击按钮,移动鼠标等)就会向reducer派发一个action

​ 4,reducer接收到action后就会去更新state

收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
img
img

如果你需要这些资料,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

据改变后而改变DOM结构的时候才进行操作,需要用到nextTick

为什么虚拟dom会提高性能

​ 虚拟dom相当于在JS和真实的dom中间加了一个缓存,利用dom,diff 算法避免了没有必要的dom操作,从而提高性能

React篇

dom-diff

​ 虚拟dom通过js的object对象模拟dom中的节点,然后再通过特定的渲染方法将其渲染成真实的dom节点

​ 频繁的操作dom,或大量造成页面的重绘和回流

​ diff算法把树形结构按照层级分解,只比较同级元素,给列表结构的每个单元添加唯一的key值,方便比较

react diff原理

​ 1,tree diff web UI 中dom节点跨层级的移动操作特别少,可以忽略不计

​ 2,component diff 拥有相同类的两个组件将会生成相似的树形结构,拥有不同类的两个组件会生成不同的树形结构

​ 3,element diff 对于同一层级的一组子节点,他们可以通过唯一的id进行区分

列表key属性

key是用来帮助react 识别哪些内容被更改、添加或者删除。如果 key值发生了变更,react 则会触发 UI 的重渲染。key就是元素的唯一标识,相当于身份证一样。

jsx原理
react-router原理

​ 实现URLUI界面的同步。其中在react-router中,URL对应Location对象,而UI是由react components来决定的,这样就转变成locationcomponents之间的同步问题

redux原理

img

​ 1,找到最上面的state

​ 2,在react中state决定了视图(ui),state的变化就会调用react的render()方法,从而改变视图

​ 3,用户通过一些事件(点击按钮,移动鼠标等)就会向reducer派发一个action

​ 4,reducer接收到action后就会去更新state

收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
[外链图片转存中…(img-CnfoBaXK-1715637059425)]
[外链图片转存中…(img-NWA1Ynmv-1715637059426)]

如果你需要这些资料,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值