DOCTYPE

DOCTYPE 是一个声明,位于 HTML 文档的最顶部,指示浏览器使用哪种 HTML 或 XHTML 版本来渲染页面。它的主要作用是确保浏览器以标准模式解析文档,从而避免不同浏览器间的渲染差异。正确使用 DOCTYPE 可以提升页面的兼容性和可访问性。 <!DOCTYPE>声明应该位于HTML文档的第一行,紧接着是<html>标签。 例如,对于 HTML5 文档,你只需写: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document Title</title> </head> <body> <!-- 页面内容 --> </body> </html> 这个声明告诉浏览器该文档是一个HTML5文档。HTML5是最新的HTML标准,它包括了许多现代化的功能,如语义元素、表单控件、音频和视频等。 DOCTYPE 的作用有以下几个方面: 指定 HTML 版本:浏览器根据 DOCTYPE 的声明来确定使用哪个 HTML 版本来渲染页面,从而保证页面在不同的浏览器上显示一致性。 触发标准模式:在 HTML 中,如果省略了 DOCTYPE 声明,浏览器会进入混杂模式(Quirks mode),这种模式下浏览器的渲染方式与早期的浏览器相同,可能导致页面的显示出现不可预测的错误。而指定了 DOCTYPE 声明,则会触发标准模式(Standards mode),使得浏览器按照 HTML 规范的要求进行页面渲染,从而保证页面的稳定性和可靠性。 供浏览器和开发人员参考:DOCTYPE 声明还包含了有关 HTML 文档的元信息,例如所使用的 DTD(文档类型定义),以及其他的元数据信息,这些信息可以供浏览器和开发人员参考,帮助开发人员更好地了解和掌握 HTML 语言的特点和规范。 提高网页加载速度:指定 DOCTYPE 声明可以帮助浏览器更快地加载网页,因为浏览器知道要使用哪种渲染模式,从而更快地解析 HTML 文档。 避免代码错误:指定 DOCTYPE 声明可以帮助开发人员在编写 HTML 代码时遵循标准,避免一些常见的代码错误,例如忘记关闭标签或者使用非法的属性和元素等等。 除了HTML5的<!DOCTYPE>声明之外,还有一些其他版本的HTML和XHTML文档类型声明。这里是一些例子: 1. HTML 4.01 Strict: ...

September 24, 2024

Claude Code 源码导读:Agent 设计详解

Claude Code 的 agent 到底是怎么被设计成一个能长时间工作、能分派子 agent、能记忆、能压缩上下文、也能可靠停下来的系统的? Claude Code 最值得研究的地方,不是它“能调用工具”,而是它把模型、工具、记忆、上下文、后台任务、hook 和权限系统编成了一个稳定的 agent harness。 一句话概括:Claude Code 的 agent 不是一个模型循环,而是三层循环叠在一起:主 query 循环负责推理和工具回灌;工具循环负责受控执行和并发;任务循环负责子 agent、后台 agent、记忆整理和长任务生命周期。 flowchart TD User["用户输入 / 队列消息"] --> Query["query.ts 主循环"] Query --> Model["流式模型调用"] Model -->|没有 tool_use| StopPath["停止路径stop hooks / token budget / completed"] Model -->|产生 tool_use| ToolLoop["工具执行循环"] ToolLoop --> Attach["附件注入记忆 / 变更文件 / 任务通知 / 技能"] Attach --> Query Query --> Compact["上下文治理tool budget / microcompact / autocompact / reactive compact"] Query --> Memory["记忆系统CLAUDE.md / AutoMem / Session Memory"] Query --> AgentTool["AgentTool"] AgentTool --> SubAgent["runAgent 子循环"] SubAgent --> LocalTask["LocalAgentTask前台 / 后台 / 可恢复"] LocalTask --> Attach 一、核心源码地图 先把关键文件放在桌面上: ...

June 21, 2026

Swift 面试:值语义、COW 与集合源码解析

