ArkUI 与 HarmonyOS(鸿蒙方向选考)

共 18 题
📑 题目列表 18 题
#
★★★

1. ArkUI 的声明式 UI,状态管理与组件更新机制?

请说明 ArkUI 声明式 UI 中状态管理的基本机制,状态变量变化时组件是如何被驱动更新的?与命令式 UI 相比其核心优势是什么?

  • 状态变量(@State 等装饰器)与 UI 的绑定模型
  • 状态变更到 UI 更新的自动刷新流程与刷新粒度
  • 声明式开发与命令式开发在可维护性上的差异

ArkUI 采用声明式 UI 模型:开发者用装饰器(@State、@Prop、@Link 等)声明状态变量,并在 build 方法中声明 UI 与状态之间的绑定关系,UI 是状态的函数,状态变化时框架自动找到依赖该状态的组件并触发局部刷新,无需开发者手动操作 DOM。其内部基于状态变量依赖收集机制维护"状态-组件"的映射:某个状态被修改后,ArkUI 的渲染引擎定位到受影响的组件节点,仅重渲染该组件及其子树的受影响部分,而非整页刷新。

相比命令式(命令式通过 id 获取节点再 setText/setStyle 逐项修改),声明式的优势是 UI 与数据单向依赖、代码可读性与可测试性更强,且框架可以自动做最小化刷新与批量调度;劣势是引入运行时依赖追踪的开销,且对写法有约束(状态必须通过装饰器管理,直接改普通成员变量不会触发刷新)。工程上应尽量缩小状态粒度、避免在 build 中做耗时计算,以发挥局部刷新的性能优势。

本题考察对声明式 UI 本质的理解:状态是唯一数据源、UI 是状态的纯函数、框架负责依赖追踪与最小化刷新。回答时先讲"状态声明-依赖收集-定向刷新"的闭环,再对比命令式差异,最后落到状态粒度的工程实践,即能体现对 ArkUI 渲染模型的系统性认识。

#
★★

2. 鸿蒙组件生命周期 aboutToAppear/aboutToDisappear 与页面生命周期的关系

鸿蒙自定义组件的 aboutToAppear/aboutToDisappear 与页面(页面级)生命周期之间是怎样的关系?分别在什么时机触发、各自适合做什么?

  • aboutToAppear/aboutToDisappear 的触发时机(组件创建/销毁前后)
  • 页面生命周期(onPageShow/onPageHide/onBackPress)的语义
  • 二者在初始化、数据加载、资源释放上的分工

aboutToAppear 在组件即将创建、即将挂载到组件树时触发(build 之前),适合做初始化逻辑:读取 @Prop/@Link 传入的值、发起数据请求、注册事件监听等;aboutToDisappear 在组件即将销毁时触发,适合释放定时器、取消订阅、解绑事件等清理工作。它们属于"组件级"生命周期,随组件的创建与销毁而触发,与页面是否可见无关。

页面级生命周期(onPageShow/onPageHide/onBackPress 等)属于"页面级":onPageShow 在页面显示时触发(包括从后台回到前台、从子页面返回),onPageHide 在页面隐藏时触发。关系上:页面首次加载时,先执行页面及根组件的 aboutToAppear,再进入 onPageShow;而页面被覆盖(如跳转到新页面)时只触发 onPageHide,组件并不会销毁,只有页面真正销毁(如压栈返回)时才触发 aboutToDisappear。因此"数据请求"适合放 aboutToAppear(只做一次),"页面可见时刷新"适合放 onPageShow(每次显示都执行),两者不可互相替代。

核心是区分"组件创建/销毁"与"页面可见/不可见"两套语义:aboutToAppear/aboutToDisappear 绑定组件生命周期、只执行一次;onPageShow/onPageHide 绑定页面显示状态、可多次触发。能准确说出首屏加载时两者先后顺序与返回场景下组件不销毁的事实,即证明理解到位。

#
★★

3. 鸿蒙 TaskPool 与 Worker 的多线程选择依据与线程间通信方式

鸿蒙提供了 TaskPool 与 Worker 两种多线程能力,它们的定位差异是什么?实际开发中如何选择?线程间通信有哪些方式?

  • TaskPool(任务池,适合短时任务)与 Worker(常驻线程,适合长时任务)的定位差异
  • 两者的线程复用、任务调度与生命周期管理区别
  • 线程间通信方式(Sendable、ArrayBuffer、序列化消息)与限制

