跳到主要内容

5mm耳机插入后电脑不识别

· 阅读需 1 分钟
素明诚
Full stack development

问题

  1. Realtek 高清晰音頻管理器在设置的时候,找不到耳机应该有的选项
  2. 使用了 Windows10 家庭版的系统
  3. 装过奇怪的声卡软件

解决方法

下载

https://downloadcenter.intel.com/zh-tw/download/29284/-Windows-Realtek-High-Definition-Audio-10-64-Intel-NUC9VXQNX-NUC9V7QNX-NUC9i9QNX-NUC9i7QNX-NUC9i5QNX-## 问题总结

只要不是你耳机的问题,插入后有反应,那就说明是驱动或者是软件的问题。当你重装驱动还有问题,那么你可以下载。

Realtek高清晰音頻管理器,安装、重启、插入耳机。复活!

硬盘被写保护去除方法

· 阅读需 1 分钟
素明诚
Full stack development

以管理员身份运行命令提示符(Win+R)
输入命令 diskpart

ac8cf4f43d23deb3ca13feee79d8d4c5

进入 diskpart 的界面

输入命令 list disk 回车

6d1be1bd4b9799e56998a4239db9a4b2

选择想去除保护的磁盘

输入命令 select disk 2 回车 磁盘 2 是我想清除属性的盘,你可以选择你想清除的。

b6ffde537c4db7fba628a27a434b7cdc

输入命令 attribute disk clear readonly 回车

f83aa4b0abc59a80d1ae2da400e8b261

输入命令 attribute disk 回车 查看

3985a37d8156a85a0ff3e1e647791681

若有收获,就点个赞吧

JavaScript 常用正则

· 阅读需 1 分钟
素明诚
Full stack development

匹配手机号

^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]$

前端性能优化

· 阅读需 4 分钟
素明诚
Full stack development

内容方面

  1. 减少 HTTP 请求:雪碧图、合并文件
  2. 减少 DNS 查询:DNS 缓存、将资源分布到恰当数量的主机名,平衡并行下载和 DNS 查询
  3. 避免重定向:多余的中间访问
  4. 组件加载:非必须组件延迟加载,未来所需组件预加载
  5. DOM 元素:减少 DOM 元素数量、或者是减少 DOM 元素嵌套的深度
  6. 将资源放到不同的域下:浏览器同时从一个域下载资源的数目有限,增加域可以提高并行下载量。这个限制的目的是防止网站占用大量网络带宽导致其他网站网络质量变差。大多数浏览器都有默认的并行请求数限制,通常是在 6 到 8 之间。
  7. 减少 iframe 数量:iframe 会阻塞主页面的 Onload 事件及 iframe 和主页面共享连接池,会影响页面的并行加载。并且 iframe 加载速度慢同时也不利于 SEO。

服务器方面

  1. CDN:常用的包用CDN 代替,https://www.bootcdn.cn/
  2. 添加Expires或者Cache-Control响应头来设置缓存,尽可能的使用本地缓存,减少服务器压力,增强用户体验
  3. 使用Gzip压缩:注意!!! 图片和PDF文件不要使用gzip。它们本身已经压缩过,再使用gzip压缩不仅浪费 CPU资源,而且还可能增加文件体积。
  4. 配置ETagEtag通过文件版本标识,方便服务器判断请求的内容是否有更新,如果没有就响应304命中本地缓存,避免重新下载。
  5. 避免空srcimg标签:src属性为空时,浏览器在渲染的过程中仍会将href属性或src属性中的空内容进行加载,直至加载失败,这样就阻塞了页面中其他资源的下载进程,而且最终加载到的内容是无效的,因此要尽量避免。可以使用一个Base64的图片来作为骨架屏。

CSS 方面

  1. 将样式表放到页面顶部
  2. 减少CSS类名的嵌套深度
  3. 不使用CSS表达式:在前端这块避免使用CSS表达式,因为它的重绘次数非常多,相当的影响性能。但是calc方法不会有性能问题
  4. 如果你使用的是Sass/Scss/Less 要尽可能合并相同的样式规则
  5. 使用 CSS 压缩工具压缩 CSS 文件
  6. 异步加载样式表,避免阻塞页面渲染。
<link rel="preload" href="style.css" as="style">

Javascript 方面

  1. 将脚本放到页面底部,不影响DOM的渲染
  2. 压缩JavaScriptCSS
  3. 删除不需要的脚本
  4. 尽可能的用类名操作样式,而不是直接操作DOM样式
  5. 合理setTimeoutsetInterval,使用时候用变量接收移除并赋值为null
  6. 使用documentFragment来减少 DOM操作的次数
  7. 全局变量的访问会比局部变量慢,因此应该尽可能地使用局部变量
  8. 如果数组过大,尽量减少数组的操作,例如使用 forEach方法取代 for 循环。
  9. 遇到CPU密集型的场景可以使用Web Workers