Swift 面试:值语义、COW 与集合源码解析 Swift 的 Array、String、Dictionary 都表现为值类型,但它们不可能每次赋值都完整复制底层存储。面试官问值语义和 COW,真正想看的是你能不能说清楚:值语义是语言语义,COW 是性能实现;集合表面是 struct,底层经常共享引用存储;写入前靠唯一性检查决定是否复制。 这篇文章从面试题出发,把结论落到 Swift 标准库源码里的 Array buffer、String guts、Dictionary storage 和 isKnownUniquelyReferenced。 面试高频问题 Swift 的 struct 为什么常说是值语义? Array 赋值时一定会复制底层元素吗? Copy-on-Write 的触发条件是什么? isKnownUniquelyReferenced 检查的到底是什么? Array、ContiguousArray、ArrayBuffer、Storage 是什么关系? String 为什么不能用整数下标随机访问? String.Index 为什么不是一个简单的 Int? Dictionary 也是 COW 吗? ArraySlice 为什么可能持有原数组存储? 值类型里包含 class 引用,还算值语义吗? 30 秒回答版 Swift 的值语义是说:从语言使用者角度看,赋值、传参、修改不会意外影响另一个值。但这不等于底层每次都立即复制。 标准库集合通常用 Copy-on-Write 实现:多个值可以共享同一份堆上 buffer;只有当某个值要写入时,才检查底层 buffer 是否唯一引用。如果唯一,就原地修改;如果不唯一,就复制一份新 buffer 再修改。 所以: 值语义:用户看到的是独立值 COW:实现上先共享,写入前再判断是否复制 ARC:维护底层 buffer 的引用计数 isUnique:让 COW 判断能否原地修改 面试可以这样回答: Swift 的 Array 是 struct,但它内部持有引用语义的 storage。赋值时通常只复制结构体里的引用;真正写入时通过唯一性检查决定是否复制底层 storage。这让 Array 同时具备值语义和接近引用共享的性能。 ...

June 16, 2026

Codable底层原理

Codable 是 Swift 4 引入的序列化方案,官方定位是替代 Objective-C 时代的 NSCoding、以及各种第三方字典转模型框架(MJExtension、YYModel、JSONModel 等)。与运行时反射方案不同,Codable 通过"编译器自动合成 + 标准库协议抽象 + 具体格式实现"三层解耦,在编译期就把类型与序列化逻辑绑定好,兼具类型安全、性能和扩展性。 本文基于以下 Swift 源码展开分析: 协议定义:swift/stdlib/public/core/Codable.swift 编译器合成:swift/lib/Sema/DerivedConformanceCodable.cpp、DerivedConformanceCodingKey.cpp Foundation 实现:swift-corelibs-foundation/Sources/Foundation/JSONEncoder.swift、JSONDecoder.swift、PropertyListEncoder.swift 整体架构 在开始深入之前,先建立整体印象。Codable 可以拆成三层角色: 用户类型层:业务中的 struct / class / enum,声明遵循 Codable 标准库与编译器层:标准库定义 Encodable / Decodable / Encoder / Decoder 等协议,编译器为符合条件的类型合成 encode(to:) 和 init(from:) 格式实现层:Foundation 或第三方提供具体 Encoder / Decoder,负责把容器操作落到 JSON、Plist、BSON 等格式上 flowchart LR subgraph L1[用户类型层] A[struct / class / enum声明遵循 Codable] end subgraph L2[标准库与编译器层] B[Encodable / Decodable协议要求] C["编译器合成encode(to:) / init(from:)"] D[Encoder / Decoder容器协议] B --> C C --> D end subgraph L3[格式实现层] E[JSONEncoder / JSONDecoderPropertyListEncoder / 第三方实现] F[Data / 字符串 / 其他格式] E --> F end A -->|conforms to| B D -->|由具体类型实现| E 核心思想是:标准库只定义"如何描述一个可编码类型"和"编码器需要提供什么能力",具体的格式(JSON、Plist、BSON…)由 Foundation 或第三方实现。用户类型只需要遵循协议,剩下的由编译器在 SIL 层自动生成。 ...

