零基础鸿蒙应用开发第五节:基础数据类型对象与类型转换

零基础鸿蒙应用开发学习计划表

【学习目标】

  1. 理解原始值与内置对象的核心区别,掌握NumberStringBoolean内置对象的初始化方式
  2. 熟练使用内置对象的高频内置方法(数值格式化、字符串截取/查找、布尔值转换)解决实际问题
  3. 掌握强类型环境下的显式类型转换技巧(数值↔字符串、数值↔布尔、字符串↔布尔)
  4. 能处理null/undefined的边界场景,避免转换时出现异常
  5. 理解内置对象的装箱/拆箱特性,明确ArkTS强类型下需显式拆箱的通用规则

【学习重点】

  1. 核心区别:原始值(number/string/boolean)与内置对象(Number/String/Boolean)的本质差异
  2. 方法使用:内置对象的高频内置方法(如toFixedsliceincludes)的语法与场景
  3. 类型转换:显式转换的多种实现方式(推荐方法+避坑方案)
  4. 边界处理null/undefined参与转换时的安全处理策略
  5. 强类型拆箱:ArkTS需显式调用valueOf()拆箱后,才能将内置对象与原始值运算
  6. 实战应用:结合内置对象与类型转换完成数值计算、文本处理的基础需求

一、工程结构

本节我们将创建名为WrapperTypeConvertDemo的工程,基于鸿蒙5.0(API12)开发,使用DevEco Studio 6.0+工具,项目结构目录如下:

WrapperTypeConvertDemo
├── AppScope                 # 应用全局配置
├── entry                    # 主模块目录
│   ├── src
│   │   ├── main
│   │   │   ├── ets          # ArkTS核心代码目录
│   │   │   │   ├── entryability   # 应用入口能力
│   │   │   │   ├── pages          # 页面组件目录
│   │   │   │   │   └── Index.ets  # 核心页面(调用工具函数)
│   │   │   │   └── utils          # 工具函数目录
│   │   │   │       └── WrapperTypeConvertTest.ets # 本节所有学习内容
│   │   │   ├── resources        # 静态资源(图片/字符串等)
│   │   │   └── module.json5     # 模块配置文件
│   │   ├── ohosTest         # 鸿蒙端测试目录
│   │   └── test             # 单元测试目录
│   ├── build-profile.json5  # 构建配置
│   ├── hvigorfile.ts        # 构建脚本
│   └── oh-package.json5     # 依赖配置
├── hvigor                   # 构建工具依赖
└── oh_modules               # 第三方依赖包

开发准备步骤

  1. 打开DevEco Studio,创建WrapperTypeConvertDemo项目(选择Empty Ability模板,API12/鸿蒙5.0);
  2. src/main/ets目录下右键创建utils文件夹;
  3. 选中utils文件夹,右键创建WrapperTypeConvertTest.ets文件(封装所有学习内容);
  4. 所有学习函数在Index.etsaboutToAppear生命周期中统一调用。

二、原始值与内置对象的核心概念

1.1 核心区别

类型 本质 示例 特性
原始值 基本数据类型的直接值 const num = 10 不可变、本身无属性/方法(但可临时调用内置对象方法,因自动装箱为包装对象)
内置对象 引用类型的实例对象 const numObj = new Number(10) 可变、有属性/方法

1.2 装箱与拆箱

  • 装箱:分为「自动装箱」和「手动装箱」
    • 自动装箱:当原始值调用内置对象的方法时,ArkTS会自动创建对应的内置对象,方法执行后销毁该对象(如10.toString());
    • 手动装箱:通过new Number(10)/new String("ArkTS")创建内置对象(不推荐,仅用于演示)。
  • 拆箱:调用内置对象的valueOf()方法获取原始值,才能与对应原始值运算:
    • ✅ 正确:numObj.valueOf() + 5(先拆箱再运算);
    • ❌ 错误:numObj + 5(类型不一致,编译报错)。
  • 开发建议:优先使用原始值,仅在需要调用内置对象方法时依赖自动装箱,禁止手动创建内置对象(冗余且性能低)。

1.3 代码封装:原始值与内置对象的区别

// src/main/ets/utils/WrapperTypeConvertTest.ets
/**
 * 学习原始值与内置对象的核心区别、装箱与拆箱特性
 */