TaskPool 是"任务调度模型":把独立函数作为任务投递到全局线程池执行,系统负责线程的创建、复用与销毁,适合计算密集但相互独立的短任务(如图片处理、JSON 解析),开发者不感知线程实例;Worker 是"常驻线程模型":开发者显式创建并管理 Worker 线程,线程存活期可跨多个任务,适合需要持续运行或有状态的任务(如音视频编解码循环、长连接数据处理)。

选择依据:任务轻量、频次高、无需跨任务状态 → TaskPool;需要常驻、有状态、需要精细控制生命周期 → Worker。通信方式上,两者都通过结构化克隆传递消息(Worker 用 postMessage/onmessage),TaskPool 通过任务参数与返回值传递;高吞吐场景推荐使用 Sendable 对象(共享内存 + 引用计数,避免深拷贝)或转移 ArrayBuffer 所有权(transferable)减少拷贝开销。注意:TaskPool 任务函数需独立可序列化,闭包捕获受限;Worker 中修改主线程对象必须显式回传消息。

答题主线是"任务池 vs 常驻线程"两个模型的定位差异,再落到选择依据(任务长短、是否有状态)与通信机制(消息克隆、Sendable、ArrayBuffer 转移)。抓住"TaskPool 管线程、Worker 管线程实例"这一核心区别,就能把两者的适用场景说清楚。

#
★★

4. 应用包结构 HAP/HAR/HSP 的差异与模块化发布策略

鸿蒙应用工程中的 HAP、HAR、HSP 三种包结构有何差异?在模块化拆分与发布时分别适合什么场景?

  • HAP(应用安装包)、HAR(静态共享包)、HSP(动态共享包)的形态差异
  • 三者代码与资源的共享方式(编译期打包 vs 运行时加载)
  • 模块化发布策略:按需加载、多 HAP 分发、HSP 动态加载

HAP(HarmonyOS Ability Package)是应用安装与运行的基本单元,包含 UIAbility、页面与资源,一个应用可含多个 HAP(如主模块 + 特性模块)按需分发;HAR(HarmonyOS Archive)是静态共享包,编译期被打包进宿主 HAP,代码与资源随宿主分发,无法单独动态加载,适合被多个模块稳定复用的公共代码;HSP(HarmonyOS Shared Package)是动态共享包,独立编译、独立分发,运行时按需动态加载,可被多个 HAP 共享同一份实现,适合拆分为插件化、可单独升级的模块。

发布策略上:公共基础库(工具函数、基础组件)放 HAR 简单可靠;体积大、更新频繁、需要按需激活的业务模块(如支付、直播)放 HSP 或独立 HAP 实现动态分发;多 HAP + HSP 组合可实现"一次上架、按需下载",控制安装包体积与启动速度。选择时还要注意 HAR 的代码会被多个宿主各打一份(增大包体),HSP 通过依赖共享避免重复打包,但引入运行时依赖解析与版本管理复杂度。

抓住"编译期打包(HAR)vs 运行时加载(HSP)vs 独立分发单元(HAP)"这条主线即可。回答时按"是什么-差异点-发布策略"展开,并用包体大小、更新粒度、加载时机三个维度对比,能体现工程化理解。

#
★★

5. HarmonyOS NEXT 纯血鸿蒙剔除 AOSP 带来的存量代码适配改造

HarmonyOS NEXT(纯血鸿蒙)移除 AOSP 对存量应用的适配改造提出了哪些挑战?存量代码应如何分层评估与改造?

  • 剔除 AOSP 后对 Android 依赖(SDK/NDK/JNI)的不可用影响
  • 存量代码的技术栈分类(原生 Android / 跨端 / H5)与对应改造路径
  • 改造的优先级评估与灰度策略

