原始类型

Number数字类型

JavaScript使用IEEE 754标准的64位双精度浮点数表示所有数字。

整数和浮点数

// 整数
let integer = 42;
let negative = -10;

// 浮点数
let float = 3.14;
let decimal = 0.5;
let scientific = 2.5e6;  // 2500000(科学计数法)

// 数字可以是任意大小(在安全范围内)
let safeInteger = Number.MAX_SAFE_INTEGER;  // 9007199254740991
let minInteger = Number.MIN_SAFE_INTEGER;   // -9007199254740991

数值范围

// 最大值和最小值
console.log(Number.MAX_VALUE);  // 1.7976931348623157e+308
console.log(Number.MIN_VALUE);  // 5e-324

// 安全整数范围
console.log(Number.MAX_SAFE_INTEGER);   // 9007199254740991
console.log(Number.MIN_SAFE_INTEGER);   // -9007199254740991

// 检查是否在安全范围内
console.log(Number.isSafeInteger(42));           // true
console.log(Number.isSafeInteger(9007199254740992)); // false

数字方法

// 转换为字符串
let num = 42;
console.log(num.toString());      // "42"
console.log(num.toString(2));     // "101010"(二进制)
console.log(num.toString(16));    // "2a"(十六进制)

// 固定小数位数
let price = 3.14159;
console.log(price.toFixed(2));    // "3.14"
console.log(price.toFixed(4));    // "3.1416"

// 科学计数法
console.log(price.toExponential(2));  // "3.14e+0"

// 精度表示
console.log(price.toPrecision(4));    // "3.142"

数值表示法

二进制、八进制、十六进制

// 二进制(0b或0B开头)
let binary = 0b1010;  // 10
console.log(binary);  // 10

// 八进制(0o或0O开头)
let octal = 0o755;    // 493
console.log(octal);   // 493

// 十六进制(0x或0X开头)
let hex = 0xFF;       // 255
console.log(hex);     // 255

// ES2021:数字分隔符
let million = 1_000_000;
let bytes = 0xFF_FF_FF_FF;
console.log(million);  // 1000000

科学计数法

let big = 2.5e6;      // 2500000
let small = 1.5e-3;   // 0.0015

console.log(big);     // 2500000
console.log(small);   // 0.0015

特殊数值

NaN(Not a Number)

NaN表示"不是一个数字",但它本身是数字类型:

console.log(typeof NaN);  // "number"

// 产生NaN的情况
console.log(Number("abc"));     // NaN
console.log(0 / 0);             // NaN
console.log(Math.sqrt(-1));     // NaN
console.log(parseInt("东巴文")); // NaN

// NaN的特性
console.log(NaN === NaN);       // false(NaN不等于任何值,包括自己)

// 检测NaN
console.log(Number.isNaN(NaN));           // true
console.log(Number.isNaN("abc"));         // false
console.log(isNaN("abc"));                // true(先转换再判断)

// 正确的NaN检测
function isRealNaN(value) {
    return typeof value === "number" && Number.isNaN(value);
}

Infinity(无穷大)

// 正无穷和负无穷
console.log(1 / 0);    // Infinity
console.log(-1 / 0);   // -Infinity

// 最大值溢出
console.log(Number.MAX_VALUE * 2);  // Infinity

// 检测无穷
console.log(Number.isFinite(42));       // true
console.log(Number.isFinite(Infinity)); // false
console.log(Number.isFinite(NaN));      // false

// 无穷运算
console.log(Infinity + 1);      // Infinity
console.log(Infinity * 2);      // Infinity
console.log(Infinity / Infinity); // NaN
console.log(Infinity - Infinity); // NaN

正零和负零

let positiveZero = 0;
let negativeZero = -0;

console.log(positiveZero === negativeZero);  // true

// 区分正零和负零
console.log(Object.is(0, -0));   // false
console.log(1 / 0);              // Infinity
console.log(1 / -0);             // -Infinity

数值精度问题

浮点数精度问题

JavaScript使用IEEE 754双精度浮点数,存在精度问题:

// 经典的精度问题
console.log(0.1 + 0.2);        // 0.30000000000000004
console.log(0.1 + 0.2 === 0.3); // false

// 其他精度问题
console.log(0.07 * 100);       // 7.000000000000001
console.log(0.1 + 0.7);        // 0.7999999999999999