export function testPrimitiveAndWrapper(): void {
  // 1. 原始值(推荐使用)
  const numPrimitive: number = 10;
  const strPrimitive: string = "ArkTS";
  const boolPrimitive: boolean = true;
  console.log(`【原始值】类型检测:${typeof numPrimitive} → ${numPrimitive}`); // number → 10
  console.log(`【原始值】类型检测:${typeof strPrimitive} → ${strPrimitive}`); // string → ArkTS
  console.log(`【原始值】类型检测:${typeof boolPrimitive} → ${boolPrimitive}`); // boolean → true

  // 2. 内置对象(不推荐手动创建,仅演示)
  const numObj: Number = new Number(10);
  const strObj: String = new String("ArkTS");
  const boolObj: Boolean = new Boolean(true);
  console.log(`\n【内置对象】类型检测:${typeof numObj} → ${numObj}`); // object → 10
  console.log(`【内置对象】类型检测:${typeof strObj} → ${strObj}`); // object → ArkTS
  console.log(`【内置对象】类型检测:${typeof boolObj} → ${boolObj}`); // object → true

  // 3. 自动装箱:原始值调用内置对象方法
  const numStr: string = numPrimitive.toString(); // 自动创建Number对象
  console.log(`\n【自动装箱】10.toString() → ${numStr}(类型:${typeof numStr})`); // 10 → string

  // 4. 显式拆箱
  const sum: number = numObj.valueOf() + 5; 
  console.log(`【显式拆箱】numObj.valueOf() + 5 → ${sum}(类型:${typeof sum})`); // 15 → number
}

1.4 运行效果

【原始值】类型检测:number → 10
【原始值】类型检测:string → ArkTS
【原始值】类型检测:boolean → true

【内置对象】类型检测:object → 10
【内置对象】类型检测:object → ArkTS
【内置对象】类型检测:object → true

【自动装箱】10.toString() → 10(类型:string)
【显式拆箱】numObj.valueOf() + 5 → 15(类型:number)

三、Number内置对象的高频内置方法

Number内置对象的方法主要用于数值格式化、数值判断,原始值可通过自动装箱调用这些方法。

3.1高频方法列表

方法名 作用 示例 结果
toString(base) 将数值转为字符串,base为进制(2-36,默认10) 10.toString(2) "1010"
toFixed(digits) 保留指定小数位数(四舍五入),digits为小数位数(0-20) 3.14159.toFixed(2) "3.14"
toPrecision(len) 保留指定有效数字(四舍五入),len为有效数字位数(1-21) 123.45.toPrecision(3) "123"
Number.parseInt(str, base) 全局方法:将字符串转为整数(进制可选) Number.parseInt("123a") 123
Number.parseFloat(str) 全局方法:将字符串转为浮点数 Number.parseFloat("123.45a") 123.45
Number.isInteger(num) 静态方法:判断是否为整数 Number.isInteger(10.0) true
Number.isNaN(num) 静态方法:判断是否为NaN(仅对NaN返回true) Number.isNaN(10/0) false(Infinity不是NaN)
valueOf() 显式拆箱:获取Number对象对应的原始数值 new Number(10).valueOf() 10

3.2 代码封装:Number内置对象的方法

// src/main/ets/utils/WrapperTypeConvertTest.ets
/**
 * 学习Number内置对象的高频内置方法(数值格式化、字符串转数值、数值判断)
 * 新手避坑:toFixed返回字符串,运算前需转数值
 */