HarmonyOS NEXT 不再兼容 Android APK 与 AOSP 底层,依赖 Android SDK、JNI、第三方 AAR 的存量代码无法直接运行,必须重写为 ArkTS/ArkUI 或适配鸿蒙原生能力。改造工作可分层:第一层是业务逻辑与技术栈盘点,按"纯 UI 页面 / 业务逻辑 / 系统能力调用(推送、定位、支付、相机)/ 原生依赖(NDK、JNI、AAR)"四类评估;第二层是按模块选择路径——轻交互页面用 ArkTS 重写,复杂页面可先用 Web 容器(ArkWeb)加载 H5 过渡,公共逻辑抽成 HAR/HSP 共享;第三层是处理系统能力差异:定位、蓝牙、NFC、推送等都要替换为鸿蒙 SDK 对应接口,原有的第三方 SDK(友盟、极光等)需等待其鸿蒙版本。

改造策略上建议"由外到内、分批灰度":先以 H5 套壳保证功能可用,再逐页原生化替换高频页面,同时建立接口兼容层(如统一封装 storage/网络/埋点),降低业务代码对平台 API 的直接依赖,最后移除 H5 兜底。成本评估要计入:团队 ArkTS 学习成本、双栈并行维护成本、以及每个系统能力替换时的联调与回归成本。

本题考查存量改造的工程方法论:先分层盘点(UI/逻辑/系统能力/原生依赖),再按"套壳过渡-逐页原生-能力替换"推进,并用兼容层与灰度控制风险。回答突出"不是整体重写,而是分层分批替换"即可展现务实经验。

#
★★

6. ArkWeb(Web 容器)加载 H5 的机制与 JSBridge 双向通信(registerJavaScriptProxy 注入与回调)

ArkWeb 加载 H5 页面的机制是怎样的?原生与 H5 之间如何通过 JSBridge 实现双向通信,其中 registerJavaScriptProxy 的作用与注意事项是什么?

  • ArkWeb(基于 Chromium)的加载机制与 WebView 演进
  • registerJavaScriptProxy 注入原生方法供 JS 调用及回调机制
  • 安全与生命周期注意事项(注入时机、对象生命周期、校验)

ArkWeb 是鸿蒙基于 Chromium 内核的 Web 容器,通过 loadUrl 加载 H5,页面渲染与 JS 执行在 Web 内核中完成,与原生层(ArkTS)通过 JSBridge 桥接。原生调 H5:通过 runJavaScript/evaluateJavaScript 执行 JS 并拿回调结果;H5 调原生:通过 controller.registerJavaScriptProxy 把原生对象(如 bridgeObj)注册为 JS 全局对象,H5 中直接调用 bridgeObj.method(args),原生方法执行后可把结果回传(如再次调用 JS 回调函数或在方法返回值中回传,再通过 runJavaScript 通知 H5)。该方法注册后还需调用 refresh 或等页面加载后注入才生效,且有注入生效时机(页面加载前注册)的约束。

注意事项:一是安全,注入对象暴露给页面 JS,必须对入参做合法性校验、限制危险能力,并控制注入对象的生命周期(页面销毁前 unregisterJavaScriptProxy);二是性能,桥接调用涉及跨进程/跨线程序列化,高频调用应批量合并参数;三是异步语义,原生方法的回调要正确处理时序,避免页面已销毁后仍回调导致崩溃。

双向通信的关键是分清两条链路:原生→JS 用 runJavaScript 执行表达式,JS→原生用 registerJavaScriptProxy 注入全局对象。回答时先讲加载机制,再分别讲两条链路与回调实现,最后补安全与生命周期约束,即完整覆盖考点。

#
★★

7. 既有 Web 前端应用迁移到 ArkTS/ArkUI 的路径(H5 套壳 / 逐页原生化 / Taro/uni-app 编译)与成本评估

既有 Web 前端应用迁移到鸿蒙 ArkTS/ArkUI 有哪些可行路径?各路径的成本与收益如何评估?

  • 三种迁移路径:H5 套壳(ArkWeb)、逐页原生化、Taro/uni-app 编译
  • 各路径在体验、性能、维护成本上的权衡
  • 迁移决策的评估维度(页面复杂度、团队技术栈、迭代频率)

主要路径有三条。路径一:H5 套壳——用 ArkWeb 直接加载现有 H5,通过 JSBridge 桥接原生能力,成本最低、上线最快,但体验受 Web 渲染限制(滚动、动效、内存),适合低频工具页或过渡期;路径二:逐页原生化——用 ArkTS/ArkUI 重写核心页面,提供原生交互与性能,其余页面继续 H5,按流量与体验收益排序逐页替换,改造成本随页面复杂度上升;路径三:Taro/uni-app 编译——若项目已用这类跨端框架,通过鸿蒙编译目标直接产出 ArkTS/ArkUI 工程,复用大部分业务代码,但受框架对鸿蒙适配成熟度限制,复杂自定义组件与原生能力仍需手写。