June 8, 2026

React Native 详解

React Native 是 Meta 2015 年开源的跨平台框架,用 JavaScript/TypeScript 写一份业务代码,在 iOS 和 Android 上渲染出真正的原生控件(UIView / android.view.View),而不是像 Flutter 那样自绘,也不是像 H5 那样跑在 WebView 里。经过 2018~2024 年的"新架构"大重构,RN 在 0.76 让 New Architecture(Fabric + TurboModules + JSI + Codegen + Bridgeless)成为默认,并在 0.82(2025 年 10 月)彻底告别旧的 Bridge 时代——这是 RN 十年来最大的一次范式迁移。 对 iOS 开发者而言,RN 的定位很特殊:UI 仍然是 UIKit,但控制 UI 的大脑换成了 JS。这让它一方面拥有"原生 Look & Feel“的天然优势(iOS 26 Liquid Glass 不用等框架跟进),另一方面又背负着”JS/原生边界抖动“的原罪。在 AI Coding 时代,RN 凭借 Web 生态庞大的训练语料和 Expo 工具链成为 LLM 生成代码正确率最高的移动框架,但 JSI 的 C++ 层和 Bridgeless 的新调试链路也让"AI 修 Bug"变得比以前更难。 ...

May 2, 2026

SOLID原则

概述 SOLID 是面向对象设计的五大基本原则的首字母缩写,由 Robert C. Martin(Uncle Bob)在 2000 年代初期提出。这五个原则是构建可维护、可扩展软件的基础,在 iOS 开发中同样适用。 字母 原则 英文名称 S 单一职责原则 Single Responsibility Principle O 开放封闭原则 Open-Closed Principle L 里氏替换原则 Liskov Substitution Principle I 接口隔离原则 Interface Segregation Principle D 依赖倒置原则 Dependency Inversion Principle 单一职责原则(Single Responsibility Principle, SRP) 定义 A class should have one, and only one, reason to change. 一个类应该只有一个引起它变化的原因。 原则解读 单一职责原则要求每个类只负责一项职责。这里的"职责"可以理解为"变化的原因"——如果你能想到多于一个的原因去改变一个类,那么这个类就有多于一个的职责。 核心思想:将不同的关注点分离,使每个模块只专注于做好一件事。 解决的问题 1. 代码耦合度高 当一个类承担多个职责时,这些职责会相互依赖、相互影响。修改其中一个职责的代码,可能会无意中破坏另一个职责的功能。 2. 难以复用 如果一个类混合了多个职责,当你只想使用其中一个职责时,不得不引入整个类及其所有依赖。 3. 维护困难 职责混杂的类通常代码量大、逻辑复杂,理解和修改都很困难。不同职责的代码交织在一起,修改一处可能产生意想不到的连锁反应。 4. 测试复杂 ...

May 2, 2026

WebView底层原理

前言 iOS 上的 WebView 目前以 WKWebView 为事实标准。它对外表现得像一个 UIView 子类,但内部其实对接着整个 WebKit 引擎——一个由多个独立进程协作的庞大系统。日常开发中遇到的那些困扰:为什么 Web 页白屏不会把 App 带崩?为什么 Cookie 和 App 自身的 NSHTTPCookieStorage 总是对不上?为什么 JS 调用 Native 永远是异步?为什么 NSURLProtocol 拦不到 WKWebView 的请求?这些问题单看 API 都得不到答案,必须下潜到 WebKit 源码里才能看清楚。 好在 WebKit 是 Apple 官方开源的项目,仓库在 github.com/WebKit/WebKit。本文基于其 Source/ 目录下的公开源码,按"源码地图 → 多进程架构 → 各进程职责 → 全链路串联 → 工程启示"的顺序,把 WKWebView 从创建到渲染一帧的底层机制梳理清楚。 一、先看源码地图 阅读源码前,先在脑子里建立目录结构。以 WebKit/WebKit 仓库的 Source/ 目录为例: Source/ ├── JavaScriptCore/ # JS 引擎(解释器、JIT 编译器、GC) ├── WebCore/ # 渲染引擎核心(DOM、CSSOM、Layout、Paint) ├── WebKit/ # 多进程框架 + Cocoa 层 API │ ├── UIProcess/ # 主进程侧(App 进程) │ │ ├── API/Cocoa/ # WKWebView.mm、WKProcessPool.mm 等 │ │ ├── API/ios/ # WKWebViewIOS.mm │ │ ├── ios/ # WKContentView.mm、WebPageProxyIOS.mm │ │ └── ... │ ├── WebProcess/ # 渲染进程侧(WebContent) │ ├── NetworkProcess/ # 独立网络进程 │ ├── GPUProcess/ # 独立 GPU 进程 │ └── Shared/ # 跨进程共享的数据结构、IPC 消息定义 └── WTF/ # 基础容器、线程、字符串工具库 日常 iOS 开发能看到的 WKWebView,对应的实现就在 Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm。它是一个 Objective-C++ 文件,内部只是持有一个 C++ 的 WebPageProxy 对象,几乎所有实际工作都转发给它。为什么要这样设计?原因就藏在下一节要讲的多进程架构里。 ...