export function testNumberWrapperMethods(): void {
  console.log(`\n========== Number内置对象方法 ==========`);
  const num: number = 3.1415926;
  const intNum: number = 100;
  const strNum: string = "123.456a";
  const numObj: Number = new Number(99.9); // 仅用于演示拆箱

  // 1. 数值格式化(高频)
  console.log(`【数值格式化】${num}.toFixed(2) → ${num.toFixed(2)}`); // 3.14(保留2位小数)
  console.log(`【数值格式化】${num}.toFixed(4) → ${num.toFixed(4)}`); // 3.1416(四舍五入)
  console.log(`【数值格式化】${num}.toPrecision(3) → ${num.toPrecision(3)}`); // 3.14(保留3位有效数字)
  console.log(`【数值格式化】${intNum}.toString(2) → ${intNum.toString(2)}`); // 1100100(二进制)
  console.log(`【数值格式化】${intNum}.toString(16) → ${intNum.toString(16)}`); // 64(十六进制)

  // 新手错误示例:toFixed返回字符串,直接运算会出错
  const price = 2999;
  const wrongTotal = price.toFixed(2) + 10; // "2999.0010"(非数值运算)
  const correctTotal = Number(price.toFixed(2)) + 10; // 3009.00
  console.log(`\n【错误示例】toFixed直接运算 → ${wrongTotal}`);
  console.log(`【正确写法】toFixed转数值后运算 → ${correctTotal}`);

  // 2. 字符串转数值(全局方法)
  console.log(`\n【字符串转数值】Number.parseInt("${strNum}") → ${Number.parseInt(strNum)}`); // 123
  console.log(`【字符串转数值】Number.parseFloat("${strNum}") → ${Number.parseFloat(strNum)}`); // 123.456
  console.log(`【字符串转数值】Number.parseInt("1010", 2) → ${Number.parseInt("1010", 2)}`); // 10(二进制转十进制)

  // 3. 数值判断(静态方法)
  console.log(`\n【数值判断】Number.isInteger(10) → ${Number.isInteger(10)}`); // true
  console.log(`【数值判断】Number.isInteger(10.5) → ${Number.isInteger(10.5)}`); // false
  console.log(`【数值判断】Number.isNaN(NaN) → ${Number.isNaN(NaN)}`); // true
  console.log(`【数值判断】Number.isNaN(10/0) → ${Number.isNaN(10/0)}`); // false(Infinity不是NaN)

  // 4. 显式拆箱示例
  console.log(`\n【显式拆箱】numObj.valueOf() + 0.1 → ${numObj.valueOf() + 0.1}`); // 100.0
}

3.3 运行效果

========== Number内置对象方法 ==========
【数值格式化】3.1415926.toFixed(2) → 3.14
【数值格式化】3.1415926.toFixed(4) → 3.1416
【数值格式化】3.1415926.toPrecision(3) → 3.14
【数值格式化】100.toString(2) → 1100100
【数值格式化】100.toString(16) → 64

【错误示例】toFixed直接运算 → 2999.0010
【正确写法】toFixed转数值后运算 → 3009

【字符串转数值】Number.parseInt("123.456a") → 123
【字符串转数值】Number.parseFloat("123.456a") → 123.456
【字符串转数值】Number.parseInt("1010", 2) → 10

【数值判断】Number.isInteger(10) → true
【数值判断】Number.isInteger(10.5) → false
【数值判断】Number.isNaN(NaN) → true
【数值判断】Number.isNaN(10/0) → false

【显式拆箱】numObj.valueOf() + 0.1 → 100.0

四、String内置对象的高频内置方法

String内置对象的方法是文本处理的核心,涵盖字符串截取、查找、替换、大小写转换等场景,原始值可通过自动装箱调用。

4.1 高频方法列表

方法名 作用 示例 结果
length(属性) 获取字符串长度 "ArkTS".length 5
charAt(index) 获取指定索引的字符(索引从0开始) "ArkTS".charAt(2) "k"
slice(start, end) 截取字符串(start起始索引,end结束索引(不包含),支持负数) "ArkTS".slice(1, 3) "rk"
substring(start, end) 截取字符串(与slice类似,不支持负数,start>end时自动交换) "ArkTS".substring(3, 1) "rk"
includes(substr) 判断是否包含子字符串(返回布尔值) "ArkTS".includes("TS") true
indexOf(substr) 查找子字符串首次出现的索引(未找到返回-1) "ArkTS".indexOf("k") 2
lastIndexOf(substr) 查找子字符串最后出现的索引(未找到返回-1) "ArkTSArkTS".lastIndexOf("k") 7
toUpperCase() 转为大写字符串 "ArkTS".toUpperCase() "ARKTS"
toLowerCase() 转为小写字符串 "ArkTS".toLowerCase() "arkts"
trim() 去除首尾空格(含换行符、制表符) " ArkTS ".trim() "ArkTS"
replace(old, new) 替换第一个匹配的子字符串(支持正则) "ArkTS ArkTS".replace("TS", "JS") "ArkJS ArkTS"
split(sep) 按分隔符分割为数组 "a,b,c".split(",") ["a","b","c"]
valueOf() 显式拆箱:获取String对象对应的原始字符串 new String("ArkTS").valueOf() "ArkTS"