成本评估应围绕四个维度:人力成本(ArkTS 学习曲线、重写工作量)、性能与体验收益(首屏、滚动、动效)、维护成本(双栈并行 vs 单一栈)、风险(框架适配缺口、系统能力差异)。实务上常用组合拳:以路径三(若技术栈匹配)或路径一起步保功能,再按页面价值用路径二逐页收割体验收益,形成"先可用、再优化"的渐进迁移。

本题考查方案权衡而非单一答案:把三条路径按"成本从低到高、体验从弱到强"排序,并说明组合策略与评估维度,即体现工程决策能力。不要只罗列路径,要给出选择判据。

#
★★

8. ArkTS 与 TypeScript 的差异,静态类型与限制?

ArkTS 与标准 TypeScript 在静态类型层面有哪些差异与限制?为什么会存在这些限制?

  • ArkTS 是 TS 的子集,禁用了部分动态特性
  • 禁用结构化类型(开放类)、any/unknown 的约束、类型收窄限制
  • 限制的设计动机(性能与确定性、静态分析友好)

ArkTS 是 TypeScript 的严格子集,面向高性能 ArkUI 运行时做了裁剪。主要差异:一是禁用结构化类型(structural typing)的开放用法,类之间不通过"结构相同"自动兼容,必须显式声明继承或实现接口,对象字面量须有明确类型(不允许直接赋值给任意接口而不检查多余属性);二是弱化/禁用 any 与 unknown 的宽松使用,禁止通过 any 绕过类型检查,强制类型收窄(如联合类型需先判别再访问成员);三是限制了一些动态特性:函数需有显式返回类型、禁止无类型推导的隐式 any、不支持在对象字面量上随意添加属性、对泛型约束更严格等。

设计动机:ArkTS 运行在自带静态类型的 ArkUI 运行时上,强类型能保证编译期布局与状态系统(装饰器)的确定性,避免运行期动态派发带来的性能损耗;同时静态可分析性让工具链(混淆、摇树、跨语言优化)更安全。代价是写法的灵活性下降,部分 JS 生态库(依赖 any/动态 this 的库)需要封装适配层。

答题从"ArkTS 是 TS 子集"出发,列举具体限制(结构化类型、any、类型收窄),并说明动机(运行时性能与静态可分析性),最后提适配代价,即完整。关键是举例具体而非泛泛说"更严格"。

#
★★

9. ArkUI 声明式开发与命令式开发的核心差异与适用场景

ArkUI 声明式开发与传统命令式开发的核心差异是什么?各自适合什么场景?

  • 声明式:描述"UI 是什么"、数据驱动更新
  • 命令式:描述"怎么做"、手动操作节点
  • 各自适用场景与团队协作影响

声明式开发的核心是"声明状态与 UI 的映射关系":开发者描述"状态是什么、界面长什么样",框架自动在状态变化时更新界面;命令式开发的核心是"描述操作步骤":开发者通过 API 获取控件实例,手动设置属性、更新内容、处理事件,UI 与数据之间没有自动绑定。ArkUI 采用声明式:@State 状态变化自动触发组件刷新,代码表达的是界面结构与数据流的声明,而非"先取节点再改属性"的步骤序列。

适用场景上:声明式适合状态复杂、交互频繁、界面结构多变的业务应用(组件化、可测试、并发协作友好,UI 是状态函数,回归风险低);命令式适合对性能与底层控制要求极高的场景(如游戏渲染、复杂自定义绘制、引擎类开发),因为可以精确控制每一步操作、避免框架依赖追踪开销。工程上两者常并存:业务 UI 用声明式,需要细粒度性能控制的部分(如 Canvas、动画帧循环)退化为命令式。选择时主要看"状态驱动的程度"与"对自动化的信任"。

核心对比维度是"声明 vs 步骤"与"自动绑定 vs 手动控制":先定义两者的语义差异,再讲各自适合的状态复杂度与性能敏感场景,最后指出可并存。回答体现"框架做了多少、开发者管多少"的分工思考即可。

