跳到主要内容

数据类型

基本数据类型

Undefined type

  • 表示未定义值;
  • 表示变量声明, 但未初始化的状态;
    • 用于可选函数;

Null type

  • 表示已经定义, 但是为空值;
  • 通常用于初始化对象, 表示一个空的对象;

Boolean type

布尔类型
  • true + false;
布尔类型与数字的关系
  • true 不等于 1;
  • false 不等于 0;
  • 两者通过 Number() 可转换为 1 和 0;
任意类型的布尔值
  • 任意类型都具有布尔值;
  • 可通过 Boolean() 函数转换;
数据类型真值假值
Booleantruefalse
String任何非空字符串空字符串
Number任何非 0 数字0, NaN
Object任意对象null
Undefinedn/aundefined

Number Type

基础

格式
  • 使用 IEEE–754 表示整数和浮点数;
  • 64 位双浮点数精度;
进制
// 十进制
let intNum = 55; // integer
// 二进制
let bNum = 0b10;
// 八进制
let octalNum = 070; // octal for 56
// 十六进制
let hexNum = 0xa;

浮点数

语法格式
let floatNum1 = 1.1;
let floatNum = 3.125e7; // equal to 31250000
let floatNum = 3e-7; // equal to 0.0000003
float 到 int 的隐式转换
  • 若小数点后无数字或为 0, 将其转换为 int;
let floatNum1 = 1; // 等效于 int 1
let floatNum2 = 10.0; // 等效于 int 10
精度损失
let a = 0.1 + 0.2; // equal to 0.30000000000000004

数字的范围

常量
  • Number.MIN_VALUE: 5e–324;
  • Number.MAX_VALUE: 1.7976931348623157e+308;
  • Number.MAX_SAFE_INTEGER: 9007199254740991;
  • Number.MIN_SAFE_INTEGER: -9007199254740991;
  • Number.NEGATIVE_INFINITY: -Infinity;
  • Number.POSITIVE_INFINITY: Infinity;
  • Number.EPSILON: 2.220446049250313e-16;
  • Number.NaN: NaN;
计算机制
  • 若计算范围超过 JavaScript 范围;
  • 结果为 Infinity/-Infinity;

整数和浮点数的内存耗费

  • 数值为整数, 存储在栈上, 耗费 8 字节;
  • 数值为浮点数, 存储在堆上, 栈存储堆上的内存地址, 耗费 16 字节;

NaN

NaN
  • 表明无效值;
计算特性
  • NaN 与任何值计算结果皆为 NaN;
  • NaN 不等于任何值, 包括 NaN;
  • 只能通过 isNaN() 方法判断是否为 NaN, 其余方法一直为 false;
console.log(typeof NaN); // 输出 "number"
let x = NaN;
console.log(x == NaN); // 输出 "false"
console.log(x === NaN); // 输出 "false"
console.log(isNaN(x)); // 输出 "true"

BigInt

  • 任意精度格式的整数;
const bigint = 1234567890123456789012345678901234567890n;
const sameBigint = BigInt("1234567890123456789012345678901234567890");

The String Type

基本概念

string
  • 16-bit Unicode;
  • immutable;
  • 字符序列;

转义字符

转义字符意义转义字符意义
\0Null Byte\'单引号
\b退格\"双引号
\n换行符\\
\f换页符\XXX八进制
\r回车键\xnn二位十六进制
\t水平制表符\unnnn四位十六进制
length 属性
  • 字符串长度;
  • 当字符串中包含双字节字符 (如汉字, emoji), length 不一定准确;

模板字面量

基本语法
let name = "kxh";
console.log(`My name is ${name}.`); // My name is kxh;
标签函数
  • 若 Template Literal 具有 n 个 Interpolation;
  • 第一个参数以 Template Literal 中 n 个 Interpolation 作为分隔点, 构成具有 n + 1 个字符串片段的数组;
  • 其余 n 个参数依次为 Template Literal 中的 n 个 Interpolation;
let a = 6;
let b = 9;
function simpleTag(strings, aValExpression, bValExpression, sumExpression) {
console.log(strings);
console.log(aValExpression);
console.log(bValExpression);
console.log(sumExpression);
return "foobar";
}
let taggedResult = simpleTag`${a} + ${b} = ${a + b}`;
// ["", " + ", " = ", ""]
// 6
// 9
// 15
console.log(taggedResult); // "foobar"

原始字符串

console.log(String.raw`first line\nsecond line`); // "first line\nsecond line"

Symbol 类型

基础

