问git 提交的整个过程
- 暂存本地更改
当你需要暂时保存当前工作进度,但不想立即提交时,可以使用 git stash 命令。例如:
git stash push -m "stash local changes"
- Git 打开了一个文本编辑器(如 Vim 或其他默认编辑器),提示你输入合并提交的说明信息。
- 按下 `Esc` 键,退出插入模式。
- 输入 `:wq` 并按下回车键,保存并退出 Vim。
执行该命令后,Git 会将当前的本地更改存储起来,方便你后续恢复。
- 解决合并冲突
在合并分支时,可能会出现冲突。Git 会在冲突文件中标记冲突部分,例如:
<<<<<<< HEAD
// 本地代码
=======
// 远程代码
>>>>>>> branch-name
你需要手动编辑文件,保留需要的代码,删除冲突标记,然后保存文件。
-
合并分支
-
- 成功合并
当你从远程分支拉取代码并合并到当前分支时,例如:
git pull origin main
如果合并成功,Git 会输出相关信息,显示使用了 ort 策略完成合并,并列出被修改、新增或删除的文件。
-
- 已经是最新的
如果当前分支已经包含了远程分支的所有更改,Git 会提示:
Already up to date
这表明无需再次合并。
撤销提交(重在reset 和 revert 区别)
- git log 很重要,查看最近提交记录;git diff 可以看每次代码变化差异(在每次push远程时候,一定要先看下自己是否修改了些不必要的文件)
- 想从硬盘恢复某个文件的旧版本:
git checkout <file文件名>
或
git restore 文件名
- 暂存区撤销文件
git reset <文件名>
或
git restore --staged <文件名>
- 撤销本地最后一次提交,并且保留更改:
git reset head~1
- 如果你想撤销本地的最后一次提交,并删除更改,可以使用以下命令:
git reset --hard head~1
- 如果你想撤销本地的某个特定提交,可以使用以下命令:
git revert hash
-
如果你已经将更改推送到远程分支,但需要撤销,可以根据分支类型进行操作:
- 如果是公共分支,建议使用
git revert,然后推送更改:git revert <commit-hash> git push - 如果是私人分支,可以使用强制推送(需谨慎操作),强制推送会进行代码覆盖哦
git reset --hard head~1 git push -f
- 如果是公共分支,建议使用
🫥🫥🫥🫥🫥🫥🫥🫥🫥🫥🫥🫥🫥🫥🫥🫥🫥🫥🫥
原型与原型链的本质
JavaScript 中的每个对象都隐式关联着另一个对象——原型。这种关联构成了原型链这一独特的继承机制。通过 __proto__(现已建议使用 Object.getPrototypeOf())可以访问对象的原型,而构造函数通过 prototype 属性为实例提供原型。
原型链的查找机制体现了委托式继承的思想:当访问属性时,引擎会递归遍历原型链,直到找到属性或抵达 Object.prototype 的终点(null)。这种设计既实现了代码复用,又保持了对象的轻量性。
作用域与执行上下文
作用域的本质是词法环境的抽象表示,它规定了变量的可访问性。现代 JavaScript 具有三种作用域类型:
- 块级作用域(
let/const) - 函数作用域(
var) - 全局作用域
作用域链的形成源于词法环境的嵌套结构。执行上下文创建时,会建立对外部词法环境的引用,从而构成链式查找路径。值得注意的是,这种链接关系在函数创建时(而非调用时)就已确定,这就是闭包能够捕获外部变量的根本原因。
函数执行的双阶段模型
JavaScript 引擎处理代码分为两个关键阶段:
-
编译阶段:
- 构建词法环境
- 处理函数和变量声明(hoisting)
- 建立作用域链
- 生成可执行代码
-
执行阶段:
- 进行变量赋值
- 执行函数调用
- 处理运行时错误
- 管理调用栈
这种分离解释了为何 var 变量在声明前可访问(值为 undefined),而 let/const 会触发暂时性死区。
箭头函数的本质差异
箭头函数不仅是语法糖,它的核心特性源于词法作用域的绑定:
- 词法 this:箭头函数的
this在定义时静态确定,通过[[ThisMode]]内部插槽实现 - 无构造函数能力:缺少
prototype属性和[[Construct]]内部方法 - 简化的参数处理:没有
arguments对象,但可通过剩余参数模拟
这些特性使箭头函数特别适合作为回调函数,比如map 、fliter 等场景下,但也限制了其使用场景。在需要动态上下文或元编程时,传统函数仍是更好的选择。
变量提升的底层原理
变量提升现象源于 JavaScript 的编译过程:
- 在编译阶段,引擎会扫描代码并:
- 为函数声明创建完整绑定
- 为
var变量创建初始化为undefined的绑定
- 执行阶段才进行实际赋值
这种设计源于早期 JavaScript 需要单次解析执行的需求。ES6 的 let/const 通过引入块级作用域和暂时性死区(TDZ)解决了相关的混淆问题。
事件系统的双阶段模型
DOM 事件流包含三个关键阶段:
- 捕获阶段:从
window向下传播到目标 - 目标阶段:在事件目标上触发
- 冒泡阶段:从目标向上冒泡
事件代理利用了冒泡阶段的特性,但需要注意:
- 某些事件(如
focus)不冒泡 stopPropagation():阻止事件的冒泡或捕获行为。preventDefault():阻止事件的默认行为,但不会影响事件的传播。(冒泡或捕获)
进程与线程的浏览器实现
现代浏览器采用多进程架构:
- 浏览器进程:管理界面、网络请求等
- 渲染进程:每个标签页独立进程,包含:
- 主线程(DOM 解析、样式计算、JavaScript 执行)
- 合成线程
- 光栅线程
- GPU 进程:加速渲染(transform、opacity等)
- 插件进程:隔离风险插件
Web Worker 运行在独立的线程中,通过消息传递(postMessage)与主线程通信(onmessage等),这种隔离设计既保证了并行能力,又维护了线程安全。
哈希算法的应用实践
JavaScript 引擎使用哈希表实现对象属性的快速访问,其核心机制包括:
- 哈希函数:将键转换为固定长度的哈希值
- 冲突解决:通常采用链地址法
- 动态扩容:当负载因子过高时自动调整大小
在 Map 和 Set 的实现中,哈希算法使得基本操作的时间复杂度接近 O(1)。值得注意的是,对象的字符串键会被规范化,而 Map 保留键的原始值。