#
★★

10. @State/@Prop/@Link/@Provide/@Consume 装饰器的数据流向与刷新范围

ArkUI 中 @State、@Prop、@Link、@Provide、@Consume 各自的数据流向与刷新范围是什么?使用时有什么注意点?

  • 各装饰器的作用域与数据流方向(单向/双向/跨层级)
  • @Prop 单向同步、@Link 双向同步、@Provide/@Consume 跨层传递
  • 刷新范围与使用注意点(深拷贝、初始化、装饰类型限制)

@State 是组件内部的状态变量,组件自己持有与修改,是声明式 UI 的数据源头;@Prop 用于父传子,父组件把值单向传给子组件,子组件内部修改 @Prop 不会同步回父组件(父子之间是值的单向同步,父更新时子刷新);@Link 实现父子双向同步,子组件修改后父组件随之刷新(通过引用关联,而非拷贝);@Provide/@Consume 用于跨层级(祖先-后代)传递:祖先用 @Provide 提供数据,任意层级后代用 @Consume 接收,实现跨组件的数据共享(后代修改 @Consume 会同步回提供者,实现双向同步)。@StorageLink/@StorageProp 则与 AppStorage 全局存储关联,跨页面共享。

刷新范围方面:@State 变化只刷新绑定该状态的组件;@Prop 是值的单向拷贝,子组件刷新但父组件不受影响;@Link 是引用同步,任何一侧变化都刷新两侧绑定组件;@Provide 变化会刷新所有 @Consume 该数据的后代。注意点:@Prop 传递的是拷贝值(对象为深拷贝语义,大数据慎用);@Link 要求传入的是状态变量本身;@Provide/@Consume 的 key 要全局唯一避免冲突;不支持装饰函数返回值或复杂计算属性,仅支持基础类型、对象、数组等。

答题框架按"作用域 + 方向 + 刷新范围"逐装饰器展开:@State 组件内、@Prop 父→子单向、@Link 父子双向、@Provide/@Consume 跨层共享,并补充 @StorageLink 的跨页面能力。再补使用注意点即可覆盖全部考点。

#
★★

11. ArkUI 状态管理 V2(@ObservedV2/@Trace)相比 V1 的细粒度更新优势

ArkUI 状态管理 V2(@ObservedV2/@Trace)相比 V1(@Observed/@ObjectLink)有哪些细粒度更新优势?适用场景是什么?

  • V1 的 @Observed/@ObjectLink 的类级观测与整类刷新问题
  • V2 的 @ObservedV2/@Trace 的属性级观测与精确刷新
  • V2 的工程收益(性能、代码简洁性)与迁移注意

V1 中 @Observed 装饰类后,@ObjectLink 观测的是整个类:类内任何一个属性变化都会导致所有引用该对象的组件整体刷新,且数组元素变化需要嵌套 @Observed 类才能被追踪,粒度粗、样板代码多。V2(@ObservedV2 + @Trace)把观测粒度细化到属性:@Trace 标记的单个属性变化时,仅刷新绑定该属性的 UI(依赖收集精确到属性),未标记的属性变化不会触发刷新,从而避免"改一个字段、整页重渲染"的浪费。

优势上:一是刷新粒度从"类"降到"属性",复杂对象模型下渲染开销显著下降;二是支持普通类与对象字面量(V1 要求类需 @Observed 装饰且通过 @ObjectLink 引用),数据模型定义更自由简洁;三是数组、Map、Set 等集合类也有属性级/元素级追踪能力,配合 UI 组件可减少不必要的重建。适用场景:数据模型深、字段多、高频局部更新的页面(如表格、长表单、画布属性面板)。迁移时注意:V2 与 V1 装饰器不能混用在同一数据链路中,且 @Trace 只追踪标记属性,未标记字段变化不触发 UI 更新,需要开发者明确数据与 UI 的绑定关系。

抓住"V1 类级观测整类刷新 vs V2 属性级观测精确刷新"这一核心差异,再展开 V2 在模型自由度、集合支持上的优势与迁移注意点,即可完整覆盖。强调"@Trace 只追踪标记属性"是理解 V2 的关键。

#
★★

12. Stage 模型与 FA 模型的核心差异及新应用优先选用 Stage 的原因