May 2, 2026

命令模式

定义 命令模式(Command Pattern)是一种行为型设计模式,它将请求封装成对象,从而可以用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。 命令模式的核心思想是:将"请求"封装成一个对象,使得可以用不同的请求、队列或日志来参数化其他对象,同时支持可撤销操作。 为什么需要命令模式 命令模式要解决的核心问题是:将请求(操作)封装成对象,使得可以对请求进行存储、传递、撤销等操作。 问题场景:假设我们正在开发一个文本编辑器,需要支持撤销/重做功能。 最直接的方式可能是这样: class TextEditor { var text: String = "" func insertText(_ newText: String, at position: Int) { let index = text.index(text.startIndex, offsetBy: position) text.insert(contentsOf: newText, at: index) } func deleteText(from start: Int, length: Int) { let startIndex = text.index(text.startIndex, offsetBy: start) let endIndex = text.index(startIndex, offsetBy: length) text.removeSubrange(startIndex..<endIndex) } } // 用户操作 let editor = TextEditor() editor.insertText("Hello", at: 0) editor.insertText(" World", at: 5) editor.deleteText(from: 5, length: 6) // 如何实现撤销?需要记住每次操作的类型、参数、以及如何逆向执行 // 这变得非常复杂... 这种方式有什么问题? ...

May 2, 2026

小红书-社招-3年 · 第 3 轮 · 技术面试

← 第 2 轮 · 返回本次面经 · 已是最后一轮 → 本轮概述: 这一轮主要考察了小程序的低代码设计架构、Web Worker的使用、中台系统的微前端拆分策略等方面的知识。 本轮共 4 道题。答案默认折叠,便于先自行作答。 1. 讲一下你关于小程序的低代码设计架构 题目要点 小程序低代码架构本质是配置驱动的运行时体系,核心包括 DSL 协议设计、组件注册机制、运行时解析与数据驱动更新;必须围绕 setData 性能约束进行差量更新与渲染优化;工程重点不在编辑器,而在运行时引擎的性能治理与扩展能力设计。 参考答案 小程序的低代码架构,本质是在受限运行环境下实现“可配置驱动 UI 与逻辑”。核心不是拖拽能力,而是如何让页面结构、交互逻辑、数据流都由配置驱动,同时保证性能与可维护性。 一、整体架构分层 小程序低代码一般分为四层: 编辑层 → DSL 层 → 运行时引擎 → 渲染层 编辑层负责产出结构化配置;DSL 层定义组件树与属性协议;运行时负责解析与调度;渲染层落在小程序原生组件体系之上(如 WXML + setData 机制,在 微信小程序 中即运行于其渲染框架内)。 关键问题在于:小程序不是虚拟 DOM 模型,而是逻辑层与视图层分离,通过 JSON 数据桥接,因此架构必须围绕数据驱动。 二、DSL 设计 DSL 通常采用 JSON Schema 形式,核心包含: 组件类型 属性 props 样式 事件绑定 数据源 条件显示规则 低代码的关键在于“协议稳定性”,一旦 DSL 设计混乱,后续扩展成本会极高。因此会设计: 组件注册机制 属性校验规则 默认值策略 版本兼容策略 三、运行时引擎 运行时是核心。 ...