4.2 代码封装:String内置对象的方法

// src/main/ets/utils/WrapperTypeConvertTest.ets
/**
 * 学习String内置对象的高频内置方法(文本处理核心)
 * 新手避坑:1. slice支持负数索引,优先使用;2. 索引越界返回空字符串,无报错
 */
export function testStringWrapperMethods(): void {
  console.log(`\n========== String内置对象方法 ==========`);
  const str: string = "  Hello ArkTS!  ";
  const simpleStr: string = "ArkTS";
  const strObj: String = new String("Test"); // 仅用于演示拆箱

  // 1. 基础属性与字符获取(高频)
  console.log(`【基础属性】"${simpleStr}".length → ${simpleStr.length}`); // 5
  console.log(`【字符获取】"${simpleStr}".charAt(2) → ${simpleStr.charAt(2)}`); // k(偶尔用)
  console.log(`【字符获取】"${simpleStr}"[2] → ${simpleStr[2]}`); // k(简化写法,推荐)

  // 新手错误示例:索引越界
  console.log(`\n【错误示例】charAt越界 → ${simpleStr.charAt(10)}`); // ""(无报错,返回空字符串)
  console.log(`【错误示例】slice越界 → ${simpleStr.slice(10)}`); // ""(无报错,返回空字符串)

  // 2. 字符串截取(高频)
  console.log(`\n【字符串截取】"${simpleStr}".slice(1, 3) → ${simpleStr.slice(1, 3)}`); // rk
  console.log(`【字符串截取】"${simpleStr}".slice(-2) → ${simpleStr.slice(-2)}`); // TS(倒数2个字符,推荐)
  console.log(`【字符串截取】"${simpleStr}".substring(3, 1) → ${simpleStr.substring(3, 1)}`); // rk(不推荐,无负数索引)

  // 3. 字符串查找(高频)
  console.log(`\n【字符串查找】"${simpleStr}".includes("TS") → ${simpleStr.includes("TS")}`); // true
  console.log(`【字符串查找】"${simpleStr}".indexOf("k") → ${simpleStr.indexOf("k")}`); // 2
  console.log(`【字符串查找】"${simpleStr}".indexOf("JS") → ${simpleStr.indexOf("JS")}`); // -1(未找到)

  // 4. 大小写转换与去空格(高频)
  console.log(`\n【大小写转换】"${simpleStr}".toUpperCase() → ${simpleStr.toUpperCase()}`); // ARKTS
  console.log(`【大小写转换】"${simpleStr}".toLowerCase() → ${simpleStr.toLowerCase()}`); // arkts
  console.log(`【去空格】"${str}".trim() → "${str.trim()}"`); // Hello ArkTS!

  // 5. 替换与分割(高频)
  console.log(`\n【字符串替换】"ArkTS ArkTS".replace("TS", "JS") → ${"ArkTS ArkTS".replace("TS", "JS")}`); // ArkJS ArkTS
  console.log(`【字符串分割】"a,b,c".split(",") → ${JSON.stringify("a,b,c".split(","))}`); // ["a","b","c"]
  console.log(`【字符串分割】"a|b|c".split("|") → ${JSON.stringify("a|b|c".split("|"))}`); // ["a","b","c"]

  // 6. 显式拆箱示例
  console.log(`\n【显式拆箱】strObj.valueOf() + "123" → ${strObj.valueOf() + "123"}`); // Test123
}

4.3 运行效果

========== String内置对象方法 ==========
【基础属性】"ArkTS".length → 5
【字符获取】"ArkTS".charAt(2) → k
【字符获取】"ArkTS"[2] → k

【错误示例】charAt越界 → 
【错误示例】slice越界 → 

【字符串截取】"ArkTS".slice(1, 3) → rk
【字符串截取】"ArkTS".slice(-2) → TS
【字符串截取】"ArkTS".substring(3, 1) → rk

【字符串查找】"ArkTS".includes("TS") → true
【字符串查找】"ArkTS".indexOf("k") → 2
【字符串查找】"ArkTS".indexOf("JS") → -1

【大小写转换】"ArkTS".toUpperCase() → ARKTS
【大小写转换】"ArkTS".toLowerCase() → arkts
【去空格】"  Hello ArkTS!  ".trim() → "Hello ArkTS!"