Vue 方面

  1. 尽可能的使用v-show,减少DOM操作
  2. 多使用计算属性,因为它会缓存值
  3. v-for的时候必须添加Key ,没有Key就用nanoId
  4. 禁止v-forv-if连用,当它们处于同一节点,v-for 的优先级比**v-if 更高**,这意味着 v-if 将分别重复运行于每个 v-for 循环中
  5. 图片懒加载
  6. vue-router 使用懒加载
  7. 按需引入不同的包,这很重要,大多时候包体积过大都是没有按需引入
  8. 服务端渲染提升首屏用户体验
  9. 使用 mixin 提取公共逻辑
  10. 长列表性能优化:只用于展示的可以freeze对象
export default {
data: () => ({
users: {}
}),
async created() {
const users = await axios.get("/api/users");
this.users = Object.freeze(users);
}
};

Webpack 方面

  1. 可以用image-webpack-loader来压缩图片
  2. 提取公共代码
  3. 使用SourceMap解决构建后的项目无法精准定位错误的问题
  4. 构建结果输出分析使用webpack-bundle-analyzer
  5. 使用Tree Shaking剔除JS死代码,它正常工作的前提是代码必须采用ES6的模块化语法

其他方面

  1. Chrome Performance:使用Chrome开发者工具分析页面性能
  2. 让用户使用Chrome
  3. 使用Git管理代码,而不是使用SVN
  4. 团队代码尽可能使用ESlint保证编码风格

实现nextTick

· 阅读需 1 分钟
素明诚
Full stack development

为什么会有$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的区别

· 阅读需 3 分钟
素明诚
Full stack development

HTTP/HTTPS 的主要区别

HTTP 是一种无状态的协议,它不提供任何对数据的加密或安全保护。因此,任何人都可以在传输过程中查看或修改数据。

HTTPS 是在 HTTP 基础上增加了 SSL/TLS 加密协议的安全版本。它通过在客户端和服务器之间建立加密连接来保护数据的隐私和完整性。因此,当您使用 HTTPS 访问 Web 页面时,您可以确保您的数据不会被第三方窃取或篡改。

HTTPHTTPS
是否为加密传输明文传输混合加密传输
如何建立连接TCP/IP 三次握手TCP 三次握手 + SSL/TLS 握手
默认端口80443
证书没有服务端 CA 数字证书

HTTPS 工作原理

  1. TCP 协议三次握手,建立 TCP 连接
  2. 服务利用 TCP 将证书发送给浏览器
  3. 浏览器通过本地 Root CA 验证网站证书
  4. 浏览器用证书的公钥加密:协商对称加密的算法和密码
  5. 服务器相应,确定对称加密算法和密码
  6. 会话建立,来往数据使用对称加密

SSL/TLS

SSL (Secure Sockets Layer) 和 TLS (Transport Layer Security) 是加密协议,用于在两个通信节点之间提供安全连接。它们是为了保护数据在网络上传输过程中不被窃取或篡改而设计的。

SSL 和 TLS 是两种相似的协议,不同点在于 TLS 是 SSL 的替代品。

TLS 引入了一些改进,例如更强的加密算法和更好的认证方式。

因此,现在已经不再使用 SSL,而是使用 TLS。

SSL/TLS 原理

  1. 建立连接:客户端与服务端建立连接,进行 SSL/TLS 协议的握手(Handshake)。
  2. 证书验证:服务器发送公钥证书给客户端,客户端验证证书的有效性,包括证书颁发机构是否可信任,证书内容是否匹配网站信息等。
  3. 密钥交换:使用预定义的密钥交换算法,如 Diffie-Hellman,生成公共密钥,并使用该密钥加密下一步通信。
  4. 加密通信:使用公共密钥加密数据,并通过网络发送。
  5. 解密接收:服务器接收到加密数据,使用公共密钥进行解密。
  6. 结束连接:客户端与服务端完成通信后进行四次握手,结束连接。

整个过程中使用的证书都是由第三方机构颁发的,确保了数据安全和双方身份的正确性。

数据传输过程

9e2b119469d5a09878c3eddf8542345b65e936468119848b455f1a66f040f9eb

为什么是三次握手四次挥手

· 阅读需 1 分钟
素明诚
Full stack development

三次握手

因为二者都处于在一个初始状态,都是是为了建立连接,所以 ACK 响应这个步骤就可以是一步。

d765b74174cf30d522d384b425e2431c## 四次挥手

可能服务端给客户端发送的请求还没收回来,或者是客户端发送的请求服务端还没有响应,所以在挥手的时候,服务端自己要准备一段时间,中间这两步是没有办法合二为一的,所以必须是四次。

6aaac66eb342230d16875c7b367a8ff0

正向代理和反向代理的区别

· 阅读需 1 分钟
素明诚
Full stack development

正向代理

科学上网的时候,我们请求服务器,让它帮我们访问另一个服务器

反向代理

我们不知道后面有代理服务器,我们请求目标资源的时候,内部帮我们访问了其他网站的资源。重点在于这个事情我们是不知道的。

e7389519dd148683d8d4aa988062c944

前端常见算法题

· 阅读需 4 分钟
素明诚
Full stack development

数组去重

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));

深拷贝的实现

  1. JSON.parse(JSON.stringify(obj)):可以实现简单的对象的深拷贝,但是不支持函数、正则表达式、undefined、循环引用等特殊情况。
  2. 递归:通过递归的方式对对象进行拷贝,可以实现更为灵活的深拷贝,支持特殊情况。
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] 中找到最终的答案。