解决方案

// 方案1:使用toFixed(返回字符串)
let result = (0.1 + 0.2).toFixed(1);
console.log(result);           // "0.3"
console.log(parseFloat(result)); // 0.3

// 方案2:乘以倍数再除以倍数
function add(a, b) {
    return (a * 100 + b * 100) / 100;
}
console.log(add(0.1, 0.2));    // 0.3

// 方案3:使用Number.EPSILON比较
function isEqual(a, b) {
    return Math.abs(a - b) < Number.EPSILON;
}
console.log(isEqual(0.1 + 0.2, 0.3)); // true

// 方案4:使用第三方库(如decimal.js)
// import Decimal from 'decimal.js';
// console.log(new Decimal(0.1).plus(0.2).toNumber()); // 0.3

东巴文提醒:涉及金额计算时,建议使用整数(分)或专门的库来避免精度问题。

Math对象

Math对象提供了丰富的数学方法。

常用常量

console.log(Math.PI);        // 3.141592653589793
console.log(Math.E);         // 2.718281828459045
console.log(Math.SQRT2);     // 1.4142135623730951
console.log(Math.LN2);       // 0.6931471805599453
console.log(Math.LN10);      // 2.302585092994046

取整方法

let num = 3.7;

// 向下取整
console.log(Math.floor(3.7));   // 3
console.log(Math.floor(-3.7));  // -4

// 向上取整
console.log(Math.ceil(3.2));    // 4
console.log(Math.ceil(-3.2));   // -3

// 四舍五入
console.log(Math.round(3.5));   // 4
console.log(Math.round(3.4));   // 3
console.log(Math.round(-3.5));  // -3

// 截断(去掉小数部分)
console.log(Math.trunc(3.7));   // 3
console.log(Math.trunc(-3.7));  // -3

随机数

// 0到1之间的随机数
console.log(Math.random());

// 0到9之间的随机整数
console.log(Math.floor(Math.random() * 10));

// 1到10之间的随机整数
console.log(Math.floor(Math.random() * 10) + 1);

// 任意范围的随机整数
function getRandomInt(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}
console.log(getRandomInt(5, 15));

// 随机数组元素
const colors = ["红", "绿", "蓝", "黄"];
const randomColor = colors[Math.floor(Math.random() * colors.length)];

最大值和最小值

console.log(Math.max(1, 2, 3, 4, 5));  // 5
console.log(Math.min(1, 2, 3, 4, 5));  // 1

// 数组中的最大值和最小值
const numbers = [1, 5, 3, 9, 2];
console.log(Math.max(...numbers));  // 9
console.log(Math.min(...numbers));  // 1

幂和开方

// 幂运算
console.log(Math.pow(2, 10));  // 1024
console.log(2 ** 10);          // 1024(ES6语法)

// 平方根
console.log(Math.sqrt(16));    // 4

// 立方根
console.log(Math.cbrt(27));    // 3

// n次方根
function nthRoot(num, n) {
    return Math.pow(num, 1 / n);
}
console.log(nthRoot(16, 4));   // 2

三角函数

// 注意:参数是弧度,不是角度
console.log(Math.sin(0));              // 0
console.log(Math.sin(Math.PI / 2));    // 1
console.log(Math.cos(0));              // 1
console.log(Math.tan(Math.PI / 4));    // 1

// 角度转弧度
function toRadians(degrees) {
    return degrees * Math.PI / 180;
}

// 弧度转角度
function toDegrees(radians) {
    return radians * 180 / Math.PI;
}

console.log(Math.sin(toRadians(90)));  // 1

其他方法

// 绝对值
console.log(Math.abs(-5));     // 5

// 符号
console.log(Math.sign(-5));    // -1
console.log(Math.sign(0));     // 0
console.log(Math.sign(5));     // 1

// 对数
console.log(Math.log(Math.E)); // 1
console.log(Math.log2(8));     // 3
console.log(Math.log10(100));  // 2

// 勾股定理
console.log(Math.hypot(3, 4)); // 5

String字符串类型

字符串是由零个或多个字符组成的序列,用单引号、双引号或反引号包围。

创建字符串

// 单引号
let single = '东巴文';

// 双引号
let double = "东巴文";

// 反引号(模板字符串)
let template = `东巴文`;

