js中对数组的一些操作

闭包

闭包是函数中返回一个函数,函数能够访问到其父级作用域,

优点:保护变量,封装到函数内部,避免全局污染 延长变量的生命周期,即使函数执行完成后还能继续使用

缺点:内存占用,无法被垃圾回收 甚至会出现内存泄漏问题 ,闭包会设计到作用域链的查找,对性能也会有影响。

解决内存泄漏问题 从根本上来说就是对外部变量的引用,如果能够接触对变量的引用,使得其能够被垃圾回收机制释放。当然这只是最明显的,此外还有对闭包函数以及解绑函数本身的一个释放。使该变量=null进行释放

数据类型判断有四种方式

直接的有type of跟instanceof

前者主要是判断基本数据类型(除了null,null会判断成object)引用类型都会判断成object,除了function会被正常判断,

instanceof的返回值是true或者false,相反它不能判断基本数据类型(都会返回false),只能判断引用类型。

原型中的判断方式 Object.prototype.toString.call,调用slice(8,-1)就能获取到类型,均能获得

构造函数的name属性也可以进行判断

7中基本数据类型

Number,String,null,BigInt,Symbol,Boolean,Undefined

放入栈内存中

引用数据类型

Object,Array,Date,Error,Function,RegExp

放入堆内存中 在栈中存储了指针在堆中的起始位置。

generator函数生成器

function* yield 生成迭代器 next调用

浏览器工作原理

浏览器本地存储

cookie localstorage,sessionstorage,indexdDB

发布-订阅模式

vue-router

导航守卫有三类:全局守卫 路由独享守卫和组件内守卫(钩子)

两种历史记录模式

前端路由关键:

1可以修改url,在不刷新页面的情况下跳转路由

2可以监听url的变化,根据url渲染对应组件

hash模式 hash是通过location API修改url的 通过onhashchange监听hash改变

#后面的字符不会发送给服务器 seo(Search Engine Optimization搜索引擎优化)会比较差(没这么容易搜索到) 不会在服务器生成日志记录

HTML5模式 history是通过history.pushState或者history.replacestate修改url 通过popState监听

相比来说不带#号 直接在域名后写路径 优雅

Map Reduce与Filter

Map(当前值,值索引,数组本身)逐个改变数组,注意是改变,而不会生成一个新的数组

?如果不return的话也会直接改变数组

filter(当前值,值索引,数组本身),会删除数组,返回值小于等于原数组长度

reduce((累加器,当前值,值索引,数组本身)=>{},累加器初始值),值,会生成一个新的数组

foreach没有return,直接改变原数组

call apply bind

用处:改变this的指向,实现方法的继承

function.call(this指向,参数1,参数2)

function.apply(this指向,[参数])

function.bind(this指向,参数)//但不是立即执行,返回一个方法,需要手动执行

let test=function.bind()

test()执行

手写call方法

1.原型中进行绑定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Function.prototype.mycall=function(context,..arg){

if(type of this !=="function"){
throw new TypeError("被调用的对象必须是函数")
};

context=context||globalThis;

let fn=Symbol("key");

context[fn]=this;

const result=context[fn](...arg);

delete context[fn]

return result;
}

vue2与vue3的区别

vue3加入组合式api 所以没有this的操作 生命周期没有creat setup等同于create 卸载变成了unmount

vue3中的v-if高于v-for的优先级

根实例的创建从new app变成了createApp

响应式改成了proxy 解决了数组无法通过对下标修改

reactive定义的响应式数据使用proxy包装 ref使用的还是defineProperty,定义一个value属性做响应式

在组合式api时更方便按需引入 tree-shaking

性能优化 静态节点不会被标记 不会进行对比(diff)

mixin方法不被推荐 推荐用hook

v-model 用在自定义组件的时候 value/modelValue 监听事件也不一样

更好的配合ts

vue2的响应式原理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function defineProperty(obj,key,val){
//深层遍历
Observer(val)
Object.defineProperty(data,key,{
get: function(){
return val
},
set: function(newvalue){
//深层遍历
Observer(val)
if(newvalue==value) return
val = newvalue
}

})
}

function Observer(obj){
if(typeof obj!=='object'||object==null){
return
}
for(const key in obj){
defineProperty(obj,key,obj[key])
}
}


因为Object.defineProperty()无法监听到数组的方法,所以vue2中选择了直接对Object的原型进行了一个重写,使其能够监听到相应的方法。