Symbol
  • 原子类型;
  • Symbol 实例是唯一, 不可变的;
  • 避免对象同名字符串;
let sym = Symbol();
// 字符串是对 sym 的描述, 与符号标识无关
let sym = Symbol("test");
符号作为属性
let s1 = Symbol("foo");

// 使用计算属性语法
let o = {
[s1]: "foo val";
};

// 使用 Object.defineProperty()/Object.defineProperties() 方法
Object.defineProperty(o, s1, { value: "foo val" });
Object.defineProperties(o, {
[s1]: { value: "foo val" };
});

方法

  • Symbol.for(key): 全局注册 symbol;
  • Symbol.keyFor(sym): 查询全局注册表中 symbol 对应的 key 值;

内置符号

Symbol.asyncIterator
  • 返回对象的 AsyncIterator, 用于 for-await-of 语句;
class Emitter {
constructor(max) {
this.max = max;
this.asyncIdx = 0;
}
async *[Symbol.asyncIterator]() {
while (this.asyncIdx < this.max) {
yield new Promise((resolve) => resolve(this.asyncIdx++));
}
}
}
Symbol.hasInstance
  • 确定一个对象是否使其实例, 用于 instanceof 操作符;
class Bar {}
class Baz extends Bar {
static [Symbol.hasInstance]() {
return false;
}
}
Symbol.isConcatSpreadable
  • 表示该对象使用 Array.prototype.concat() 是否打平其数组元素, 默认为 true
let initial = ["foo"];
let array = ["bar"];
console.log(array[Symbol.isConcatSpreadable]); // undefined
console.log(initial.concat(array)); // ['foo', 'bar']
array[Symbol.isConcatSpreadable] = false;
console.log(initial.concat(array)); // ['foo', Array(1)]
Symbol.iterator
  • 返回对象的 Iterator, 用于 for-of 语句;
class Emitter {
constructor(max) {
this.max = max;
this.idx = 0;
}
*[Symbol.iterator]() {
while (this.idx < this.max) {
yield this.idx++;
}
}
}
Symbol.match
  • 应用于正则表达式匹配, 用于 match/replace/search 等方法, RegExp 默认具有该属性;
class FooMatcher {
static [Symbol.match](target) {
return target.includes("foo");
}
}
Symbol.toPrimitive
  • 将对象转换为对应的原始值, 应用与隐式转换;
class Bar {
constructor() {
this[Symbol.toPrimitive] = function (hint) {
switch (hint) {
case "number":
return 3;
case "string":
return "string bar";
case "default":
default:
return "default bar";
}
};
}
}
let bar = new Bar();
console.log(3 + bar); // "3default bar"
console.log(3 - bar); // 0
console.log(String(bar)); // "string bar"

最佳实践

解决浮点数精度问题

Number.EPSILON
  • ES6 提供 Number.EPSILON 属性;
  • 只要误差小于其, 即可判断相等;
浮点数转换为整数
  • 根据实际情况, 将浮点数转换为整数;
数学库
  • 使用数学库;

判断数据类型的方法

不同方法优劣
typeofinstancofconstructorObject.prototype.toString.call()
优点简单可判断引用数据类型检查除 null/undefined 的一切类型所有类型
缺点无法判断引用数据类型和 null不能检查基本数据类型, 无法跨 iframe不能跨 iframe, constor 可被修改无法在 IE 使用
var str = "Hello, World!";
typeof str; // "string"
instanceof str; // false
str.constructor === String; // true
var strType = Object.prototype.toString.call(str); // [object String]
判断空对象
  • 使用 Object.keys() 方法;
  • 使用 for in;
  • 使用 JSON.stringify() 方法;
Object.keys(obj).length === 0;

function isEmpty(obj) {
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
return false;
}
}
return true;
}

JSON.stringify(obj) === "{}";
undefined 和 null 判断
  • 使用简单判等;
if (value == null) {
// ...
}
自定义类型判断方法
  • typeof 判断基本类型;
  • Object.prototype.toString 判断引用类型;
typeof 历史遗留问题
typeof null; // object
typeof NaN; // number

数字千分位分隔

  • 数字转换为字符串数组, 三位添加逗号;
  • 使用正则表达式;
function numberWithCommas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
  • 使用 Intl.NumberFormat() AP
var number = 1234567.8911111;
var formattedNumber = new Intl.NumberFormat("en-US", {}).format(number);
console.log(formattedNumber); // 1,234,567.891
  • 使用 String.toLocaleString() API;
    • 实际调用 Intl.NumberFormat() API;
console.log((1234567.8911111).toLocaleString("en-US")); // 1,234,567.891