// 构造函数
let constructed = new String("东巴文");
console.log(typeof single);       // "string"
console.log(typeof constructed);  // "object"

字符串特性

// 字符串是不可变的
let str = "东巴文";
str[0] = "西";  // 无效,不会改变原字符串
console.log(str);  // "东巴文"

// 字符串长度
console.log("东巴文".length);  // 3

// 访问字符
let text = "Hello";
console.log(text[0]);        // "H"
console.log(text.charAt(0)); // "H"
console.log(text.charAt(10)); // ""(空字符串)
console.log(text[10]);       // undefined

转义字符

let escaped = "他说:\"你好\"";
console.log(escaped);  // 他说:"你好"

// 常用转义字符
console.log("换行\n第二行");
console.log("制表符\t内容");
console.log("回车\r换行");
console.log("反斜杠\\");
console.log("单引号\'");
console.log("双引号\"");
转义字符 含义 东巴文说明
\n 换行 New Line
\t 制表符 Tab
\r 回车 Carriage Return
\ 反斜杠 Backslash
' 单引号 Single Quote
" 双引号 Double Quote
\uXXXX Unicode字符 如 \u4e2d(中)

字符串方法

查找方法

let str = "东巴文学习JavaScript";

// indexOf - 查找子串位置
console.log(str.indexOf("学习"));     // 3
console.log(str.indexOf("Python"));   // -1(未找到)

// lastIndexOf - 从后往前查找
console.log(str.lastIndexOf("a"));    // 10

// includes - 是否包含
console.log(str.includes("东巴文"));   // true
console.log(str.includes("Python"));  // false

// startsWith - 是否以某字符串开头
console.log(str.startsWith("东巴文")); // true

// endsWith - 是否以某字符串结尾
console.log(str.endsWith("Script"));  // true

// search - 正则搜索
console.log(str.search(/Java/));      // 5

截取方法

let str = "东巴文学习JavaScript";

// slice - 切片(推荐)
console.log(str.slice(0, 3));    // "东巴文"
console.log(str.slice(3));       // "学习JavaScript"
console.log(str.slice(-6));      // "Script"
console.log(str.slice(-10, -6)); // "学习J"

// substring - 子串
console.log(str.substring(0, 3)); // "东巴文"
console.log(str.substring(3, 0)); // "东巴文"(自动调整顺序)

// substr - 指定位置和长度(已废弃,不推荐)
console.log(str.substr(0, 3));   // "东巴文"

// charAt - 获取指定位置字符
console.log(str.charAt(0));      // "东"

// charCodeAt - 获取字符编码
console.log(str.charCodeAt(0));  // 19996("东"的Unicode编码)

大小写转换

let str = "Hello 东巴文";

console.log(str.toUpperCase());  // "HELLO 东巴文"
console.log(str.toLowerCase());  // "hello 东巴文"

// 首字母大写
function capitalize(str) {
    return str.charAt(0).toUpperCase() + str.slice(1);
}
console.log(capitalize("hello")); // "Hello"

修改方法

let str = "  东巴文  ";

// trim - 去除两端空白
console.log(str.trim());       // "东巴文"

// trimStart / trimLeft - 去除开头空白
console.log(str.trimStart());  // "东巴文  "

// trimEnd / trimRight - 去除结尾空白
console.log(str.trimEnd());    // "  东巴文"

// repeat - 重复
console.log("东巴文".repeat(3)); // "东巴文东巴文东巴文"

// padStart - 开头填充
console.log("5".padStart(3, "0"));  // "005"

// padEnd - 结尾填充
console.log("5".padEnd(3, "0"));    // "500"

// replace - 替换(只替换第一个)
let text = "东巴文东巴文";
console.log(text.replace("东巴文", "DBW")); // "DBW东巴文"

// replaceAll - 替换所有(ES2021)
console.log(text.replaceAll("东巴文", "DBW")); // "DBWDBW"

// 使用正则替换所有
console.log(text.replace(/东巴文/g, "DBW")); // "DBWDBW"

分割和连接

// split - 分割成数组
let str = "东巴文,学习,JavaScript";
let arr = str.split(",");
console.log(arr);  // ["东巴文", "学习", "JavaScript"]

// join - 数组连接成字符串
console.log(arr.join("-"));  // "东巴文-学习-JavaScript"