【字符串替换】"ArkTS ArkTS".replace("TS", "JS") → ArkJS ArkTS
【字符串分割】"a,b,c".split(",") → ["a","b","c"]
【字符串分割】"a|b|c".split("|") → ["a","b","c"]

【显式拆箱】strObj.valueOf() + "123" → Test123

五、Boolean内置对象的核心方法

Boolean内置对象的方法较少,核心作用是将其他类型值转为布尔值,常用Boolean()全局函数(而非手动创建内置对象)。

5.1 布尔值转换规则

值示例 类型 转换结果 新手易错点
0 number false -
10 number true -
"" string false -
"0" string true 误以为和数值0一样是false
"false" string true 误以为内容是false就转false
null null false -
undefined undefined false -
[] array true 空数组不是false
NaN number false NaN是特殊的falsy值
Infinity number true 无穷大不是false

5.2 核心方法

方法名 作用 示例 结果
valueOf() 显式拆箱:获取Boolean对象对应的原始布尔值 new Boolean(true).valueOf() true

5.3 代码封装:Boolean内置对象与布尔值转换

// src/main/ets/utils/WrapperTypeConvertTest.ets
/**
 * 学习Boolean内置对象的核心方法与布尔值转换规则
 * 新手避坑:1. 空数组/空对象转布尔为true;2. "0"转布尔为true;3. !!与Boolean()效果一致
 */
export function testBooleanWrapperMethods(): void {
  console.log(`\n========== Boolean内置对象与转换 ==========`);
  const bool: boolean = false;
  const boolObj: Boolean = new Boolean(true); // 仅用于演示拆箱

  // 1. 内置对象方法(极少使用)
  console.log(`【Boolean方法】${bool}.toString() → ${bool.toString()}`); // false
  console.log(`【Boolean方法】${!bool}.toString() → ${(!bool).toString()}`); // true

  // 2. 其他类型转布尔值(推荐使用Boolean()全局函数)
  console.log(`\n【布尔转换】Boolean(0) → ${Boolean(0)}`); // false | 数值0是falsy值
  console.log(`【布尔转换】Boolean(10) → ${Boolean(10)}`); // true | 非0数值是truthy值
  console.log(`【布尔转换】Boolean("") → ${Boolean("")}`); // false | 空字符串是falsy值
  console.log(`【布尔转换】Boolean("0") → ${Boolean("0")}`); // true | 非空字符串(新手高频坑)
  console.log(`【布尔转换】Boolean("false") → ${Boolean("false")}`); // true | 非空字符串(新手高频坑)
  console.log(`【布尔转换】Boolean(null) → ${Boolean(null)}`); // false | null是falsy值
  console.log(`【布尔转换】Boolean(undefined) → ${Boolean(undefined)}`); // false | undefined是falsy值
  console.log(`【布尔转换】Boolean([]) → ${Boolean([])}`); // true | 空数组是truthy值(新手高频坑)

  // 3. 双重取反(!!)快速转布尔值
  console.log(`\n【双重取反】!!0 → ${!!0}`); // false | 等价于Boolean(0)
  console.log(`【双重取反】!!"ArkTS" → ${!!"ArkTS"}`); // true | 等价于Boolean("ArkTS")
  console.log(`【双重取反】!!null → ${!!null}`); // false | 等价于Boolean(null)

  // 4. 显式拆箱示例
  console.log(`\n【显式拆箱】boolObj.valueOf() && false → ${boolObj.valueOf() && false}`); // false
}

5.4 运行效果

========== Boolean内置对象与转换 ==========
【Boolean方法】false.toString() → false
【Boolean方法】true.toString() → true

【布尔转换】Boolean(0) → false
【布尔转换】Boolean(10) → true
【布尔转换】Boolean("") → false
【布尔转换】Boolean("0") → true
【布尔转换】Boolean("false") → true
【布尔转换】Boolean(null) → false
【布尔转换】Boolean(undefined) → false
【布尔转换】Boolean([]) → true

【双重取反】!!0 → false
【双重取反】!!"ArkTS" → true
【双重取反】!!null → false

【显式拆箱】boolObj.valueOf() && false → false

六、强类型环境下的显式类型转换

ArkTS均禁止隐式类型转换,所有类型转换必须显式进行,以下是常用类型的转换方法(推荐方案+避坑方案)。

