随意的世界 - 前端
type: channel
link: https://www.nasuiyile.cn/前端/
items: IndexedDB
items: Web Worker
items: SSR
items: AST abstract syntax Tree
items: Vue双向数据绑定原理
items: 牛客前端刷题记录2
items: js牛客刷题记录
items: Webpack和Vite
items: node更换版本（简单操作）
items: vue3新特性

IndexedDB
type: item
date: 2024-01-15T13:33:30+08:00
description: IndexedDB浏览器数据库 IndexedDB 入门教程 - 阮一峰的网络日志 (ruanyifeng.com)概述随着浏览器的功能不断增强，越来越多的网站开始考虑，将大量数据储存在客户端，这样可以减少从服务器获取数据，直接从本地获取数据。现有的浏览器数据储存方案，都不适合储存大量数据：Cookie 的大小不超过4KB，且每次请求都会发送回服务器；LocalStorage 在 2.5MB 到 10MB 之间（各家浏览器不同），而且不提供搜索功能，不能建立自定义的索引。所以，需要一种新的解决方案，这就是IndexedDB诞生的背景。通俗的说，IndexedDB就是浏览器提供的本地数据库，它可以被网页脚本创建和操作。IndexedDB允许存储大量数据，提供查找接口，还能建立索引。这些都是LocalStorage所不具备的。就数据库类型而言，IndexedDB不属于关系型数据库（不支持SQL查询），更接近NoSQL数据库。IndexedDB具有以下特点。键值对存储：IndexedDB内部采用对象仓库（object store）存放数据。所有类型的数据可以直接存入，包括javascript对象。对象仓库中，数据以键值对的形式保存，每一个数据记录都有一个对应的主键，主键是独一无二的，不能有重复，负责会抛出一个错误。异步。IndexedDB操作不会锁死浏览器，用户依然可以进行其他操作，这与LocalStorage形成对比，后者的操作是同步的。异步是为了防止大量数据的读写拖慢网页的表现。同源支持：IndexedDB受到同源限制，每一个数据库对应创建它的域名，网页只能访问自身名下的数据库，而不能访问跨域的数据库。存储空间大：IndexedDB的存储空间比LocalStorage大得多，一般来说不少于250MB，甚至没有上限。支持二进制存储：IndexedDB不仅可以存储字符串，还可以存储二进制数据（ArrayBuffer对象和Blob对象）基本概念IndexedDB是一个比较复杂的API，涉及不少概念。它把不同实体，抽象成一个个对象接口。学习这个API，就是学习它的各种对象接口。数据库：IDBDatabase 对象对象仓库：IDBObjectStore 对象索引： IDBIndex 对象事务： IDBTransaction 对象操作请求：IDBRequest 对象指针： IDBCursor 对象主键集合：IDBKeyRange 对象下面是一些主要的概念。数据库数据库是一系列相关数据的容器。每个域名（严格的说，是协议+域名+端口）都可以新建任意多个数据库。IndexedDB数据库有版本的概念。同一时刻，只能有一个版本的数据库存在。如果要修改数据库结构（新增或删除表、索引或者主键），只能通过升级数据库版本完成。对象仓库每个数据库包含若干个对象仓库（object store)。它类似于关系型数据库的表格。数据记录对象仓库保存的是数据记录。每条记录类似于关系型数据库里的行，但只有主键和数据体俩部分。主键用来建立默认的索引，必须是不同的，否则会报错。主键可以是数据记录里面的一个属性，也可以指定为一个递增的整数编号{ id: 1, text: 'foo' }上述对象中，id属性可以当做主键。数据体可以是任意数据类型，不限于对象。索引为了加速数据的检索，可以再对象仓库里面，为不同的属性建立索引。事务数据记录的读写和删改都要通过事务完成。事务对象提供error、abort和complete三个事件，用来监听结果操作流程IndexedDB 数据库的各种操作，一般是按照下面的流程进行的。这个部分只给出简单的代码示例，用于快速上手，详细的各个对象的 API 请看这里。var request = window.indexedDB.open(databaseName, version);这个方法接受俩个这个方法接受两个参数，第一个参数是字符串，表示数据库的名字。如果指定的数据库不存在，就会新建数据库。第二个参数是整数，表示数据库的版本。如果省略，打开已有数据库时，默认为当前版本；新建数据库时，默认为1。indexedDB.open()方法返回一个 IDBRequest 对象。这个对象通过三种事件error、success、upgradeneeded，处理打开数据库的操作结果。（1）error 事件error事件表示打开数据库失败。request.onerror = function (event) { console.log('数据库打开报错'); };（2）success 事件success事件表示成功打开数据库。var db; request.onsuccess = function (event) { db = request.result; console…

Web Worker
type: item
date: 2024-01-10T13:56:37+08:00
description: Web Worker简介Web Worker（工作线程）是HTML5中提出的概念，分为俩汇总类型，专用线程（Dedicated Web Worker）：专用线程仅能被创建它的脚本所使用（一个专用线程独对应一个主线程）。共享线程（Shared Web Worker）：而共享线程能够在不同的脚本下进行使用（一共共享线程对应多个主线程）。专用线路可以看做是默认情况的WebWorker，加上修饰词的目的是为了与主线程进行区分。用途Web Worker 的意义在于可以将一些耗时的数据处理操作从主线程中剥离，使主线程更加专注于页面渲染和交互。懒加载文本分析流媒体数据处理canvas 图形绘制图像处理注意有同源限制无法访问DOM节点运行在一个上下文中，无法使用Window对象WebWorker的运行不会影响主线程，但主线程交互时仍收到主线程单线程的瓶颈制约。换言之，如果Worker线程频繁与主线程进行交互，主线程由于需要处理交互，仍有可能使页面发生阻塞共享线程可以被多个浏览上下文调用（Browsing context）调用，但所有这些浏览上下文必须同源（相同协议，主机和端口号）Worker上下文 Worker执行的上下文，与主页面执行时的上下文并不相同，最顶层的对象并不是window，而是WorkerGlobalScope，所以无法访问window、以及与window相关的DOM API，但是可以与setTimeout、setInterval等协作。WorkerGlobalScope作用域下的常用属性、方法：1、self： WorkerGlobalScope 的 self 属性对对象本身的引用；2、location：location 属性返回当线程被创建出来的时候与之关联的 WorkerLocation对象，它表示用于初始化这个工作线程的脚步资源的绝对 URL，即使页面被多次重定向后，这个 URL 资源位置也不会改变；3、close：关闭当前线程；4、importScripts：通过importScripts()方法通过url在worker中加载库函数；5、XMLHttpRequest：能发出Ajax请求，但是XMLHttpRequest的responseXML和channel属性总会返回null；6、能调用setTimeout/setInterval以及addEventListener/postMessage等；具体分类为为：时间相关clearInterval()clearTimeout()setInterval()setTimeoutWorker 相关importScripts()close()postMessage()存储相关CacheIndexedDB网络相关FetchWebSocketXMLHttpRequest支持根据 CanI Use 网站的统计，目前约有98.01% 的浏览器支持专用线程。而对于共享线程，则仅有大约 41.66% 的浏览器支持。if (window.Worker) { // ... }if (window.SharedWorker) { // ... }专用线程线程创建专用线程由Worker()方法创建，可以接收俩个参数，第一个参数是必填的脚本的URL，第二个参数是可选的配置对象options，可以指定type、credentials、name三个属性URL是一个DOMString表示worker将执行的脚本的URL。它必须遵循同源策略。options包含可以再创建对象实例时设置的选项的属性的对象。可用属性如下type：用以指定 worker 类型的 DOMString 值. 该值可以是 classic 或 module. 如果未指定，将使用默认值 classic.credentials：用以指定 worker 凭证的 DOMString 值.该值可以是 omit, same-origin，或 include.。如果未指定，或者 type 是 classic，将使用默认值 omit (不要求凭证)。name：在 DedicatedWorkerGlobalScope 的情况下，用来表示 worker 的 scope 的一个 DOMString 值，主要用于调试目的。通常形式创建worker线程var worker = new Worker('worker.js') //var worker = new Worker('worker.js', { name: 'workerName'})另外，通过URL.createObjectURL()创建URL对象，可以实现创建内嵌的worker：var myTask = ` //js脚本执行代码 `; //创建Blob对象 var blob = new Blob([myTa…

SSR
type: item
date: 2024-01-09T14:18:37+08:00
description: SSR谈谈我对服务端渲染(SSR)的理解 - 掘金 (juejin.cn)什么是SSRCSR是client Side Render简称；页面上的内容是我们JS文件渲染出来的，js文件运行在浏览器上面，服务端只返回一个HTML模板。SSR是Server Side Render简称；页面上的内容是通过服务端渲染生成的，浏览器直接显式服务端返回的HTML就可以了。SSR解决的问题：优点SEO：搜索引擎优先取页面HTML结构，使用SSR时，服务端已经生成了和业务关联的HTML，有利于SEO首屏呈现渲染：用户无需等待页面所有js加载完成就可以看到页面视图（压力来到了服务器，所以需要权衡哪些用服务端渲染，哪些交给客户端）缺点需要特殊库的兼容，提升了整体项目的复杂度由于没有动态更新，（拿vue举例子）所有生命周期钩子函数中，只有beforeCreate和created会在服务端渲染SSR过程中被调用。也就是说任何其他生命周期钩子函数中的代码（beforeMount或mounted，）只会在客户端执行同时渲染对服务端的压力也是相对较大的，现在主流的无论是vue还是react框架都提供了完善的对SSR的支持，但是这里仍然奉劝大家，开始做项目选型的时候就要考虑好前端部分是否需要做SSR，将一个已经开发了很长一段时间的项目改成SSR的模式是非常费时费力的。SSR渲染流程和传统那么我们来首先看看前后端不分离下的请求流程，也就是是传统服务端渲染前后端职责不清前后端代码杂揉在一起项目难以管理和维护 尽管如此，这种渲染方式还是有一些好处：客户端能够快速呈现服务器端渲染好的页面，减少白屏时间，这能够提供很好的用户体验SEO 友好，服务端渲染从服务器发出的html带有页面内容，可提高搜索排名。下面是主流的前后端分离架构客户端渲染指使用 JS 来渲染页面大部分内容。客户端在请求时，服务端不做任何处理，直接将前端资源打包后生成的html返回给客户端，此时的html中无任何网页内容，需要客户端去加载执行js代码才能渲染生成页面内容，同时完成事件绑定，然后客户端再去通过ajax请求后端api获取数据更新视图。这样一来，前后端代码解耦，两端使用 ajax 进行交互实现局部刷新。但这种方式也有一些不足：首屏加载缓慢，因为要等 js 加载完毕后，才能进行页面渲染SEO 不友好，SPA模式的客户端渲染从服务器发出的只是一个没有内容的空壳，大部分页面内容通过js渲染，搜索引擎自然爬不到东西客户端渲染至少发起http请求三次，第一次是请求页面，第二次是请求页面里的JS脚本（渲染dom和进行事件绑定），第三次是动态数据ajax请求。而服务端渲染将传统的3次串行http请求简化成一次http请求，客户端只需要请求页面，解析服务端返回的html即可。需要重复渲染，因为发送ajax请求向后台获取数据，一般在componentDidMounted生命周期，页面已经渲染过一次，等到获取数据后更新视图，页面又需要再渲染一次SSR渲染其实就是将一套JS代码在服务端执行一遍渲染静态页面，又在客户端执行一遍完成事件绑定。SSR的优劣势刚才已经提到过了不再赘述，那么看起来是不是很简单呢？那什么情况下应该使用SSR进行渲染呢？主要取决于首屏渲染速度是否真的重要SEO是否真的需要其核心的变动就是增加了一个Node层中间层作为对一些主要元素进行与渲染，因为Node服务器和后台的API服务器在内网之中，因此它们俩之间交互会非常的快，在这里直接实现API的调用很显然比客户端到服务端的代销来的小，当然也相应增加了服务端的压力。同时增加了代码的复杂性，因为写代码的时候还需要考虑哪些代码是在Node服务器就执行了，哪些会延迟到客户端执行。选型无论如何还是明确一点，SSR大部分情况下都是为了SEO做的，但是做SER不止SSR一种方式也可以用SSG，他也是一种服务端渲染技术。如果你调研 SSR 只是为了优化为数不多的营销页面的 SEO (例如 /、/about 和 /contact 等)，那么你可能需要 SSG 而不是 SSR。SSG 也非常适合构建基于内容的网站，比如文档站点或者博客。静态站点生成 (Static-Site Generation，缩写为 SSG)，也被称为预渲染，是另一种流行的构建快速网站的技术。如果用服务端渲染一个页面所需的数据对每个用户来说都是相同的，那么我们可以只渲染一次，提前在构建过程中完成，而不是每次请求进来都重新渲染页面。预渲染的页面生成后作为静态 HTML 文件被服务器托管。

AST abstract syntax Tree
type: item
date: 2023-11-22T16:34:28+08:00
description: AST abstract syntax Tree简介抽象语法树是一种用编程语言编写的源代码的抽象语法结构的树表示。树的每个节点表示源代码中出现的一个构造。AST全称为Abstract Syntax Tree，抽象语法树。AST在编译器的应用非常重要，因为抽象语法树是编译器中广泛用于表示程序代码结构的数据结构。AST通常是编译器语法分析阶段的结果。它通常过编译器所需的几个阶段作为程序的中间表示，并且对编译器的最终输出有很大影响。在进一步讨论实现部分之前，让我们先讨论一下AST的使用。AST主要用于编译器一检查代码的准确性。如果生成的语法树有错误，编译器会打印一条错误信息。使用抽象语法树（AST）是因为某些构造无法用上下文无关语法表示，列如隐式类型。它们高度特定于编程语言，但对通用语法树的研究正在进行中。在java中AST通常由一个解析器创建，该解析器读取原地阿妈并创建一个树形结构，代表代码的语法和结构。树中的每个节点都代表一个不同的语法结构，如类、方法或语句。一般来说，AST是编译器和其他需要分析和处理编程语言语法的工具的重要工具。作用AST有什么作用了？用过lombok的人一定能感觉到那种简洁舒服的代码风格，lombok的原理也就是在代码编译的时候根据相应的注解动态的去修改AST这个树，为它增加新的节点（也就是对于的代码比如get、set）。所以如果想动态的修改代码，或者直接生成java代码的话，AST是一个不错的选择。什么是AST抽象语法树我们都知道,在传统的编译语言的流程中,程序的一段源代码在执行之前会经历三个步骤,统称为"编译":分词/词法分析 这个过程会将由字符组成的字符串分解成有意义的代码块,这些代码块统称为词法单元(token).举个例子: let a = 1, 这段程序通常会被分解成为下面这些词法单元: let 、a、=、1、 ；空格是否被当成此法单元，取决于空格在这门语言中的意义。解析/语法分析 这个过程是将词法单元流转换成一个由元素嵌套所组成的代表了程序语法结构的树,这个树被称为"抽象语法树"（abstract syntax code，AST）代码生成 将AST转换成可执行代码的过程被称为代码生成.抽象语法树（abstract syntax code ，AST）是源代码的抽象语法结构的树状表示，树上的每个节点都表示源代码中的一种结构，之所以说是抽象的，抽象表示把js代码进行了结构化的转化，转化为一种数据结构。这种数据结构其实就是一个大的json对象，json我们都熟悉，他就像一颗枝繁叶茂的树。有树根，有树干，有树枝，有树叶，无论多小多大，都是一棵完整的树。简单理解,就是把我们写的代码按照一定的规则转换成一种树形结构。用途AST不仅仅是用来Js引擎的编译上，我们实际开发过程中也是经常使用的，比如我们常用的babel插件自动将ES6的语法转换成ES5、使用 UglifyJS来压缩代码 、css预处理器、开发WebPack插件、Vue-cli前端自动化工具等等，这些底层原理都是基于AST来实现的，AST能力十分强大， 能够帮助开发者理解JavaScript这门语言的精髓。结构我们先来简单看一组AST树状结构const team = '大转转FE'经过转换，输出如下AST树桩结构{ "type": "Program", "start": 0, "end": 18, "body": [ { "type": "VariableDeclaration", "start": 0, "end": 18, "declarations": [ { "type": "VariableDeclarator", "start": 6, "end": 18, "id": { "type": "Identifier", "start": 6, "end": 8, "name": "team" }, "init": { "type": "Literal", "start": 11, "end": 18, "value": "大转转FE", "raw": "'大转转FE'" } } ], "kind": "const" } ], "sourceType": "module" }我们可以看到，一个标准的AST结构可以理解为一个json对象，那我们就可以通过一些方法去解析和操作它Esprima: Parser测试网址AST编译过程词法分析var company = 'zhuanzhuan'假如有以上代码，在词法分析阶段，回显对整个代码进行扫描，生成tokens流，扫描过程如下我们会通过条件判断这个字符是字母， "/" , "数字" , 空格 , "(" , ")" , ";" 等等。如果是字母会继续往下看如果还是字母或者数字，会继续这一过程直到不是…

Vue双向数据绑定原理
type: item
date: 2023-01-20T13:41:00+08:00
description: Vue双向数据绑定原理vue2defineProperty第一个参数为需要定义属性的对象第二参数为需要定义的属性名第三个参数为属性描述符使用definePropery定义的属性不能对其进行修改，删除，以及枚举。怎么解决呢？在属性描述符中设置writable:true 可修改enumerable:true 可枚举configurable:true 可操作/删除var obj={} Object.defineProperty(obj,"name",{ value:"lisa", writable:true, enumerable:true, configurable:true })defineProperty的set和get属性用于实现数据劫持var obj={} var a=1; Object.defineProperties(obj,{ a:{ // 注意：value，writable属性与get,set互斥，如果同时存在则会报错 //所以，设置初始值只能在外部设置 //在a被访问时返回a的值 get(){ console.log("a被访问了，值为"+a) return a; }, //在a被修改时，将a的值修改为传入的新值 set(newVal){ a=newVal; console.log("a被修改了，值为"+a) } } }) obj.a //访问a,值为1 obj.a=5 //设置a的值，值为5 obj.a//再次访问a，值为5将操作的元素放入数组function DataArr(){ var Arrobj={} //数组的属性 var arr=[] //this指向new DataArr() Object.defineProperty(this,"val",{ get(){ return Arrobj; }, set(newVal){ Arrobj=newVal //向数组中添加新的属性值 arr.push({val:Arrobj}) } }) this.getArr=function(){ return arr } } var dataArr=new DataArr() dataArr.val=123 dataArr.val=456 console.log(dataArr.getArr()) //[{val:123},{val:456}] 问题关于对象： Vue 无法检测 property 的添加或移除。关于数组：不能利用索引直接设置一个数组项,也不能修改数组的长度。vue3原理：Vue3.0中的响应式采用了ES6中的 Proxy 方法。Proxy 对象用于定义基本操作的自定义行为（如属性查找、赋值、枚举、函数调用等）据阮一峰文章介绍：Proxy可以理解成，在目标对象之前架设一层 "拦截"，当外界对该对象访问的时候，都必须经过这层拦截，而Proxy就充当了这种机制，类似于代理的含义，它可以对外界访问对象之前进行过滤和改写该对象。监听数组的方法不能触发Object.defineProperty方法中的set操作(如果要监听的到话，需要重新编写数组的方法)。必须遍历每个对象的每个属性，如果对象嵌套很深的话，需要使用递归调用。const obj = new Proxy(target, handler);target: 被代理对象。handler: 是一个对象，声明了代理target的一些操作。obj: 是被代理完成之后返回的对象。但是当外界每次对obj进行操作时，就会执行handler对象上的一些方法。handler中常用的对象方法如下：1. get(target, propKey, receiver)2. set(target, propKey, value, receiver)3. has(target, propKey)4. construct(target, args):5. apply(target, object, args)const target = { name: 'kongzhi' }; const handler = { get: function(target, key) { console.log("${key} 被读取"); return target[key]; }, set: function(target, key, value) { console.log("${key} 被设置为 ${value}"); target[key] = value; } }; const testObj = new Proxy(target, handler); /* 获取testObj中name属性值 会自动执行 get函数后 打印信息：name 被读取 及输出名字 kongzhi */ conso…

牛客前端刷题记录2
type: item
date: 2023-01-19T20:05:00+08:00
description: 牛客刷题记录2Hash和History的区别Hash路由hash模式的工作原理是hash change事件，可以在windows监听hash变化。我们在url后面随便添加一个#xx触发这个事件vue-router默认的是hash模式使用URL的hash来模拟完整的一个URL，当URL改变的时候，页面不会重新加载，也就是单页应用了，当后面hash发生变化，不会导致浏览器向服务器发出请求，浏览器不发出请求，就不会刷新页面，并且会触发hashChange这个事件，通过监听hash值的变化来实现更新页面部分内容的操作。对于hash模式会创建hashhistory对象在访问不同路由的时候会发生俩件事HashHistory.push()将新的路由添加到浏览器访问的历史栈顶，和HashHistory.replce()替换到当前栈顶路由history路由通过history.push使它做页面跳转不会出发页面刷新，使用window.onpopstate监听浏览器的前进和后退，再做其他处理每当激活同一文档中不同的历史记录条目时，popstate事件就会在对应的window对象上触发。如果当前处于激活状态的历史记录条目是由history.pushState()方法创建的或是history.replaceState()方法进行修改的，则popstate事件的state属性包含了记录条目的state对象的一个拷贝调用 history.pushState() 或者 history.replaceState() 不会触发 popstate 事件。popstate 事件只会在浏览器某些行为下触发，比如点击后退按钮（或者在 JavaScript 中调用 history.back() 方法）。即，在同一文档的两个历史记录条目之间导航会触发该事件。hash模式下url会带有#，需要url更优雅时，可以使用history模式。需要兼容低版本的浏览器时，建议使用hash模式。需要添加任意类型数据到记录时，可以使用history模式。延伸前端路由的出现要从 ajax 开始，有了 Ajax 后，用户交互就不用每次都刷新页面，体验带来了极大的提升。随着技术的发展，简单的异步已经不能满足需求，所以异步的更高级体验出现了——SPA(单页应用)。 SPA 的出现大大提高了 WEB 应用的交互体验。在与用户的交互过程中，不再需要重新刷新页面，获取数据也是通过 Ajax 异步获取，页面显示变的更加流畅。 但由于 SPA 中用户的交互是通过 JS 改变 HTML 内容来实现的，页面本身的 url 并没有变化，这导致了两个问题：• SPA 无法记住用户的操作记录，无论是刷新、前进还是后退，都无法展示用户真实的期望内容。• SPA 中虽然由于业务的不同会有多种页面展示形式，但只有一个 url，对 SEO 不友好，不方便搜索引擎进行收录。前端路由就是为了解决上述问题而出现。圣杯布局和双飞翼布局神隔壁布局和双飞翼布局是一回事，它们实现的都是三栏布局，俩边的盒子宽度固定，中间盒子自适应，也就是我们常说的固比固布局。他们的实现效果是一样的双飞翼布局如果把三栏布局比作一只鸟，可以把main看成是鸟的身体，left和right则是鸟的翅膀。这个布局的思路是先把重要的身体布局放好，然后再把翅膀移动到适当的地方圣杯布局圣杯布局是俩便固定宽度，中间自适应的三栏布局中间栏放到文档流前面，先行渲染目的是为了解决三栏布局实现方式很多可以使用定位也可以使用浮动，弹性盒子实现比较简单和双飞翼布局大同小异，区别于在堆遮挡中间栏的处理方式，圣杯为父元素设置padiding，然后相对定位把左右俩部分拉会原位双飞翼则是直接对中间部分设置margin，把左右俩边拉会原位浏览器输入URL后发生了什么用户输入url会使用浏览器默认的搜索引擎加上搜索内容合成url，如果是域名会加上协议合成完整的URL（如https）合成完整的URL然后按下回车。浏览器进程通过进程间通信把url传给网络进程（网络进程接收到url才发起真正的网络请求）网络进程接受到url后，先查找有没有缓存，有缓存直接返回缓存的资源地址，没有缓存直接发起真正的网络请求首先获得域名IP地址和服务器简历TCP连接（三次握手）简历连接后，浏览器构建数据包（请求行，请求头，请求正文，并把改域名相关的cookie等数据附加到请求头）然后想服务器发送请求消息服务器接受得到请求消息后根据请求信息构建响应数据（响应行，响应头，响应正文）然后发送回网络进程网络进程接收到数据后进行解析，如果发现状态码为301,302说明服务器要进行重定向数据传输完成，tcp四次挥手断开连接。网络进程将获取到的数据包进行解析，根据响应头中的content-type来判断响应数据类型（如果是字节类型，就将请…

js牛客刷题记录
type: item
date: 2023-01-18T20:37:06+08:00
description: js牛客刷题记录1Cookie，sessionStroage，localstorage之间的区别Cookie前后端都可以写入，sessionStorage以及localStorage都是由前端写入cookie的生命周期由写入时就设置好的，localstorage是写入时就一直存在，除非手动清除，sessionStroage是由页面关闭时自动删除cookie存储空间大小约4k，sessionStroage以及localStroage空间比较大，大约5MB。前端给后端发送请求时自动携带cookie，session以及local都不携带cookie一般存储登录验证信息，localstroage常用于存储不宜变动的数据，减轻服务器压力sessionStroage可以用来检测用户是否刷新进入页面，如音乐恢复进度条功能JS基础数据类型number包括整数和浮点数JS进行浮点元素运算可能得到一个不精确的值0.1+0.2=0.300000004，不能进行精确度要求比较高的运算；NAN表示not A Number 检查时返回number数值number类型，用来表示任何类型的数字：整数或者浮点数都可以；实际上，JS中的数值，是一个64位的浮点数，这与Java中的double类型的浮点数是一致的；但是它有表示的范围，在范围内，JS可以准确表示，超出范围，JS不会报错，但是数值不准：整数范围：±253-1，闭区间，即±9007,1992,5474,0992，那么超出16位的整数，必然表示不准；浮点数范围：±1.7976,9313,4862,3157308，JS有内置常量用于表示这个数值，即Number.MAX_VALUE；能表示的最小的小数：5-324，JS有内置常量用于表示这个数值，即Number.MIN_VALUE;位运算范围：JS只支持32位整数，即[-231, 231-1]；String类型String类型（字符串）是由 Unicode 字符、数字、标点符号等组成的序列，在 JavaScript 代码中用于表示 JavaScript 文本的数据类型，字符串型数据通常由单引号或双引号包裹，由双引号定界的字符串中可以再包含有单引号，单引号定界的字符串中也可以再包含有双引号。在js中字符串需要使用引号引起来，单引号和双引号不能混用；引号不能嵌套，可以使用进行转义。Boolean与数字类型的值不同，Boolean类型（布尔型）变量的值只有固定的两种表示方式，一种是 true，另一种是 false，前者表示真，后者表示假，如果用数字表示，那么，true 可以使用 1 来表示，false 可以使用 0 来表示，布尔型变量的值来源于逻辑性运算符，常用于控制结构流程。布尔值只有两个true/false，主要做逻辑判断；使用typeof检查一个布尔值时返回boolean。Null类型在 JavaScript 代码中，Null类型（空值型）是一个比较特殊的类型，它只有一个值，就是 null，当引用一个未定义的对象时，则将返回一个这个 null 值， 从严格意义上来说，null 值本质上是一个对象类型，是一个空指针的对象类型。Null（空值）类型的值只有一个，null，用来表示一个为空的对象；使用typeof检查时值时返回object，因为null表示空对象NaN、infanity、undefined。Undefined类型与 Null 型相同，Undefined 型（未定义）也是只有一个 undefined 值，当在编写 JavaScript 代码时，如果定义了一个变量，但没有给它赋值，那么，这个变量将返回 undefined 值，这也是变量默认的值，与 Null 型不同之处在于，Null 型是一个空值，而 Undefined 型表示无值。js中输出未被赋值的被定义变量结果是Undefined；Undefined类型的值只有一个。使用typeof检查时值时返回undifineBitIntBigInt 类型是 JavaScript 中的一个基础的数值类型，可以表示任意精度的整数。使用 BigInt，您可以安全地存储和操作大整数，甚至可以超过数字类型的安全整数限制。BigInt 是通过在整数末尾附加字母 n 或调用构造函数来创建的。通过使用常量 Number.MAX_SAFE_INTEGER，您可以获得可以用数字递增的最安全的值。通过引入 BigInt，您可以操作超过 Number.MAX_SAFE_INTEGER 的数字。StringJavaScript 的字符串类型用于表示文本数据。它是一组 16 位的无符号整数值的“元素”。在字符串中的每个元素占据了字符串的位置。第一个元素的索引为 0，下一个是索引 1，依此类推。字符串的长度是它的元素的数量。不同于一些编程…

Webpack和Vite
type: item
date: 2022-09-16T14:33:07+08:00
description: Webpack和ViteWebpack和vite都是现代化打包工具为什么vite快vite是基于esbuild预构建依赖,而esbuild是go语言编写,因为go语言的效率更高,所以vite比用js编写的打包器快10倍webpack原理vite原理图webpack过程分析依赖=>编译打包=>交给本地服务器进行渲染.首先分析各个模块之间的依赖,然后进行打包,在启动webpack-dev-server请求时,直接显式打包结果.webpack打包之后存在的问题随着模块的增多，会造成打出的 bundle 体积过大，进而会造成热更新速度明显拖慢。vite启动服务器=>请求模块时按需动态编译显示,是先启动开发服务器,请求某个模块时,再对该模块进行实时编译,因为现代浏览器本身支持es-Module,所以会自动向依赖的Module发出请求.所以vite就将环境下的模块文件作为浏览器执行文件,而不是像webpack进行打包后交给本地服务器为什么快分析了webpack和vite的打包方式后,就明白了了vite为什么比webpack打包快,因为在确定时候不需要打包,所以不用分析与模块之间的依赖关系,不用进行编译,这种方式就类似于我们在请求某个ui框架的时候,可以对其进行按需加载,当浏览器请求某个模块时,在根据需要对模块的内容进行编译.按需动态编译可缩短编译时间,当项目越复杂,模块越多的情况下,vite明显优于webpakc热更新方面,效率更高,当改动了某个模块时,也只用让浏览器重新请求该模块,不需要像webpack那样将模块依赖的模块全部编译一次

node更换版本（简单操作）
type: item
date: 2022-07-27T13:56:38+08:00
description: 1.安装nvmhttps://github.com/coreybutler/nvm-windows/releases下载exe程序即可管理员权限打开cmdnvm ls 命令查看本地已有版本 nvm ls // 查看已安装node版本 nvm install vXX // 安装对应vXX版本的node nvm uninstall vXX // 卸载对应vXX版本的node nvm use xxx // 选择使用XXX版本

vue3新特性
type: item
date: 2021-07-28T14:10:00+08:00
description: 性能双向响应原理由Object.defindProperty改为基于ES6的proxy使其粒度更大,速度更快,且消除了之前存在的警告重写了Vdom,突破了Vdom的性能瓶颈进行了模板编译的优化进行了更加高效的组件初始化tree-shaking的支持支持了tree-shaking(剪枝):像修建输液一样把不需要的东西给修剪掉,使vue3的体积更小需要的模块才会打入到包里,优化后的Vue3.0的打包体积只有原来的一半.像keep-alive,transition甚至v-for等功能都可以按需引入Composition APIcomposition-api是一个vue3中新增的功能,是比mixin更强大的存在composition-api可以提高代码逻辑的可复用性,从而实现与模板的无关性;同时使代码的可压缩性更强,另外把Reactivity模块独立开来,意味着vue3.0的响应式模块可以与其他框架相组合Fragments不再限制teplate只有一个根节点render函数也可以返回数组了Better TypeScript Support更好的类型推导,使得Vue3吧TypeScript支持的更好Custom Renderer API实现用DOM的方式进行WebGL编程