// 分割每个字符
console.log("东巴文".split(""));  // ["东", "巴", "文"]

模板字符串

模板字符串使用反引号,支持多行字符串和插值表达式。

基本用法

// 普通字符串
let greeting = "你好," + name + "!";

// 模板字符串
let name = "东巴文";
let greeting = `你好,${name}!`;
console.log(greeting);  // "你好,东巴文!"

// 表达式插值
let a = 10;
let b = 20;
console.log(`${a} + ${b} = ${a + b}`);  // "10 + 20 = 30"

// 调用函数
function getPrice() {
    return 99.99;
}
console.log(`价格:${getPrice()}元`);  // "价格:99.99元"

多行字符串

// 普通字符串(需要使用\n)
let html1 = "<div>\n  <p>东巴文</p>\n</div>";

// 模板字符串(直接换行)
let html2 = `<div>
  <p>东巴文</p>
</div>`;

console.log(html1 === html2);  // true

标签模板

function highlight(strings, ...values) {
    let result = strings[0];
    for (let i = 0; i < values.length; i++) {
        result += `<strong>${values[i]}</strong>${strings[i + 1]}`;
    }
    return result;
}

let name = "东巴文";
let age = 1;

let result = highlight`我叫${name},今年${age}岁。`;
console.log(result);  // "我叫<strong>东巴文</strong>,今年<strong>1</strong>岁。"

Boolean布尔类型

布尔类型只有两个值:true和false。

布尔值

let isActive = true;
let isLoggedIn = false;

console.log(typeof true);   // "boolean"
console.log(typeof false);  // "boolean"

布尔转换

// Boolean()函数
console.log(Boolean(1));          // true
console.log(Boolean(0));          // false
console.log(Boolean("东巴文"));    // true
console.log(Boolean(""));         // false
console.log(Boolean([]));         // true
console.log(Boolean({}));         // true
console.log(Boolean(null));       // false
console.log(Boolean(undefined));  // false

// 双重否定
console.log(!!1);     // true
console.log(!!0);     // false
console.log(!!"");    // false

比较运算符

console.log(5 > 3);    // true
console.log(5 < 3);    // false
console.log(5 >= 5);   // true
console.log(5 <= 4);   // false

// 相等比较
console.log(5 == "5");   // true(隐式转换)
console.log(5 === "5");  // false(严格相等)

console.log(5 != "5");   // false
console.log(5 !== "5");  // true

逻辑运算符

// 逻辑与(&&)
console.log(true && true);    // true
console.log(true && false);   // false
console.log(false && true);   // false(短路)

// 逻辑或(||)
console.log(true || false);   // true
console.log(false || true);   // true
console.log(true || true);    // true(短路)

// 逻辑非(!)
console.log(!true);           // false
console.log(!false);          // true
console.log(!!true);          // true

Undefined类型

Undefined类型只有一个值:undefined。

undefined的产生

// 未初始化的变量
let x;
console.log(x);  // undefined

// 未提供的参数
function greet(name) {
    console.log(name);
}
greet();  // undefined

// 不存在的属性
let obj = {};
console.log(obj.name);  // undefined

// 函数没有返回值
function noReturn() {}
console.log(noReturn());  // undefined

检测undefined

let x;

// 使用严格相等
console.log(x === undefined);  // true

// 使用typeof(安全,不会报错)
console.log(typeof x === "undefined");  // true

// 未声明的变量
// console.log(notDeclared);  // ReferenceError
console.log(typeof notDeclared);  // "undefined"

undefined vs null

特性 undefined null 东巴文说明
含义 未定义 空值 undefined是"没有",null是"空"
类型 undefined object null的typeof是历史遗留问题
出现场景 自动产生 手动赋值 undefined是默认值
使用建议 不主动赋值 主动赋空值 null表示"无值"
console.log(typeof undefined);  // "undefined"
console.log(typeof null);       // "object"

console.log(undefined == null);  // true
console.log(undefined === null); // false

// 最佳实践
let name;           // undefined(未赋值)
let user = null;    // null(明确表示空值)

Null类型

Null类型只有一个值:null,表示"空"或"无"。

null的使用

// 表示空值
let user = null;  // 暂时没有用户

// 条件判断
if (user === null) {
    console.log("没有用户");
}

// 清除引用
let obj = { name: "东巴文" };
obj = null;  // 解除引用,便于垃圾回收