(一)数值与字符串的相互转换

1. 数值转字符串(2种推荐方法)

  • 方法1:num.toString()(原始值自动装箱)
  • 方法2:String(num)(处理null/undefined时更安全)

2. 字符串转数值(2种推荐方法)

  • 方法1:Number(str)(严格转换,非数值字符串返回NaN)
  • 方法2:Number.parseInt(str)/Number.parseFloat(str)(宽松转换,截取数字部分)

代码逻辑封装:数值↔字符串转换

// src/main/ets/utils/WrapperTypeConvertTest.ets
/**
 * 学习数值与字符串的显式类型转换(强类型环境推荐方案)
 */
export function testNumberStringConversion(): void {
  console.log(`\n========== 数值↔字符串转换 ==========`);
  const num1: number = 123;
  const str1: string = "456";
  const str2: string = "789a";
  const str3: string = "abc";

  // 1. 数值转字符串
  const numToStr1: string = num1.toString();
  const numToStr2: string = String(num1);
  console.log(`【数值转字符串】${num1}.toString() → ${numToStr1}(类型:${typeof numToStr1})`); // 123 → string
  console.log(`【数值转字符串】String(${num1}) → ${numToStr2}(类型:${typeof numToStr2})`); // 123 → string

  // 2. 字符串转数值
  const strToNum1: number = Number(str1);
  const strToNum2: number = Number.parseInt(str2);
  const strToNum3: number = Number(str3);
  console.log(`\n【字符串转数值】Number("${str1}") → ${strToNum1}(类型:${typeof strToNum1})`); // 456 → number
  console.log(`【字符串转数值】Number.parseInt("${str2}") → ${strToNum2}(类型:${typeof strToNum2})`); // 789 → number
  console.log(`【字符串转数值】Number("${str3}") → ${strToNum3}(类型:${typeof strToNum3})`); // NaN → number
}

运行效果

========== 数值↔字符串转换 ==========
【数值转字符串】123.toString() → 123(类型:string)
【数值转字符串】String(123) → 123(类型:string)

【字符串转数值】Number("456") → 456(类型:number)
【字符串转数值】Number.parseInt("789a") → 789(类型:number)
【字符串转数值】Number("abc") → NaN(类型:number)

(二)数值/字符串与布尔值的相互转换

1. 数值/字符串转布尔值(2种推荐方法)

  • 方法1:Boolean(value)(遵循布尔转换规则)
  • 方法2:!!value(简化写法,效果与Boolean()一致)

2. 布尔值转数值/字符串(直接转换)

  • 布尔值转数值:Number(bool)(true→1,false→0)
  • 布尔值转字符串:bool.toString()(true→"true",false→"false")

代码逻辑封装:数值/字符串↔布尔值转换

// src/main/ets/utils/WrapperTypeConvertTest.ets
/**
 * 学习数值/字符串与布尔值的显式类型转换
 */
export function testBooleanConversion(): void {
  console.log(`\n========== 数值/字符串↔布尔值转换 ==========`);
  const num2: number = 0;
  const num3: number = 10;
  const str4: string = "";
  const str5: string = "false";
  const bool2: boolean = true;

  // 1. 数值/字符串转布尔值
  console.log(`【数值转布尔】Boolean(${num2}) → ${Boolean(num2)}`); // false
  console.log(`【数值转布尔】!!${num3} → ${!!num3}`); // true
  console.log(`【字符串转布尔】Boolean("${str4}") → ${Boolean(str4)}`); // false
  console.log(`【字符串转布尔】!!"${str5}" → ${!!str5}`); // true

  // 2. 布尔值转数值/字符串
  console.log(`\n【布尔转数值】Number(${bool2}) → ${Number(bool2)}`); // 1
  console.log(`【布尔转数值】Number(${!bool2}) → ${Number(!bool2)}`); // 0
  console.log(`【布尔转字符串】${bool2}.toString() → ${bool2.toString()}`); // true
  console.log(`【布尔转字符串】String(${!bool2}) → ${String(!bool2)}`); // false
}

运行效果

========== 数值/字符串↔布尔值转换 ==========
【数值转布尔】Boolean(0) → false
【数值转布尔】!!10 → true
【字符串转布尔】Boolean("") → false
【字符串转布尔】!!"false" → true