当使用get()和set()来获取和设置该被劫持属性的值,那么不能使用操作属性的valuewritable属性,会冲突。当要访问被劫持属性的值,那么会触发get(),并得到的是get()中返回的值;当要修改被劫持属性的值就会触发set(),其天生具有一个参数newVal,表示新的值

作者:前端平水
链接:https://juejin.cn/post/7268820544995901495
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Proxy

vue3实现响应式的原理,proxy进行监听,但对象本身的方法在Reflect上。

1
2
3
4
5
6
7
8
9
10
11
12
13
const obj = new Proxy({},{
get(target,key,receiver){
return Reflect(target,key,receiver)
},
set(target,key,value,receiver){
if(key=='key'){
module.innerText=value
text.innerText=value
}
return Reflect(target,key,value,receiver)
}
})

mvvm

一种前端的设计模式 Model模式 View视图 ViewModel视图模型

Model模式:通常是数据部分 js部分?

View视图:Html跟Css部分

ViewModel视图模型:两者之间的桥梁,将模型的数据传递给视图,将视图中的交互事件传递给模型

bfc block formatting context 块级格式化上下文

简单的来说,就是把元素块级话,在一个有父子元素的布局中,如果子元素浮动的话,此时,它的父元素因为不是一个bfc会发生坍塌,只要对元素进行bfc化就能解决这个问题。在比如就是当两个元素上下排列的时候,两个外边距坍塌,此时在中间加入一个bfc元素就可以达到没有坍塌的效果。

方法有:float:right||left position:absolute||fixed display: overflow:

单点登录single sign on

一个地方登录,所有其他的页面也是登录装态。

在不同的系统之间再设置一个共享的认证系统,每次进入系统先重定向到认证系统,系统对token资源统一管理。

主域与子域可以共享cookie 然后实现单点登录

虚拟dom

原生js是当数据放生改变时相应的dom进行更新

但是基础框架的虚拟dom是因为框架本身的一些原因,需要对全局进行一个更新,要知道操作真实dom,而且每一次都是这样牵一发而动全身的话会造成很大的性能损耗,所以就有个虚拟dom,虚拟dom完成了对全局的一个更新,再通过对新旧虚拟dom通过diff算法 进行对比,最后对相应的真实dom进行更新。虚拟dom作为中间层就完成了全量更新以及相对性能损耗较小的目的。

为了完成响应式的需求

浏览器渲染原理

先html

构建dom->构建cssom->构建渲染树->布局->绘制

遇到js代码会阻塞,等到构建渲染树时再将js代码装入。

1.样式声明(包括自定义与浏览器自带)

2.计算层叠

​ 比较重要性(自己>浏览器默认)

​ 比较特殊性(权重值)

​ 比较原次序(后来者居上)

3.如果可以,从父元素中继承

4.赋予默认值

浏览器缓存

强制缓存跟协商缓存两种

强制缓存有一个cache-control跟expires,优先级是前者大于后者,前者可以设置一个最大过期时间,max-age,expires(http1.1之前的)是一个过时的字段。

协商缓存时通过etag,让客户端跟服务器进行一个对比,如果一样的话,那就直接在缓存中读取,如果不一致的话那就重新请求。

主要有last-modified(服务器返回的字段)与if-modified-since(客户端发送的字段)etag(服务器返回的字段,资源的唯一标识符)if-none-match(客户端发送的字段,客户端期待标识符)如果两者相等没有更新,不相等则代表更新了。

304状态码就是协商缓存中代表资源没有更新。

强制缓存主要用于一些静态资源,比如说(css,js,图片等)设置一个长时间的缓存。

直接赋值,浅拷贝与深拷贝

基于引用类型来说

直接赋值是赋值对象与被赋值对象指向同一块区域

浅拷贝是对引用类型的第一层是全新的赋值,但是还有更深的引用类型存在的话,这时候改变这些的话会连同原来的一起改变。

浅拷贝常用的方法数组中的slice与contact然后对象中有assign以及使用拓展运算符号filter,新的方法toSorted,toSpliced,toReversed都是返回一个新的数组而不改变原数组。

深拷贝常用的一个是JSON.parse(JSON.stringify(对象)),无法解决循环引用问题,无法拷贝特殊对象和函数

还有就是手写递归函数进行递归赋值

vuex与pinia

pinia只有state、getter,action仨,并且支持组合式的写法,在最后return回去就行了。

vuex多了mutation跟module

webpack与vite

构建速度:vite更新更快

webpack会将所有文件都打包成一个bundle 初次加载会更慢一些,热更新需要整个替换

vite利用了浏览器支持es module的特性,实现了按模块更新。