鸿蒙 Stage 模型与 FA 模型的核心差异是什么?为什么新应用优先选用 Stage 模型?

  • Stage 的 UIAbility 组件化、模块化与权限模型
  • FA 的 PageAbility 与轻量组件模型的局限
  • Stage 对工程化、后台运行与安全模型的改进

FA 模型(Feature Ability)以 PageAbility 为基本单元,页面与组件耦合较紧,多个 PageAbility 难以共享复杂上下文,权限与后台运行管理粗放,适合早期轻量应用。Stage 模型把"应用"与"组件"分离:应用由多个 UIAbility(页面入口)、ExtensionAbility(扩展能力)和 Module(HAP/HAR/HSP)组成,每个 Ability 有独立上下文与生命周期,组件可跨 Ability 复用,模块可独立开发、测试与发布。

核心差异:一是组件化与模块化——UIAbility 之间通过显式/隐式 Want 通信,模块边界清晰,支持多 HAP 按需分发;二是权限模型——Stage 采用按需申请、运行时可动态授予的权限体系,更接近现代系统;三是后台与生命周期管控——Stage 明确前后台切换、onBackground 挂起等规则,限制后台行为,配合系统统一管控;四是上下文(Context)模型统一,方便获取资源、启动 Ability 与申请权限。新应用优先选 Stage:它面向多设备协同、按需加载与安全管控设计,是官方演进方向,FA 已被逐步弱化,新建工程默认 Stage,社区与工具链支持也更完善。

用"组件化/模块化、权限与后台管控、Context 统一"三个差异点对比 FA,再说明 Stage 是面向现代多设备与合规管控设计的演进方向,即可回答"为什么优先"。重点体现"Ability 与 Module 分离"带来的工程收益。

#
★★

13. UIAbility 与 ExtensionAbility 的职责边界与启动模式

UIAbility 与 ExtensionAbility 的职责边界是什么?各自有哪些典型启动模式(launchType)与使用场景?

  • UIAbility 面向用户交互、ExtensionAbility 面向系统能力扩展
  • launchType:standard/multiton、singleton、specified 的语义
  • 各自典型场景(前台页面 vs 后台任务/输入法/分享等)

UIAbility 是应用与用户交互的入口(相当于 Activity/Window),承载页面与用户操作,有完整的前后台生命周期,一个应用可有多个 UIAbility(如主界面、分享落地页);ExtensionAbility 是系统能力的扩展点(类似 Service/Provider),不直接展示 UI 或仅在特定 UI 容器中展示,包括 ServiceExtensionAbility(后台服务)、InputMethodExtensionAbility(输入法)、ShareExtensionAbility(分享)、AccessibilityExtensionAbility(无障碍)等,由系统按场景拉起并受系统管控。

启动模式(launchType)用于控制同一 UIAbility 被多次启动时的实例行为:standard(多实例,每次启动新建,适合需要独立栈的场景)、singleton(单实例,复用已有实例并触发 onNewWant,适合主界面类入口)、specified(按业务特征键区分实例,如"不同账号各一个实例"),由 AbilityStage 中的 resolve 逻辑决定。ExtensionAbility 的拉起由系统管理(如用户选择分享目标、输入法被唤起),应用侧需遵循其生命周期回调(onCreate/onDestroy 等)与后台限制规则。

先按"用户交互 vs 系统扩展"划分职责,再分别展开 UIAbility 的三种 launchType 语义与 ExtensionAbility 的典型类型,即可覆盖。理解 singleton 的 onNewWant 复用机制与 specified 的多键实例是得分点。

#
★★

14. ArkTS 相比 TypeScript 的限制(禁结构化类型/强类型声明)及其设计动机

ArkTS 相比 TypeScript 在类型声明上做了哪些限制(如禁止结构化类型、强类型声明)?这些限制的设计动机是什么?

  • 禁止开放结构化类型、类需显式继承/实现
  • 强类型声明:禁止 any 逃逸、类型收窄要求
  • 设计动机:运行时确定性、性能优化与静态工具链