【布尔转数值】Number(true) → 1
【布尔转数值】Number(false) → 0
【布尔转字符串】true.toString() → true
【布尔转字符串】String(false) → false

(三)null/undefined的安全转换处理

null/undefined无法直接转换为数值/字符串(会报错或返回"null"/"undefined"),需先进行空值判断再转换。

关键区别:??(空值合并运算符)仅对null/undefined生效,||(逻辑或)对所有falsy值生效,鸿蒙开发中优先用??

代码逻辑封装:null/undefined的安全转换

// src/main/ets/utils/WrapperTypeConvertTest.ets
/**
 * 学习null/undefined的安全转换处理(避免转换异常)
 * 核心避坑:?? 仅处理null/undefined,|| 处理所有falsy值(数值型默认值慎用||)
 */
export function testNullUndefinedSafeConversion(): void {
  console.log(`\n========== null/undefined的安全转换 ==========`);
  const nullVar: string | null = null;
  const undefVar: number | undefined = undefined;
  const age: number = 0; // 合法数值(falsy值)

  // 1. 错误示例:直接转换(不推荐)
  console.log(`【错误示例】String(null) → ${String(nullVar)}`); // null
  console.log(`【错误示例】Number(undefined) → ${Number(undefVar)}`); // NaN

  // 2. 正确示例:空值判断后转换(推荐)
  const nullToStr: string = nullVar ?? "";
  console.log(`\n【安全转换】null ?? "" → "${nullToStr}"`); // ""
  const undefToNum: number = undefVar ?? 0;
  console.log(`【安全转换】undefined ?? 0 → ${undefToNum}`); // 0
  // 关键区别:?? vs ||
  console.log(`【对比】age ?? 18 → ${age ?? 18}`); // 0(保留合法0值,推荐)
  console.log(`【对比】age || 18 → ${age || 18}`); // 18(误判0为无效值,慎用)
  
  const userAge: number | undefined = undefined;
  const ageStr: string = String(userAge ?? 18);
  console.log(`【安全转换】String(undefined ?? 18) → ${ageStr}`); // 18
}

运行效果

========== null/undefined的安全转换 ==========
【错误示例】String(null) → null
【错误示例】Number(undefined) → NaN

【安全转换】null ?? "" → ""
【安全转换】undefined ?? 0 → 0
【对比】age ?? 18 → 0
【对比】age || 18 → 18
【安全转换】String(undefined ?? 18) → 18

七、实战练习:结合内置对象与类型转换处理业务场景

练习目标

整合内置对象方法、类型转换、空值处理的技巧,完成鸿蒙端常见业务场景处理。

代码逻辑封装:实战练习

// src/main/ets/utils/WrapperTypeConvertTest.ets
/**
 * 实战练习:结合内置对象与类型转换处理鸿蒙端常见业务场景
 */
export function testPracticalScenario(): void {
  console.log(`\n========== 实战练习 ==========`);

  // 场景1:商品价格格式化(保留2位小数,补0)
  const price: number = 2999;
  const priceStr: string = price.toFixed(2);
  console.log(`【场景1】商品价格:${price} → 格式化后:${priceStr}元`); // 2999.00元

  // 场景2:用户输入手机号处理(截取后4位,隐藏前7位)
  const phone: string = "13812345678";
  const phoneHide: string = phone.slice(0, 3) + "****" + phone.slice(7);
  console.log(`【场景2】手机号:${phone} → 隐藏后:${phoneHide}`); // 138****5678

  // 场景3:用户输入年龄处理(字符串转数值,判断是否成年)
  const ageInput: string = "24a";
// 处理非数字输入时返回0,避免Number.parseInt返回NaN导致后续判断异常
  const age: number = isNaN(Number.parseInt(ageInput)) ? 0 : Number.parseInt(ageInput);
  const isAdult: boolean = age >= 18;
  console.log(`【场景3】输入年龄:${ageInput} → 转换后:${age} → 是否成年:${isAdult}`); // 24 → true

  // 场景4:成绩判断(字符串转数值,判断等级)
  const scoreInput: string = "85";
  const score: number = Number(scoreInput);
  const scoreLevel: string = score >= 90 ? "优秀" : (score >= 80 ? "良好" : (score >= 60 ? "及格" : "不及格"));
  console.log(`【场景4】输入成绩:${scoreInput} → 转换后:${score} → 等级:${scoreLevel}`); // 良好

  // 场景5:空值处理(用户昵称未设置时显示默认值)
  const nickname: string | null = null;
  const showName: string = (nickname ?? "游客").trim() || "游客";
  console.log(`【场景5】用户昵称:${nickname} → 显示:${showName}`); // 游客

  // 场景6:鸿蒙UI文本适配(去除首尾空格+空值显示默认文案)
  const userInput: string | undefined = "  "; // 用户输入仅空格
  const showText: string = (userInput ?? "").trim() || "请输入内容";
  console.log(`【场景6】用户输入:${userInput} → UI显示:${showText}`); // 请输入内容
}

