我说要高端走,面试官让我回去补Git+JavaScript基础知识🤨🤨

1,365 阅读6分钟

问git 提交的整个过程

  • 暂存本地更改

当你需要暂时保存当前工作进度,但不想立即提交时,可以使用 git stash 命令。例如:

git stash push -m "stash local changes"
-   Git 打开了一个文本编辑器(如 Vim 或其他默认编辑器),提示你输入合并提交的说明信息。
-   按下 `Esc` 键,退出插入模式。
-   输入 `:wq` 并按下回车键,保存并退出 Vim。

执行该命令后,Git 会将当前的本地更改存储起来,方便你后续恢复。

  • 解决合并冲突

在合并分支时,可能会出现冲突。Git 会在冲突文件中标记冲突部分,例如:

<<<<<<< HEAD
// 本地代码
=======
// 远程代码
>>>>>>> branch-name

你需要手动编辑文件,保留需要的代码,删除冲突标记,然后保存文件。

  • 合并分支

    1. 成功合并

当你从远程分支拉取代码并合并到当前分支时,例如:

git pull origin main

如果合并成功,Git 会输出相关信息,显示使用了 ort 策略完成合并,并列出被修改、新增或删除的文件。

    1. 已经是最新的

如果当前分支已经包含了远程分支的所有更改,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 引擎处理代码分为两个关键阶段:

  1. 编译阶段

    • 构建词法环境
    • 处理函数和变量声明(hoisting)
    • 建立作用域链
    • 生成可执行代码
  2. 执行阶段

    • 进行变量赋值
    • 执行函数调用
    • 处理运行时错误
    • 管理调用栈

这种分离解释了为何 var 变量在声明前可访问(值为 undefined),而 let/const 会触发暂时性死区。

箭头函数的本质差异

箭头函数不仅是语法糖,它的核心特性源于词法作用域的绑定:

  1. 词法 this:箭头函数的 this 在定义时静态确定,通过 [[ThisMode]] 内部插槽实现
  2. 无构造函数能力:缺少 prototype 属性和 [[Construct]] 内部方法
  3. 简化的参数处理:没有 arguments 对象,但可通过剩余参数模拟

这些特性使箭头函数特别适合作为回调函数,比如map 、fliter 等场景下,但也限制了其使用场景。在需要动态上下文或元编程时,传统函数仍是更好的选择。

变量提升的底层原理

变量提升现象源于 JavaScript 的编译过程:

  1. 在编译阶段,引擎会扫描代码并:
    • 为函数声明创建完整绑定
    • var 变量创建初始化为 undefined 的绑定
  2. 执行阶段才进行实际赋值

这种设计源于早期 JavaScript 需要单次解析执行的需求。ES6 的 let/const 通过引入块级作用域和暂时性死区(TDZ)解决了相关的混淆问题。

事件系统的双阶段模型

DOM 事件流包含三个关键阶段:

  1. 捕获阶段:从 window 向下传播到目标
  2. 目标阶段:在事件目标上触发
  3. 冒泡阶段:从目标向上冒泡

事件代理利用了冒泡阶段的特性,但需要注意:

  • 某些事件(如 focus)不冒泡
  • stopPropagation() :阻止事件的冒泡或捕获行为。
  • preventDefault() :阻止事件的默认行为,但不会影响事件的传播。(冒泡或捕获)

进程与线程的浏览器实现

现代浏览器采用多进程架构:

  • 浏览器进程:管理界面、网络请求等
  • 渲染进程:每个标签页独立进程,包含:
    • 主线程(DOM 解析、样式计算、JavaScript 执行)
    • 合成线程
    • 光栅线程
  • GPU 进程:加速渲染(transform、opacity等)
  • 插件进程:隔离风险插件

Web Worker 运行在独立的线程中,通过消息传递(postMessage)与主线程通信(onmessage等),这种隔离设计既保证了并行能力,又维护了线程安全。

哈希算法的应用实践

JavaScript 引擎使用哈希表实现对象属性的快速访问,其核心机制包括:

  1. 哈希函数:将键转换为固定长度的哈希值
  2. 冲突解决:通常采用链地址法
  3. 动态扩容:当负载因子过高时自动调整大小

MapSet 的实现中,哈希算法使得基本操作的时间复杂度接近 O(1)。值得注意的是,对象的字符串键会被规范化,而 Map 保留键的原始值。