ArkTS 的强类型限制主要体现在:禁止"开放类"与隐式结构化类型兼容——两个没有继承关系的类即使结构完全相同也不能互相赋值,对象字面量必须与目标类型完全匹配(多余属性报错),类只能通过显式 implements/extends 建立类型关系;禁止 any/unknown 的宽松逃逸——不允许把变量声明为 any 绕过检查、不允许隐式 any(参数必须标注类型),联合类型成员访问前必须收窄;此外还限制对象动态加属性、限制泛型推断的模糊用法、要求函数显式声明返回类型等。这些都让 ArkTS 成为"可静态全量分析"的类型系统。

设计动机有三:一是运行时性能——ArkUI 的状态系统与渲染引擎需要确定性的数据布局,结构化类型的动态兼容会在运行期引入类型派发与装箱开销,强类型让编译器能做内联与内存布局优化;二是正确性——声明式 UI 中状态与界面的绑定依赖精确的类型信息,模糊类型会导致依赖收集出错;三是工具链安全——混淆、摇树、跨语言编译(AOT)都依赖完整类型信息,禁用逃逸机制保证变换不破坏语义。代价是 TS 生态中依赖反射、动态派发的库需要适配层。

回答分两层:先列举限制(禁结构化类型兼容、禁 any、强制收窄与标注),再解释动机(性能、正确性、工具链安全)。关键是说明"强类型服务于运行时与编译期优化",而非单纯收窄开发者自由。

#
★★

15. ArkUI 中 @StorageLink 与 AppStorage/LocalStorage 的跨组件共享机制

ArkUI 中 AppStorage 与 LocalStorage 的作用是什么?@StorageLink/@StorageProp 是如何实现跨组件甚至跨页面数据共享的?

  • AppStorage 全局单例存储与 LocalStorage 页面级存储的定位
  • @StorageLink(双向)与 @StorageProp(单向)的绑定语义
  • 跨组件/跨页面共享的机制与使用注意

AppStorage 是应用级全局存储单例,存于应用进程,可被所有 UIAbility 页面共享,适合存登录态、主题、全局配置等;LocalStorage 是页面级(Ability 级)存储,由页面显式创建并在加载 UIAbility 时传入,供该页面的组件树共享,页面销毁即释放。两者都基于"键值 + 属性变化监听"的机制工作:@StorageLink 把组件状态变量与 AppStorage/LocalStorage 中的键双向绑定,存储值变化时组件刷新、组件修改时回写存储;@StorageProp 只做单向绑定(存储→组件),组件内部修改不写回。

跨组件共享的机制:组件树中任意位置的组件只要用 @StorageLink("@key") 绑定同一 key,就共享同一份数据,任何一方修改都会通过存储的监听器通知其他绑定组件刷新,实现"发布-订阅"式的跨层级同步;配合 @Provide/@Consume 可做局部跨层共享,而跨页面共享必须用 AppStorage(LocalStorage 只在其所属页面内有效)。注意:key 需全局唯一避免冲突;对象类型的数据建议用持久化(PersistentStorage)配合;不要滥用全局存储,高频临时数据优先组件内状态,避免不必要的全局刷新。

先区分 AppStorage(全局)与 LocalStorage(页面级)的作用域,再讲 @StorageLink/@StorageProp 的双向/单向绑定语义与"发布-订阅"刷新机制,最后补充使用注意(key 唯一、作用域选择),即构成完整答案。

#
★★

16. ArkUI ForEach 的 keyGenerator 为何不能省略及其性能影响

ArkUI ForEach 渲染列表时为什么必须提供 keyGenerator?省略或不正确生成 key 会带来什么性能与正确性问题?

  • key 用于复用/区分列表项组件实例
  • 省略 key 时全量重建的性能问题与状态错乱
  • key 生成规则(稳定、唯一、数据相关)

ForEach 渲染列表时为每个数据项生成一个 key,框架用 key 判断列表项是"复用、新增还是删除":key 相同则复用已有组件实例并更新数据,key 变化才重建。若省略 keyGenerator,框架无法建立"数据项-组件实例"的稳定映射,列表任何变化(增删、排序、数据刷新)都可能触发全量重建,滚动位置丢失、列表项内部状态(如输入框内容、滚动位置)错乱,大数据量下性能急剧恶化。

正确的 key 生成规则:必须稳定(数据不变时 key 不变)、唯一(同列表内不重复)、与数据内容相关(如 id 字段),避免使用数组下标(增删后下标错位导致复用错乱)或随机数(每次刷新都重建)。当数据项结构稳定且变更只发生在尾部时,可以省略 key(此时按下标复用),但一旦存在插入、删除、排序,就必须提供基于业务唯一标识的 keyGenerator。这也是 React/Vue 中 key 语义的同一原则在 ArkUI 的体现。