运行效果

========== 实战练习 ==========
【场景1】商品价格:2999 → 格式化后:2999.00元
【场景2】手机号:13812345678 → 隐藏后:138****5678
【场景3】输入年龄:24a → 转换后:24 → 是否成年:true
【场景4】输入成绩:85 → 转换后:85 → 等级:良好
【场景5】用户昵称:null → 显示:游客
【场景6】用户输入:   → UI显示:请输入内容

八、完整页面调用代码(Index.ets)

// src/main/ets/pages/Index.ets
import {
  testPrimitiveAndWrapper,
  testNumberWrapperMethods,
  testStringWrapperMethods,
  testBooleanWrapperMethods,
  testNumberStringConversion,
  testBooleanConversion,
  testNullUndefinedSafeConversion,
  testPracticalScenario
} from '../utils/WrapperTypeConvertTest';

@Entry
@Component
struct Index {
  aboutToAppear(): void {
    // 按顺序调用所有学习函数
    testPrimitiveAndWrapper();
    testNumberWrapperMethods();
    testStringWrapperMethods();
    testBooleanWrapperMethods();
    testNumberStringConversion();
    testBooleanConversion();
    testNullUndefinedSafeConversion();
    testPracticalScenario();
  }

  build() {
    Column() {
      Text("ArkTS内置对象与类型转换")
        .fontSize(30)
        .fontWeight(FontWeight.Bold)
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center);
  }
}

九、核心开发规范与注意事项

  1. 内置对象使用规范

    • 优先使用原始值,禁止手动创建new Number()/new String()等内置对象;
    • 字符串截取优先用slice()(支持负数索引),避免substring()
    • ArkTS内置对象与原始值运算前,需显式调用valueOf()拆箱;
    • toFixed返回字符串类型,若需数值运算必须先通过Number()转为数值。
  2. 类型转换规范

    • 所有转换必须显式进行,禁止num + ""+str等隐式写法,否则会变成字符串拼接。
    • 字符串转数值:严格验证用Number(str),宽松处理用parseInt()/parseFloat()
    • 布尔值转换优先用Boolean(value)!!value,遵循强类型规则。
  3. 空值处理规范

    • 处理null/undefined时必须先判断,结合??设置默认值(如null ?? "");
    • 数值型默认值(年龄、库存、价格)优先用??,避免||误判0为无效值;
    • 避免直接转换空值,防止出现"null"、NaN等无效结果。

十、内容总结

  1. 核心规则:ArkTS内置对象(Number/String/Boolean)需显式调用valueOf()获取原始值后,才能与对应原始值运算;
  2. 高频方法
    • NumbertoFixed(数值格式化)、parseInt/parseFloat(字符串转数值)、Number.isNaN(NaN判断);
    • Stringslice(截取)、includes(包含判断)、trim(去空格)、replace(替换);
    • BooleanBoolean()/!!(类型转换)。
  3. 类型转换:强类型下必须显式转换,数值↔字符串用toString()/Number(),布尔值转换用Boolean()/!!
  4. 边界处理null/undefined需先判断再转换,优先用??(空值合并)而非||(逻辑或)。

十一、代码仓库

十一、下节预告

下一节将学习复杂数据类型入门——数组、元组,重点包括:

  1. 掌握数组的声明、初始化、访问与高频内置方法(增删改查、筛选、排序);
  2. 理解元组的核心特性(固定长度、固定类型),区分元组与数组的差异;
  3. 结合业务场景使用数组存储同类型数据、元组存储不同类型关联数据。
posted @ 2026-01-15 15:43  鸿蒙-散修  阅读(0)  评论(0)    收藏  举报