5mm耳机插入后电脑不识别
硬盘被写保护去除方法
以管理员身份运行命令提示符(Win+R)
输入命令 diskpart
进入 diskpart 的界面
输入命令 list disk 回车
选择想去除保护的磁盘
输入命令 select disk 2 回车 磁盘 2 是我想清除属性的盘,你可以选择你想清除的。
输入命令 attribute disk clear readonly 回车
输入命令 attribute disk 回车 查看
若有收获,就点个赞吧
JavaScript 常用正则
匹配手机号
^1[345678]\d{9}$
匹配 QQ 号
^[1-9][0-9]{4,9}$
匹配 16 进制
#?([0-9a-zA-Z]{6}|[0-9a-zA-Z]{3})
匹配邮箱
^([0-9a-zA-Z_\.\-]+)@([0-9a-zA-Z_\.\-]+)\.([A-Za-z]{2,6})$
匹配 URL
^((https?|ftp|file):\/\/)?([\da-z\.\-]+)\.([a-z\.]{2,6})([\/w\.\-]*)*\/?$
匹配 HTML
^<([a-z]+)([^>]+)*(?:>(.*)<\/\1>|\s+\/>)$
匹配 IP
^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$
匹配日期
^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$
车牌
/^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-Z0-9]{4}[A-Z0-9挂学警港澳]{1}$/
身份证
^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$
前端性能优化
内容方面
- 减少 HTTP 请求:雪碧图、合并文件
- 减少 DNS 查询:DNS 缓存、将资源分布到恰当数量的主机名,平衡并行下载和 DNS 查询
- 避免重定向:多余的中间访问
- 组件加载:非必须组件延迟加载,未来所需组件预加载
- DOM 元素:减少 DOM 元素数量、或者是减少 DOM 元素嵌套的深度
- 将资源放到不同的域下:浏览器同时从一个域下载资源的数目有限,增加域可以提高并行下载量。这个限制的目的是防止网站占用大量网络带宽导致其他网站网络质量变差。大多数浏览器都有默认的并行请求数限制,通常是在 6 到 8 之间。
- 减少 iframe 数量:iframe 会阻塞主页面的 Onload 事件及 iframe 和主页面共享连接池,会影响页面的并行加载。并且 iframe 加载速度慢同时也不利于 SEO。
服务器方面
CDN
:常用的包用CDN
代替,https://www.bootcdn.cn/- 添加
Expires
或者Cache-Control
响应头来设置缓存,尽可能的使用本地缓存,减少服务器压力,增强用户体验 - 使用
Gzip
压缩:注意!!! 图片和PDF
文件不要使用gzip
。它们本身已经压缩过,再使用gzip
压缩不仅浪费CPU
资源,而且还可能增加文件体积。 - 配置
ETag
:Etag
通过文件版本标识,方便服务器判断请求的内容是否有更新,如果没有就响应304
命中本地缓存,避免重新下载。 - 避免空
src
的img
标签:src
属性为空时,浏览器在渲染的过程中仍会将href
属性或src
属性中的空内容进行加载,直至加载失败,这样就阻塞了页面中其他资源的下载进程,而且最终加载到的内容是无效的,因此要尽量避免。可以使用一个Base64
的图片来作为骨架屏。
CSS 方面
- 将样式表放到页面顶部
- 减少
CSS
类名的嵌套深度 - 不使用
CSS
表达式:在前端这块避免使用CSS
表达式,因为它的重绘次数非常多,相当的影响性能。但是calc
方法不会有性能问题 - 如果你使用的是
Sass/Scss/Less
要尽可能合并相同的样式规则 - 使用
CSS
压缩工具压缩CSS
文件 - 异步加载样式表,避免阻塞页面渲染。
<link rel="preload" href="style.css" as="style">
Javascript 方面
- 将脚本放到页面底部,不影响
DOM
的渲染 - 压缩
JavaScript
和CSS
- 删除不需要的脚本
- 尽可能的用类名操作样式,而不是直接操作
DOM
样式 - 合理
setTimeout
、setInterval
,使用时候用变量接收移除并赋值为null
- 使用
documentFragment
来减少DOM
操作的次数 - 全局变量的访问会比局部变量慢,因此应该尽可能地使用局部变量
- 如果数组过大,尽量减少数组的操作,例如使用
forEach
方法取代for
循环。 - 遇到
CPU
密集型的场景可以使用Web Workers
Vue 方面
- 尽可能的使用
v-show
,减少DOM
操作 - 多使用计算属性,因为它会缓存值
v-for
的时候必须添加Key
,没有Key
就用nanoId
- 禁止
v-for
和v-if
连用,当它们处于同一节点,v-for
的优先级比**v-if
更高**,这意味着v-if
将分别重复运行于每个v-for
循环中 - 图片懒加载
- vue-router 使用懒加载
- 按需引入不同的包,这很重要,大多时候包体积过大都是没有按需引入
- 服务端渲染提升首屏用户体验
- 使用 mixin 提取公共逻辑
- 长列表性能优化:只用于展示的可以
freeze
对象
export default {
data: () => ({
users: {}
}),
async created() {
const users = await axios.get("/api/users");
this.users = Object.freeze(users);
}
};
Webpack 方面
- 可以用
image-webpack-loader
来压缩图片 - 提取公共代码
- 使用
SourceMap
解决构建后的项目无法精准定位错误的问题 - 构建结果输出分析使用
webpack-bundle-analyzer
- 使用
Tree Shaking
剔除JS
死代码,它正常工作的前提是代码必须采用ES6
的模块化语法
其他方面
Chrome Performance
:使用Chrome
开发者工具分析页面性能- 让用户使用
Chrome
- 使用
Git
管理代码,而不是使用SVN
- 团队代码尽可能使用
ESlint
保证编码风格
实现nextTick
为什么会有$nextTick
因为Vue
是异步更新DOM
的,数据改变就会开启异步更新队列,等待队列中所有数据变化完成后再统一更新,这样做可以减少不必要的DOM
操作。
如何实现一个$nextTick
Vue 的 $nextTick
,用于在下次 DOM 更新循环结束之后执行延迟回调。它的实现主要是利用了 JavaScript 引擎的微任务机制,通过在当前任务结束后,把回调函数加入到微任务队列,实现了下次 DOM 更新循环结束之后再执行回调函数的效果。
Vue.prototype.$nextTick = function (fn) {
// 将回调函数加入到 Promise 队列
Promise.resolve().then(fn);
};
该代码的实现原理是:在 JavaScript 中,Promise 是一个微任务,当当前任务结束后,它会被添加到微任务队列,并在下一轮微任务中执行。因此,通过在 $nextTick 函数中调用 Promise.resolve().then(fn),可以实现在下一次微任务中执行 fn 回调函数的效果。
HTTPHTTPS的区别
HTTP/HTTPS 的主要区别
HTTP 是一种无状态的协议,它不提供任何对数据的加密或安全保护。因此,任何人都可以在传输过程中查看或修改数据。
HTTPS 是在 HTTP 基础上增加了 SSL/TLS 加密协议的安全版本。它通过在客户端和服务器之间建立加密连接来保护数据的隐私和完整性。因此,当您使用 HTTPS 访问 Web 页面时,您可以确保您的数据不会被第三方窃取或篡改。
HTTP | HTTPS | |
---|---|---|
是否为加密传输 | 明文传输 | 混合加密传输 |
如何建立连接 | TCP/IP 三次握手 | TCP 三次握手 + SSL/TLS 握手 |
默认端口 | 80 | 443 |
证书 | 没有 | 服务端 CA 数字证书 |
HTTPS 工作原理
- TCP 协议三次握手,建立 TCP 连接
- 服务利用 TCP 将证书发送给浏览器
- 浏览器通过本地 Root CA 验证网站证书
- 浏览器用证书的公钥加密:协商对称加密的算法和密码
- 服务器相应,确定对称加密算法和密码
- 会话建立,来往数据使用对称加密
SSL/TLS
SSL (Secure Sockets Layer) 和 TLS (Transport Layer Security) 是加密协议,用于在两个通信节点之间提供安全连接。它们是为了保护数据在网络上传输过程中不被窃取或篡改而设计的。
SSL 和 TLS 是两种相似的协议,不同点在于 TLS 是 SSL 的替代品。
TLS 引入了一些改进,例如更强的加密算法和更好的认证方式。
因此,现在已经不再使用 SSL,而是使用 TLS。
SSL/TLS 原理
- 建立连接:客户端与服务端建立连接,进行 SSL/TLS 协议的握手(Handshake)。
- 证书验证:服务器发送公钥证书给客户端,客户端验证证书的有效性,包括证书颁发机构是否可信任,证书内容是否匹配网站信息等。
- 密钥交换:使用预定义的密钥交换算法,如 Diffie-Hellman,生成公共密钥,并使用该密钥加密下一步通信。
- 加密通信:使用公共密钥加密数据,并通过网络发送。
- 解密接收:服务器接收到加密数据,使用公共密钥进行解密。
- 结束连接:客户端与服务端完成通信后进行四次握手,结束连接。
整个过程中使用的证书都是由第三方机构颁发的,确保了数据安全和双方身份的正确性。
数据传输过程
为什么是三次握手四次挥手
三次握手
因为二者都处于在一个初始状态,都是是为了建立连接,所以 ACK 响应这个步骤就可以是一步。
## 四次挥手
可能服务端给客户端发送的请求还没收回来,或者是客户端发送的请求服务端还没有响应,所以在挥手的时候,服务端自己要准备一段时间,中间这两步是没有办法合二为一的,所以必须是四次。
正向代理和反向代理的区别
前端常见算法题
数组去重
let arr = [1, 2, 3, 4, 5, 3, 2];
// 方法1:使用 Set 去重
let set = new Set(arr);
let uniqueArr = Array.from(set);
// 方法2:使用 filter 过滤重复元素
let uniqueArr = arr.filter((item, index) => arr.indexOf(item) === index);
// 方法3:使用 for 循环去重
let uniqueArr = [];
for (let i = 0; i < arr.length; i++) {
if (uniqueArr.indexOf(arr[i]) === -1) {
uniqueArr.push(arr[i]);
}
}
排序算法
let arr = [3, 1, 5, 4, 2];
// 方法1:使用 sort 排序
arr.sort((a, b) => a - b);
// 方法2:使用 for 循环排序
for (let i = 0; i < arr.length - 1; i++) {
for (let j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
let temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
二分查找
let str = 'hello world';
// 方法1:使用 split、reverse、join 实现
let reverseStr = str.split('').reverse().join('');
// 方法2:使用 for 循环实现
let reverseStr = '';
for (let i = str.length - 1; i >= 0; i--) {
reverseStr += str[i];
}
快排
let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
// 二分查找
function binarySearch(arr, target) {
let low = 0, high = arr.length - 1;
while (low <= high) {
let mid = Math.floor((low + high) / 2);
if (arr[mid] === target) {
return mid;
} else if (arr[mid] < target) {
low = mid + 1;
} else {
high = mid - 1;
}
}
斐波那契数列
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
简单的模板引擎实现
let template = `
<ul>
<% for(let i=0; i < data.length; i++) { %>
<li><%= data[i] %></li>
<% } %>
</ul>
`;
let render = (template, data) => {
let evalExpr = /<%=(.+?)%>/g;
let expr = /<%([\s\S]+?)%>/g;
template = template
.replace(evalExpr, (match, code) => `' + ${code} + '`)
.replace(expr, (match, code) => `'; ${code}; html += '`);
let html = `let html = '${template}'; return html;`;
return new Function('data', html)(data);
};
let data = [1, 2, 3, 4, 5];
let html = render(template, data);
console.log(html);
冒泡排序
function bubbleSort(arr) {
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
let temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
return arr;
}
let arr = [5, 4, 3, 2, 1];
console.log(bubbleSort(arr));
深拷贝的实现
- JSON.parse(JSON.stringify(obj)):可以实现简单的对象的深拷贝,但是不支持函数、正则表达式、undefined、循环引用等特殊情况。
- 递归:通过递归的方式对对象进行拷贝,可以实现更为灵活的深拷贝,支持特殊情况。
function deepClone(obj) {
let result = Array.isArray(obj) ? [] : {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
if (typeof obj[key] === 'object') {
result[key] = deepClone(obj[key]);
} else {
result[key] = obj[key];
}
}
}
return result;
}
数组中的最大/小值
let arr = [1, 2, 3, 4, 5];
let max = arr.reduce((a, b) => Math.max(a, b));
let min = arr.reduce((a, b) => Math.min(a, b));
console.log(max, min);
字符串的回文判断
function isPalindrome(str) {
return str === str.split('').reverse().join('');
}
function isPalindrome(str) {
let len = str.length;
for (let i = 0; i < len / 2; i++) {
if (str.charAt(i) !== str.charAt(len - 1 - i)) {
return false;
}
}
return true;
}
function isPalindrome(str) {
return str === str.split(/[\W_]/g).reverse().join('');
}
搜索算法,例如 BFS 和 DFS
const bfs = (root, target) => {
const queue = [root];
while (queue.length) {
const node = queue.shift();
if (node.value === target) return node;
node.children.forEach(child => queue.push(child));
}
return null;
};
const dfs = (node, target) => {
if (node.value === target) return node;
for (const child of node.children) {
const result = dfs(child, target);
if (result) return result;
}
return null;
};
动态规划,例如计算背包问题
动态规划 (Dynamic Programming) 是一种用于解决最优化问题的算法。在背包问题中,我们需要选择物品,以便在不超过背包容量的情况下获得最大价值。
function knapsack(capacity, weights, values, n) {
let i, w;
let K = [];
for (i = 0; i <= n; i++) {
K[i] = [];
}
for (i = 0; i <= n; i++) {
for (w = 0; w <= capacity; w++) {
if (i === 0 || w === 0) {
K[i][w] = 0;
} else if (weights[i - 1] <= w) {
K[i][w] = Math.max(
values[i - 1] + K[i - 1][w - weights[i - 1]],
K[i - 1][w]
);
} else {
K[i][w] = K[i - 1][w];
}
}
}
return K[n][capacity];
}
let values = [3, 4, 5];
let weights = [2, 3, 4];
let capacity = 5;
let n = values.length;
console.log(knapsack(capacity, weights, values, n));
在这段代码中,我们创建了一个二维数组 K
,用于记录所有的子问题的解。对于每一个物品,我们考虑是否将其放入背包中,以获得最大价值。最终,我们可以在 K[n][capacity]
中找到最终的答案。