diff --git "a/docs/\351\235\242\350\257\225\345\244\215\347\233\230/2024\345\271\2644\346\234\2101\345\217\267.md" "b/docs/\351\235\242\350\257\225\345\244\215\347\233\230/2024\345\271\2644\346\234\2101\345\217\267.md" index 067d2170..7ed76cb8 100644 --- "a/docs/\351\235\242\350\257\225\345\244\215\347\233\230/2024\345\271\2644\346\234\2101\345\217\267.md" +++ "b/docs/\351\235\242\350\257\225\345\244\215\347\233\230/2024\345\271\2644\346\234\2101\345\217\267.md" @@ -44,6 +44,19 @@ ## 5. get 和 post 的区别 +### 协议层面 + +语义上的区别 + +get 从服务器上获取数据 +post 向服务器传递数据 + +### 应用层面 + +GET 的请求体为空,即请求体是空字符串(没有请求体是违反 http 协议的,所以 get 的请求体是空字符串,而不是没有) + +### 浏览器层面 + - get 在浏览器回退时是无害的,而 post 会再次发送请求,get 请求可以直接在浏览器中访问,支持刷新和后退,而 post 不能直接在浏览器访问,刷新后数据要重新发送。 - get 产生的 url 地址可以被标记(Bookmark),而 post 不可以 @@ -376,5 +389,5 @@ const onChange = (e) => { setValue(e.target.value); }; - +; ``` \ No newline at end of file diff --git "a/docs/\351\235\242\350\257\225\345\244\215\347\233\230/\347\254\254\344\270\200\347\211\210\351\235\242\350\257\225\351\242\230.md" "b/docs/\351\235\242\350\257\225\345\244\215\347\233\230/\347\254\254\344\270\200\347\211\210\351\235\242\350\257\225\351\242\230.md" index 1b0b5673..d872d7ca 100644 --- "a/docs/\351\235\242\350\257\225\345\244\215\347\233\230/\347\254\254\344\270\200\347\211\210\351\235\242\350\257\225\351\242\230.md" +++ "b/docs/\351\235\242\350\257\225\345\244\215\347\233\230/\347\254\254\344\270\200\347\211\210\351\235\242\350\257\225\351\242\230.md" @@ -2,21 +2,21 @@ 1. typeof - 对象({})、数组([])、null 的结果都是 object + 对象({})、数组([])、null 的结果都是 object - 新数据类型如Symbol、BigInt,无法识别 + 新数据类型如 Symbol、BigInt,无法识别 2. instanceof - 无法判断基本数据类型和null + 无法判断基本数据类型和 null 3. Object.prototype.toString.call() - 语法相对复杂,但是可以区分数组、函数等引用数据类型 + 语法相对复杂,但是可以区分数组、函数等引用数据类型 4. Array.isArray() - 只能判断数组类型,精准判断数组 + 只能判断数组类型,精准判断数组 typeof 和 instanceof 的区别: @@ -26,8 +26,6 @@ typeof 和 instanceof 的区别: 精确性:typeof 对基本数据类型判断比较精确,对于引用类型则无法进一步区分。instanceof 可以准确的判断引用类型。 - - # 防抖和节流 ## 防抖 @@ -38,14 +36,14 @@ typeof 和 instanceof 的区别: ```js const debounce = (fn, delay) => { - let timer = null; - return (...args) => { - clearTimeout(timer); - timer = setTimeout(()=>{ - fn(args); - }, delay) - } -} + let timer = null; + return (...args) => { + clearTimeout(timer); + timer = setTimeout(() => { + fn(args); + }, delay); + }; +}; ``` ## 节流 @@ -56,16 +54,16 @@ const debounce = (fn, delay) => { ```js const trottle = (fn, delay) => { - let timer = null; - return function (...args) { - if(timer) return; - timer = setTimeout(() => { - fn(args); - clearTimeout(timer); - timer = null; - }, delay) - } -} + let timer = null; + return function (...args) { + if (timer) return; + timer = setTimeout(() => { + fn(args); + clearTimeout(timer); + timer = null; + }, delay); + }; +}; ``` ![image-20240312192537719](/Users/fiat_lux/Library/Application Support/typora-user-images/image-20240312192537719.png) @@ -84,17 +82,19 @@ const trottle = (fn, delay) => { 如果对象中包含循环引用,会抛出错误; -对于包含Symbol、RegExp等特殊类型的对象,可能无法正确工作 +对于包含 Symbol、RegExp 等特殊类型的对象,可能无法正确工作 ```js const obj = { - [Symbol.for('key1')]: 'a', - b: undefined, - c: NaN, - d: () => { return null }, - e: Infinity, - f: null -} + [Symbol.for('key1')]: 'a', + b: undefined, + c: NaN, + d: () => { + return null; + }, + e: Infinity, + f: null, +}; console.log(JSON.parse(JSON.stringify(obj))); // {c: null, e: null, f: null} ``` @@ -103,7 +103,7 @@ console.log(JSON.parse(JSON.stringify(obj))); // {c: null, e: null, f: null} ## 使用 js 工具库 lodash ```js -const obj = {a: 1, b: 2, c: 3}; +const obj = { a: 1, b: 2, c: 3 }; const newObj = _.cloneDeep(obj); ``` @@ -111,29 +111,27 @@ const newObj = _.cloneDeep(obj); ```js function deepClone(obj) { - // 先判断 obj 的数据类型 - if(obj === null) return obj; // obj 为 null - if(obj instanceof Date) return new Date(obj); // obj 为 Date - if(obj instanceof RegExp) return new RegExp(obj); // obj 为 RegExp - if(typeof obj !== 'object') return obj; - let cloneObj = new obj.constructor(); - for(let key in obj) { - if(obj.hasOwnProperty(key)) { - // 实现一个递归拷贝 - cloneObj[key] = deepClone(obj[key]); + // 先判断 obj 的数据类型 + if (obj === null) return obj; // obj 为 null + if (obj instanceof Date) return new Date(obj); // obj 为 Date + if (obj instanceof RegExp) return new RegExp(obj); // obj 为 RegExp + if (typeof obj !== 'object') return obj; + let cloneObj = new obj.constructor(); + for (let key in obj) { + if (obj.hasOwnProperty(key)) { + // 实现一个递归拷贝 + cloneObj[key] = deepClone(obj[key]); + } } - } - return cloneObj; + return cloneObj; } ``` - - 扩展: JSON.stringify(value, replacer, space) -参数一:value 表示要被序列化的对象,接受对象或数组类型 +参数一:value 表示要被序列化的对象,接受对象或数组类型 参数二:replacer 用于标记需要序列化的属性,接受数组和函数类型 @@ -143,10 +141,10 @@ JSON.stringify(value, replacer, space) 1. localStorage 的存储 -​ localStorage 只能存储字符串类型,kv(key,value) 结构 +​ localStorage 只能存储字符串类型,kv(key,value) 结构 ```js -const obj = {a: 1, b: 2, c: 3}; +const obj = { a: 1, b: 2, c: 3 }; // 序列化要存储的数据: JSON.stringify(obj) // 存储 localStorage.setItem('obj', JSON.stringify(obj)); @@ -158,77 +156,59 @@ localStorage.removeItem('obj'); 2. 对象的深拷贝 - ```js - const obj = {a: 1, b: 2, c: 3}; - const objA = obj; - const objB = JSON.parse(JSON.stringify(obj)); - // 修改 - objA.a = 11; - console.log(obj); // {a: 11, b: 2, c: 3} - console.log(objA); // {a: 11, b: 2, c: 3} - - objB.a = 123; - console.log(obj); // {a: 11, b: 2, c: 3} - console.log(objB); // {a: 123, b: 2, c: 3} - ``` - -3. 删除对象属性 - - ```js - const obj = {a: 1, b: 2, c: 3}; - const str = JSON.stringify(obj, (key, value) =>{ - if(key === 'b') { - return undefined; - } - return value; - }); - console.log(str); // '{"a":1,"c":3}' - const objA = JSON.parse(str); - console.log(objA); // {a: 1, c: 3} - ``` - - - + ```js + const obj = { a: 1, b: 2, c: 3 }; + const objA = obj; + const objB = JSON.parse(JSON.stringify(obj)); + // 修改 + objA.a = 11; + console.log(obj); // {a: 11, b: 2, c: 3} + console.log(objA); // {a: 11, b: 2, c: 3} + objB.a = 123; + console.log(obj); // {a: 11, b: 2, c: 3} + console.log(objB); // {a: 123, b: 2, c: 3} + ``` +3. 删除对象属性 + ```js + const obj = { a: 1, b: 2, c: 3 }; + const str = JSON.stringify(obj, (key, value) => { + if (key === 'b') { + return undefined; + } + return value; + }); + console.log(str); // '{"a":1,"c":3}' + const objA = JSON.parse(str); + console.log(objA); // {a: 1, c: 3} + ``` # 前端跨域 跨域是前端解决的范畴 - - 什么时候会发生跨域 跨域是由于浏览器的同源策略(协议、域名、)所导致的,是发生在 页面 到 服务端 请求的过程中 - - 项目中怎么解决这个跨域问题的 1. Nginx 反向代理 2. 搭建 BFF 层 - - - - 了解后端处理跨域的原理吗 -可以使用nginx,但是我们项目后端是在微服务中处理跨域 - - +可以使用 nginx,但是我们项目后端是在微服务中处理跨域 cookie 和 localStorage 的区别 - - -项目中的登录是用的cookie还是localStorage来保存token的? +项目中的登录是用的 cookie 还是 localStorage 来保存 token 的? cookie -用户在浏览器这边进行登录接口请求,服务端收到这个请求之后,在用户名和密码都正确的情况下,服务器在向浏览器返回登录结果的时候,会生成一个cookie,并且在 Http Response Header 中 Set-Cookie。这样,当浏览器再次请求服务端时,都会同步的带上 cookie,cookie 会附带在每个 Http 请求上。 +用户在浏览器这边进行登录接口请求,服务端收到这个请求之后,在用户名和密码都正确的情况下,服务器在向浏览器返回登录结果的时候,会生成一个 cookie,并且在 Http Response Header 中 Set-Cookie。这样,当浏览器再次请求服务端时,都会同步的带上 cookie,cookie 会附带在每个 Http 请求上。 生成机制 @@ -236,34 +216,41 @@ cookie 2. 客户端生成,通过 document.cookie 设置 - - Cookie 设置初衷是用于**维持 HTTP 状态**,不用于**存储数据**。因此 cookie 有以下缺点: 1. 大小限制:每个 cookie 项只能存储 **4K** 数据 2. 性能浪费: cookie 附带在 http 请求上,数据量过大,会导致每个 http 请求就非常庞大,会很消耗流量和带宽。 - - 前端和后端是同一个域名吗? 那肯定不是同一个 接口请求也是不一样的,所以跨域了 +react +常用的一些 hooks +useEffect 和 useLayoutEffect 的区别?谁先执行?谁后执行? +react 使用 虚拟 dom 的好处?为什么会提高性能? -react +直接操作 dom 性能是最高的。 -常用的一些hooks +react diff 的原理 -useEffect 和 useLayoutEffect 的区别?谁先执行?谁后执行? +## Promise 解决了什么问题 -react 使用 虚拟 dom 的好处?为什么会提高性能? +Promise 的出现最重要的是为了统一 JS 中的异步实现方案 -直接操作dom性能是最高的。 +异步是 JS 中的常见场景,统一实现方案,不仅可以有效降低心智负担,更重要的是可以让不同的异步场景相互联动 -react diff 的原理 +Promise 也无法消除回调地狱,它只不过通过链式调用的方式让回调变得可控 + +## 什么是 Vue 的响应式 + +vue 数据响应式设计的初衷是为了实现数据和函数的联动,当数据变化时,用到该数据的联动函数会自动重新运行 + +具体在 vue 的开发中,数据和组件的 render 函数关联在一起,从而实现了数据变化自动运行 render,在感官上就看到了组件的重新渲染。 +除了 vue 自动关联的 render 函数,其他还有很多使用到 vue 响应式的场景,比如 computed、watch 等等,不能仅把 vue 的数据响应式想象成和 render 的关联