核心是"key 决定组件实例的复用与重建",从正确性(状态错乱)与性能(全量重建)两个角度说明省略后果,并给出 key 的三条规则(稳定、唯一、数据相关)与下标 key 的坑,即可完整覆盖。

#

17. ArkUI-X 与 React Native/Flutter 在跨端能力、渲染一致性与生态上的取舍

ArkUI-X 与 React Native、Flutter 在跨端能力、渲染一致性、生态三个维度上有何取舍?什么场景下更适合选择 ArkUI-X?

  • ArkUI-X 直接复用 ArkUI 声明式框架扩展到多端
  • RN 的 JS 桥接与 Flutter 的自绘渲染特点
  • 渲染一致性、性能、生态成熟度的权衡

ArkUI-X 是华为推出的跨端框架,把 ArkUI 声明式能力扩展到 Android/iOS 等其他平台(编译时把 ArkTS 映射为各平台原生实现),与鸿蒙生态天然同源,鸿蒙端体验最一致;React Native 以 JS/React 驱动原生视图(View/Text 映射为原生组件),生态与 JS 社区最大,但渲染一致性依赖各平台原生组件差异;Flutter 用 Dart 自绘渲染(Skia/Impeller),不依赖原生控件,像素级一致性与动画性能强,但语言与 UI 模型自成体系。

取舍上:渲染一致性 Flutter 最优(自绘)、ArkUI-X 其次(鸿蒙一致、其他平台靠原生映射)、RN 最弱(需处理平台差异);生态成熟度 RN 与 Flutter 远超 ArkUI-X;性能上 Flutter 自绘在复杂动画有优势,ArkUI-X 在鸿蒙上因同源而最优。选择建议:主战场在鸿蒙、希望一套代码覆盖多端且团队以 ArkTS 为主 → ArkUI-X;重 JS 生态与快速迭代 → RN;重跨端一致性与品牌级 UI → Flutter。跨端方案都要接受"能力抽象层"对平台独有能力的裁剪,并用条件编译/插件机制补齐。

按"跨端能力、渲染一致性、生态"三个维度两两对比,落到"选择取决于主战场与团队栈"的结论即可。用一句话总结三者的本质(同源扩展 vs 原生桥接 vs 自绘)是答题骨架。

#

18. 鸿蒙的分布式能力,跨设备协同与流转?

鸿蒙的分布式能力如何实现跨设备协同与任务流转?前端开发如何接入这些能力?

  • 分布式软总线、分布式数据与分布式任务的架构支撑
  • 跨设备流转(continuation)与协同(多设备协作)的实现
  • 前端接入方式(流转 API、分布式数据同步)与场景

鸿蒙分布式能力由"分布式软总线 + 分布式数据管理 + 分布式任务调度"构成:分布式软总线让多设备在局域网内自动组网、低延迟通信;分布式数据管理让应用数据在不同设备间同步(如跨端读写同一 KV/关系库,或通过分布式对象实时同步状态);分布式任务调度支持把一个 UIAbility 从一个设备迁移/流转到另一个设备继续运行(如手机视频流转到平板/电视大屏)。跨设备协同典型场景包括:多端接力(continuation,用户操作一个动作后任务迁移)、跨端资源共享(手机摄像头给电视用)、多设备协同办公(手机与 PC 编辑同一文档)。

前端接入方式:使用系统能力 API(如 continuationManager 实现流转,分布式数据 SDK 做数据同步,wantAgent 拉起其他设备的 Ability),配合流转条件判断(设备在线、同账号、同局域网);协同类应用需设计"主设备 + 从设备"的角色模型与状态同步协议,并处理断连恢复。设计时注意:流转要求数据可序列化、页面状态可重建;跨端权限需用户授权与同账号校验;要处理网络抖动与设备离线降级。

从"软总线-数据-任务"三层架构讲清楚分布式底座,再落到流转与协同两类场景及其 API 接入,最后补数据序列化与断连处理的工程约束,即完整。重点是区分"流转(任务迁移)"与"协同(多设备并行)"两种形态。