// 函数参数默认值
function greet(name = null) {
    if (name === null) {
        return "你好,陌生人";
    }
    return `你好,${name}`;
}

null的检测

let value = null;

// 使用严格相等
console.log(value === null);  // true

// 同时检测null和undefined
console.log(value == null);   // true
console.log(value == undefined);  // true

// 只检测null
function isNull(value) {
    return value === null;
}

Symbol类型

Symbol是ES6引入的新原始类型,表示独一无二的值。

创建Symbol

// 创建Symbol
let sym1 = Symbol();
let sym2 = Symbol("描述");

console.log(typeof sym1);  // "symbol"
console.log(sym2.description);  // "描述"

// 每个Symbol都是唯一的
let sym3 = Symbol("东巴文");
let sym4 = Symbol("东巴文");
console.log(sym3 === sym4);  // false

Symbol作为属性键

let name = Symbol("name");
let age = Symbol("age");

let user = {
    [name]: "东巴文",
    [age]: 1,
    email: "test@example.com"
};

console.log(user[name]);  // "东巴文"
console.log(user[age]);   // 1

// Symbol属性不会被常规方法遍历
console.log(Object.keys(user));  // ["email"]
console.log(Object.getOwnPropertySymbols(user));  // [Symbol(name), Symbol(age)]

全局Symbol注册表

// Symbol.for - 创建或获取全局Symbol
let sym1 = Symbol.for("app.id");
let sym2 = Symbol.for("app.id");
console.log(sym1 === sym2);  // true

// Symbol.keyFor - 获取全局Symbol的key
console.log(Symbol.keyFor(sym1));  // "app.id"

内置Symbol

// Symbol.iterator - 迭代器
let arr = [1, 2, 3];
let iterator = arr[Symbol.iterator]();

console.log(iterator.next());  // { value: 1, done: false }
console.log(iterator.next());  // { value: 2, done: false }
console.log(iterator.next());  // { value: 3, done: false }
console.log(iterator.next());  // { value: undefined, done: true }

// Symbol.toStringTag - 自定义toString标签
class User {
    get [Symbol.toStringTag]() {
        return "User";
    }
}
console.log(Object.prototype.toString.call(new User()));  // "[object User]"

BigInt类型

BigInt是ES2020引入的类型,用于表示任意大的整数。

创建BigInt

// 使用n后缀
let big1 = 9007199254740991n;
console.log(big1);  // 9007199254740991n

// 使用BigInt()函数
let big2 = BigInt("9007199254740992");
console.log(big2);  // 9007199254740992n

// 从数字转换
let big3 = BigInt(123);
console.log(big3);  // 123n

BigInt运算

let a = 10n;
let b = 5n;

console.log(a + b);   // 15n
console.log(a - b);   // 5n
console.log(a * b);   // 50n
console.log(a / b);   // 2n(整数除法,向下取整)
console.log(a % b);   // 0n
console.log(a ** 2n); // 100n

// 不能与普通数字混合运算
// console.log(10n + 5);  // TypeError

// 需要显式转换
console.log(10n + BigInt(5));  // 15n
console.log(Number(10n) + 5);  // 15

BigInt与Number的区别

特性 Number BigInt 东巴文说明
精度 53位安全整数 任意精度 BigInt无精度限制
小数 支持 不支持 BigInt只能表示整数
Math方法 支持 不支持 Math.sqrt(4n)报错
混合运算 - 不允许 需要显式转换
JSON序列化 支持 不支持 需要转换为字符串
// 大数计算
let result = 1n;
for (let i = 1n; i <= 100n; i++) {
    result *= i;
}
console.log(result);  // 100的阶乘

// JSON序列化
let big = 123n;
// JSON.stringify({ value: big });  // TypeError

// 解决方案
JSON.stringify({ value: big.toString() });  // '{"value":"123"}'

下一步

掌握了原始类型后,让我们继续学习:

  1. 引用类型 - 深入学习引用类型
  2. 类型转换 - 深入学习类型转换
  3. 运算符概述 - 学习运算符

东巴文(db-w.cn) - 让编程学习更简单

🔢 东巴文寄语:原始类型是JavaScript的基础数据类型,理解它们的特性和方法,能让你写出更高效、更安全的代码。在 db-w.cn,我们帮你打好每一个基础!