February 1, 2026

http方法

HTTP 协议中定义了多种 请求方法(HTTP Methods),用于客户端和服务器之间进行不同的操作。 一、常用的 HTTP 方法 方法 是否幂等 是否安全 说明 GET ✅ 幂等 ✅ 安全 获取资源。请求参数放在 URL 上。不会对资源产生副作用。 POST ❌ 非幂等 ❌ 不安全 提交数据(如表单、上传),可能导致资源变化或创建。 PUT ✅ 幂等 ❌ 不安全 用于整体更新某个资源(数据完全替换)。 PATCH ❌ 非幂等 ❌ 不安全 用于部分更新资源(只改动部分字段)。 DELETE ✅ 幂等 ❌ 不安全 删除指定资源。 二、幂等性和安全性解释 幂等(Idempotent):同一个请求重复执行多次,结果应一样。例如多次 DELETE 相同资源结果相同。 安全(Safe):不对服务器资源造成副作用。GET 只查询,不修改数据,因此是安全的。 三、其他常见 HTTP 方法 方法 说明 HEAD 类似 GET,但不返回响应体,只返回响应头。常用于检测资源是否存在、获取响应信息。 OPTIONS 用于客户端获取服务器支持哪些方法。也是 CORS 预检请求的一部分。 TRACE 回显服务器收到的请求,主要用于调试。很少使用,可能存在安全隐患。 CONNECT 用于建立隧道(如 HTTPS 的代理通信)。 四、使用场景示例 场景 方法 示例 获取用户列表 GET GET /api/users 创建用户 POST POST /api/users 更新用户信息 PUT / PATCH PUT /api/users/1 或 PATCH /api/users/1 删除用户 DELETE DELETE /api/users/1 总结:记住这几点 GET 用于查询(安全、幂等)。 POST 用于新增(不幂等)。 PUT/PATCH 用于修改资源(PUT 是整体替换,PATCH 是部分更新)。 DELETE 用于删除资源(幂等,但不安全)。 OPTIONS/HEAD 用于辅助请求。 常见考点 1. 语义理解 每个方法在 RESTful API 中代表的含义? PUT 和 PATCH 的区别? GET 和 POST 区别?是否可以用 POST 替代 GET? 2. 幂等性与安全性 哪些方法是幂等的?(调用多次结果一致) 哪些方法是安全的?(不会对服务器资源产生副作用) 3. 浏览器行为 表单默认提交方式是什么?(GET 或 POST) GET 请求能携带 body 吗?(规范上不能,但部分浏览器允许) 4. 缓存行为 浏览器对 GET、POST 的缓存行为有什么区别? 为什么 GET 更适合缓存? 5. 跨域相关(CORS) 哪些方法属于“简单请求”? 使用 PUT/PATCH/DELETE 会触发预检请求(OPTIONS),为什么? 6. 请求体与响应体 哪些方法通常不携带请求体?(如 GET、DELETE) 哪些方法可以/需要携带请求体?(如 POST、PUT、PATCH) 7. 对比和实际使用中的陷阱 PUT/POST 混用的场景(如某些系统用 POST 实现更新) DELETE 是否要有请求体?(规范允许,但不推荐) 可能的延伸考察 RESTful API 设计规范 REST API 中,如何正确使用 GET/POST/PUT/DELETE 等方法? 设计一个增删改查接口,如何对应到不同 HTTP 方法? 状态码与方法配合 DELETE 成功一般返回什么状态码?(如 204 No Content) POST 创建资源后返回什么?(201 Created) 结合安全问题 POST/PUT 方法可能面临哪些安全风险?如 CSRF? 为什么建议对非幂等方法加 CSRF 防护?

July 26, 2025