7种数据类型

Undefined、Null、Boolean、String、Number、Symbol、Object

基本类型的变量是存放在栈区的
引用类型的值是同时保存在栈内存和堆内存中的

Undefined

通常指变量未定义。

Null

  1. typeof null // "object"
  2. null == undefined // true

null 值表示一个空对象指针。
不同的对象在底层原理的存储是用二进制表示的,在 javaScript 中,如果二进制的前三位都为 0 的话,系统会判定为是 Object 类型。null 的存储二进制是 000 ,也是前三位,所以系统判定 null 为 Object 类型。

Boolean

  1. Boolean(NaN); // false

String

方法:

  • split:使用:
    1. var str = "hello world";
    2. var arr = str.split('');

    Number

    使用 IEEE 754 格式表示整数和浮点值。
    进制表示:
    0b —— 二进制
    0o —— 八进制
    0x0X —— 十六进制
    通常来说,有前导 0 的数值会被视为八进制,但是如果前导 0 后面有数字 8 和 9 ,则该数值被视为十进制。
    如果要将 0b 和 0o 前缀的字符串数值转为十进制,要使用 Number 方法。
    1. Number('0b111') // 7

科学计数法
以下两种情况,JavaScript 会自动将数值转为科学计数法表示,其他情况都采用字面形式直接表示。

  1. 小数点前的数字多于 21 位。
  2. 小数点后的零多于 5 个。

正零和负零

  1. -0 === +0 // true
  2. 0 === -0 // true
  3. 0 === +0 // true

几乎所有场合,正零和负零都会被当作正常的 0 。
唯一有区别的场合是,+0-0 当做分母,返回的值是不相等的。

  1. (1 / +0) === (1 / -0) // false

上面的代码之所以出现这样的结果,是因为除以正零得到 +Infinity ,除以负零得到 -Infinity ,这两者是不相等的。

浮点值

  • 存储浮点值使用的内存空间是存储数值的两倍,所以 ECMAScript 总是想方设法把值转换为整数。
  • 默认情况下, ECMAScript 会将小数点后至少包含 6 个零的浮点值转换为科学计数法。
  • 浮点值的精确度最高可达 17 位小数,但在算术计算中远不如整数精确。例如, 0.1 + 0.2 不等于 0.3 。(之所以存在这种舍入错误,是因为使用了 IEEE 754 数值,这种错误并非 ECMAScript 所独有。其他使用相同格式的语言也有这个问题)

**NaN**
NaN是 JavaScript 的特殊值,表示“非数字”,主要出现在将字符串解析成数字出错的场合。

  1. NaN 不等于任何值,包括它本身。
  2. 数组的 indexOf 方法内部使用的是严格相等运算符,所有该方法对 NaN 不成立。
  3. NaN 在布尔运算时被当作 false

    1. Boolean(NaN) // false
  4. NaN 与任何数(包括它自己)的运算,得到的都是 NaN

返回 NaN 的情况:

  • 零除以零;
  • 无穷大除以无穷大
  • 给任意负数作开方运算(Math.pow(-1, 1/3)
  • 算数运算符与不是数字或无法转换为数字的操作数一起使用时
  1. isNaN() 函数。接收一个参数,可以是任意数据类型,然后判断这个参数是否 “不是数值”。把一个值传给 isNaN() 后,该函数会尝试把它转换为数值。某些非数值的值可以直接转换成数值。不然转换为数值的值会导致这个函数返回 true 。

**Infinity**
Infinity 表示“无穷”,用来表示两种场景。一种是一个正的数值太大,或一个负的数值太小,无法表示;另一种是非 0 数值除以 0 ,得到 Infinity

  1. // 场景一
  2. Math.pow(2, 1024)
  3. // Infinity
  4. // 场景二
  5. 0 / 0 // NaN
  6. 1 / 0 // Infinity

Infinity 有正负之分,Infinity 表示正的无穷,-Infinity 表示负的无穷。
Infinity 大于一切数值(除了 NaN ),-Infinity 小于一切数值(除了 NaN )。

  1. 0 * Infinity // NaN
  2. 0 / Infinity // 0
  3. Infinity / 0 // Infinity
  4. Infinity + Infinity // Infinity
  5. Infinity * Infinity // Infinity
  6. Infinity / Infinity // NaN
  7. Infinity - Infinity // NaN
  • Infinitynull 计算时, null 会转成 0 ,等同于与 0 的计算。
  • Infinityundefined 计算,返回的都是 NaN
  • 要确定一个值是不是有限大(即介于 JavaScript 能表示的最小值和最大值之间),可以使用 isFinite() 函数。

常数

  • Number.EPSILON:表示1与大于1的最小浮点数之间的差,实际上是JavaScript能够表示的最小精度
  • Number.MAX_SAFE_INTEGER和Number.MIN_SAFE_INTEGER:JavaScript能够准确表示的整数范围在 -2^53 到 2^53 之间(不含两个端点),超过这个范围,无法精确表示这个值。ES6 引入了Number.MAX_SAFE_INTEGERNumber.MIN_SAFE_INTEGER 这两个常量,用来表示这个范围的上下限。由于2的53次方是一个16位的十进制数值,所以简单的法则就是,JavaScript对15位的十进制数都可以精确处理。
  • Number.MIN_VALUE,最小数值,在多数浏览器中是 5e-324
  • Number.MAX_VALUE,最大数值,1.7976931348623157e+308。
  • Number.NEGATIVE_INFINITY 和 Number.POSITIVE_INFINITY 分别表示 -Infinity 和 Infinity 。

    判断是否是数字

    ```javascript function isNumber(num) { return typeof num === “number” && !isNaN(num); // typeof NaN === ‘number’ }

// 或者 function isNumber(num) { return typeof num === “number” && isFinite(num); }

// 或者 function isNumber(num) { return num === !num; }

  1. <a name="GJrQc"></a>
  2. ### 取小数点后几位
  3. ```javascript
  4. // 会四舍五入
  5. let num = 1.3489;
  6. num = num.toFixed(2); // 1.35

Symbol

Symbol 值通过 Symbol 函数生成。这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的 Symbol 类型。凡是属性名属于 Symbol 类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。
Symbol 函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分。如果参数是一个对象,就会调用该对象的 toString 方法,将其转为字符串,然后才生成一个 Symbol 值。

注意:

  • Symbol 函数前不能使用 new 命令。
  • Symbol 值作为对象属性名: 可以用方括号和 Object.defineProperty ,不能用点运算符。

转换规则

  • Symbol 值可以显式转为字符串

    1. var sym = Symbol('hello');
    2. String(sym) // 'Symbol(hello)'
    3. sym.toString() // 'Symbol(hello)'
  • Symbol 值转布尔值

    1. Boolean(sym) // true
    2. !sym // false
    3. if (sym) {}
  • Symbol 不能转为数值

    Object

    内置对象

    Arguments、Array、Boolean、Date、Error、Function、Math、Number、Object、RegExp、String

    Date

    1. var myDate = new Date();
    2. myDate.getYear(); //获取当前年份(2位)
    3. myDate.getFullYear(); //获取完整的年份(4位,1970-????)
    4. myDate.getMonth(); //获取当前月份(0-11,0代表1月) // 所以获取当前月份是myDate.getMonth()+1;
    5. myDate.getDate(); //获取当前月份中的当前日(1-31)
    6. myDate.getDay(); //获取当前星期X(0-6,0代表星期天)
    7. myDate.getTime(); //获取当前时间(从1970.1.1开始的毫秒数,13位数字,精度毫秒)
    8. myDate.getHours(); //获取当前小时数(0-23)
    9. myDate.getMinutes(); //获取当前分钟数(0-59)
    10. myDate.getSeconds(); //获取当前秒数(0-59)
    11. myDate.getMilliseconds(); //获取当前毫秒数(0-999)
    12. myDate.toLocaleDateString(); //获取当前日期
    13. var mytime = myDate.toLocaleTimeString(); //获取当前时间
    14. myDate.toLocaleString(); //获取日期与时间

    精度为秒(10位数字)的时间戳:Math.round(new Date().getTime() / 1000)

    Math

  • Math.round() :四舍五入取整

  • Math.ceil():向上取整
  • Math.floor():向下取整

    Object 的遍历

    ES6 一共有 5 种方法可以遍历对象的属性:
  1. for...in (es3就存在):遍历对象所有可继承的可枚举属性,包括原型链上的可枚举属性(不含 Symbol 属性)。无法保证遍历顺序,应尽量避免编写依赖对象属性顺序的代码。

注意:如果属性的 _enumerable_ 设置为 _false_ ,则无法被遍历到。如果想过滤掉原型链上的属性,可以用 hasOwnProperty 方法来进行过滤。

  1. Object.keys(obj) (es5新增):返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 **Symbol** 属性)的键名,不包含原型链上的属性。与 for in + hasOwnProperty 的效果一样。
  2. Object.getOwnPropertyNames(obj) (es5新增):返回一个数组,包括对象自身的所有属性(不含Symbol属性,但是包括不可枚举属性)的键名,不包含原型链上的属性
  3. Object.getOwnPropertySymbols(obj) :返回一个数组,包含对象自身的所有 Symbol 属性的键名。
  4. Reflect.ownKeys(obj) :返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。

举个例子:

  1. const parent = Object.create(Object.prototype, {
  2. a: {
  3. value: 1,
  4. writable: true,
  5. enumerable: true,
  6. configurable: true
  7. }
  8. })
  9. const child = Object.create(parent, {
  10. b: {
  11. value: 2,
  12. writable: true,
  13. enumerable: true,
  14. configurable: true
  15. },
  16. c: {
  17. value: 3,
  18. writable: true,
  19. enumerable: false,
  20. configurable: true
  21. }
  22. })
  23. // for in
  24. for(let i in child) {
  25. if (child.hasOwnProperty(i)) {
  26. console.log(i); // b
  27. }
  28. }
  29. // Object.keys
  30. console.log(Object.keys(child)) // ['b']
  31. // Object.getOwnPropertyNames
  32. console.log(Object.getOwnPropertyNames(child)); // ['b', 'c']
  1. const obj = {100: 'a', 2: 'b', 7: 'c' };
  2. Object.values(obj); // ["b", "c", "a"] 不按顺序输出

属性遍历的次序规则:

  • 首先遍历所有数值键,按照数值升序排列。
  • 其次遍历所有字符串,按照加入时间升序排列。
  • 最后遍历所有 Symbol 键,按照加入时间升序排排列。

Object的两类属性

数据属性(四个特征):

  • value:就是属性的值
  • writable:决定属性能否被赋值,默认为 true
  • enumerable:决定 for in 能否枚举该属性。默认情况下,所有直接定义在对象上的属性的这个特性都是 true
  • configurable:决定该属性能够被删除(delete)以及除 value 和 writable 特性外的其他特性是否可以被修改,默认为 true
    1. var b = {};
    2. Object.defineProperties(b, {
    3. name: {
    4. get() {
    5. return "huangry"
    6. },
    7. configurable: false
    8. }
    9. });
    10. Object.getOwnPropertyDescriptor(b, "name"); // {set: undefined, enumerable: false, configurable: false, get: ƒ}
    11. Object.keys(b); // []
    12. b.age = 18;
    13. Object.getOwnPropertyDescriptor(b, "age"); // {value: 18, writable: true, enumerable: true, configurable: true}
    14. Object.keys(b); // ["age"]
    image.png看颜色可以知道谁是可枚举的。 ```javascript // configurable var obj1 = {}; Object.defineProperties(obj1, { name: { get() {
    1. return "huangry"
    }, configurable: false } }); Object.defineProperty(obj1, “name”, { value: “hippo” }) // TypeError Object.defineProperty(obj1, “name”, { configurable: true }) // TypeError delete obj.name; // false

var obj2 = {name: “huangry”}; Object.defineProperties(obj2, { name: { configurable: false } }); Object.defineProperty(obj2, “name”, { value: “hippo” }) // {name: “hippo”}

  1. 访问器属性(四个特征):
  2. - `getter`:函数或 undefined ,在取属性值时被调用
  3. - `setter`:函数或 undefined ,在设置属性值时被调用
  4. - `enumerable`:决定 `for in` 能否枚举该属性
  5. - `configurable`:决定该属性能够被删除或者改变特征值
  6. 可通过 `Object.getOwnPropertyDescripter` 查看属性的特征值<br />可通过 `Object.defineProperty` 来定义或改变属性的特征
  7. **对象的分类**
  8. - 宿主对象:例如 `window`
  9. - 内置对象
  10. - 固有对象
  11. - 原生对象
  12. - 普通对象
  13. <a name="fejet"></a>
  14. # Map
  15. `Map` 是一种新的集合类型, `Map` 的大多数特性都可以通过 `Object` 类型实现,但二者之间还是存在一些细微的差异。
  16. <a name="LWXwe"></a>
  17. ## 基本 API
  18. 使用 `new` 关键字和 `Map` 构造函数可以创建一个空映射:
  19. ```javascript
  20. const m = new Map()

初始化之后,可以使用 set() 方法再添加键/值对。另外,可以使用 get()has() 进行查询,可以通过 size 属性获取映射中的键/值对的数量,还可以使用 delete()clear()删除值。

Object 只能使用数值、字符串或符号作为键不同, Map 可以使用任何 JavaScript 数据类型作为键。
Object 类型的一个主要差异是, Map 实例会维护键值对的插入顺序,因此可以根据插入顺序执行迭代操作。

选择 Object 还是 Map

  1. 内存占用
    ObjectMap的工程级实现在不同浏览器间存在明显差异,但存储单个键/值对所占用的内存数量都会随键的数量线性增加。批量添加或删除键/值对则取决于各浏览器对该类型内存分配的工程实现。不同浏览器的情况不同,但给定固定大小的内存,Map大约可以比Object多存储50%的键/值对。
  2. 插入性能
    ObjectMap中插入新键/值对的消耗大致相当,不过插入Map在所有浏览器中一般会稍微快一点儿。对这两个类型来说,插入速度并不会随着键/值对数量而线性增加。如果代码涉及大量插入操作,那么显然Map的性能更佳。
  3. 查找速度
    与插入不同,从大型ObjectMap中查找键/值对的性能差异极小,但如果只包含少量键/值对,则Object有时候速度更快。在把Object当成数组使用的情况下(比如使用连续整数作为属性),浏览器引擎可以进行优化,在内存中使用更高效的布局。这对Map来说是不可能的。对这两个类型而言,查找速度不会随着键/值对数量增加而线性增加。如果代码涉及大量查找操作,那么某些情况下可能选择Object更好一些。
  4. 删除性能
    使用delete删除Object属性的性能一直以来饱受诟病,目前在很多浏览器中仍然如此。为此,出现了一些伪删除对象属性的操作,包括把属性值设置为undefinednull。但很多时候,这都是一种讨厌的或不适宜的折中。而对大多数浏览器引擎来说,Mapdelete()操作都比插入和查找更快。如果代码涉及大量删除操作,那么毫无疑问应该选择Map

    WeakMap

    ECMAScript 6新增的“弱映射”(WeakMap)是一种新的集合类型,为这门语言带来了增强的键/值对存储机制。WeakMapMap的“兄弟”类型,其API也是Map的子集。WeakMap中的“weak”(弱),描述的是JavaScript垃圾回收程序对待“弱映射”中键的方式。

基本 API

可以使用new关键字实例化一个空的WeakMap

  1. const wm = new WeakMap();

初始化之后可以使用set()再添加键/值对,可以使用get()和has()查询,还可以使用delete()删除。

Set

WeakSet

类型转换

“==”

规则:

  • NaN 不等于任何值,包括其本身
  • 布尔值会转成数字类型
  • 数字和字符串比较,字符串会转换成数字
  • undefinednull 除了和 undefinednull 相等,和其它相比都是 false

ES5规范11.9.3抽象相等比较算法

  1. 若 Type(x) 与 Type(y) 相同,则
    1. 若 Type(x) 为 **Undefined** ,返回 true
    2. 若 Type(x) 为 **Null** ,返回 true
    3. 若 Type(x) 为 **Number** ,则
      1. 若 x 为 NaN ,返回 false
      2. 若 y 为 NaN ,返回 false
      3. 若 x 与 y 为相等数值,返回 true
      4. 若 x 为 +0 且 y 为 -0 ,返回 true
      5. 若 x 为 -0 且 y 为 +0 ,返回 true
      6. 返回 false 。
    4. 若 Type(x) 为 **String** ,则当 x 和 y 为完全相同的字符序列(长度相等且相同字符在相同位置)时返回 true 。否则,返回 false
    5. 若 Type(x) 为 **Boolean** ,当 x 和 y 同为 true 或者同为 false 时返回 true 。否则,返回 false
    6. 当 x 和 y 为引用同一对象时返回 true 。否则,返回 false
  2. 若 x 为 null 且 y 为 undefined ,返回 true
  3. 若 x 为 undefined 且 y 为 null ,返回 true
  4. 若 Type(x) 为 Number 且 Type(y) 为 String ,返回 comparison x == ToNumber(y) 的结果。
  5. 若 Type(x) 为 String 且 Type(y) 为 Number ,返回比较 ToNumber(x) == y 的结果。
  6. 若 Type(x) 为 Boolean ,返回比较 ToNumber(x) == y 的结果。
  7. 若 Type(y) 为 Boolean ,返回比较 x == ToNumber(y) 的结果。
  8. 若 Type(x) 为 StringNumber ,且 Type(y) 为 Object ,返回比较 x == ToPrimitive(y) 的结果。
  9. 若 Type(x) 为 Object 且 Type(y) 为 StringNumber ,返回比较 ToPrimitive(x) == y 的结果。
  10. 返回false。
    1. null == undefined // true
    2. true == 1 //true
    3. false == 0 // true
    4. "123" == 123 //true
    5. "1a" == 1 //false,"1a"转成数字是NaN
    6. undefined == 0 // false
    7. undefined == false // false
    8. new String("a") == "a" // true
    9. new String("a") == new String("a") // false

    X → Number

数据类型 数字类型
字符串 1) 数字转化为对应的数字
2) 其他转化为 NaN
布尔类型 1) true 转化为 1
2) false 转化为 0
null 0
undefined NaN
数组 1) 数组为空转化为 0;
2) 数组只有一个元素转化为对应元素;
3) 其他转化为NaN
空字符串 0
  1. Number(10); // 10
  2. Number('10'); // 10
  3. Number(null); // 0
  4. Number(''); // 0
  5. Number(true); // 1
  6. Number(false); // 0
  7. Number([]); // 0
  8. Number([1,2]); // NaN
  9. Number('10a'); // NaN
  10. Number(undefined); // NaN

字符串转数字

  1. parseInt(s); // 解析时会跳过任意数量的前导空格,尽可能解析更多数值字符
  2. parseFloat(s);
  3. Number(s); // 字符中不能出现非数字的字符,否则将返回 NaN

parseInt && parseFloat
paeseInt 方法用于将字符串转为整数。如果字符串头部有空格,空格会被自动去除。如果 parseInt 的参数不是字符串,则会先转为字符串再转换。字符串转为整数的时候,是一个个字符依次转换,如果遇到不能转为数字的字符,就不再进行下去,返回已经转好的部分。
如果字符串的第一个字符不能转化为数字(后面跟着数字的正负号除外),返回 NaN
所以, parseInt 的返回值只有两种可能,要么是一个十进制整数,要么是 NaN
如果字符串以 0x0X 开头, parseInt 会将其按照十六进制数解析。
对于那些会自动转为科学计数法的数字, parseInt 会将科学计数法的表示方法视为字符串,因此导致一些奇怪的结果。

  1. parseInt('1e+21') // 1

parseInt 方法还可以接受第二个参数(2到36之间),表示被解析的值的进制,返回该值对应的十进制数。默认情况下, parseInt 的第二个参数为 10 ,即默认是十进制转十进制。

  1. parseInt('1000', 2) // 8
  2. parseInt('1000', 6) // 216

如果第二个参数不是数值,会被自动转为一个整数。这个整数只有在 2 到 36 之间,才能得到有意义的结果,超出这个范围,则返回 NaN 。如果第二个参数是 0 、 undefined 和 null ,则直接被忽略。
如果字符串包含对于指定进制无意义的字符,则从最高位开始,只返回可以转换的数值。如果最高位无法转换,则直接返回 NaN 。

X → String

对于原始类型来说,转字符串类型会默认调用 toString() 方法。

数据类型 String类型
数字 转化为数字对应的字符串
true 转化为字符串 “true”
null 转化为字符串 “null”
undefined 转化为字符串 “undefined”
Object 转化为 “[object Object]”

x → Boolean

数据类型 转化为 true 的值 转换为 false 的值
Boolean true false
String 非空字符串 空字符串
Number 非零数值(包括无穷值) 0 、 NaN
Object 任意对象 null
Undefined N/A(不存在) undefined
  1. Boolean("") //false
  2. Boolean(undefined) // false
  3. Boolean(null) // false
  4. Boolean(NaN) // false
  5. Boolean(false) // false
  6. Boolean(0) // false
  7. Boolean({}) // true
  8. Boolean([]) // true

判断数据类型

typeof

返回的值有:

  1. "undefined"
  2. "boolean"
  3. "string"
  4. "number"
  5. "object" 表示值为对象(而不是函数)或 null
  6. "function"
  7. "symbol"

除了 null 类型以及 Object 类型不能准确判断外,其他数据类型都可能返回正确的类型。
既然 typeof 对对象类型都返回 Object 类型情况的局限性,我们可以使用 instanceof 来进行判断某个对象是不是另一个对象的实例。返回值的是一个布尔类型。

  1. typeof undefined // 'undefined'
  2. typeof null // 'object'
  3. typeof Symbol() // 'symbol'
  4. typeof Function // 'function'
  5. typeof [] // 'object'
  6. typeof {} // 'object'

instanceof

Object.prototype.toString.call()

最好的

  1. Object.prototype.toString.call(1) // "[object Number]"
  2. Object.prototype.toString.call('hi') // "[object String]"
  3. Object.prototype.toString.call({a:'hi'}) // "[object Object]"
  4. Object.prototype.toString.call([1,'a']) // "[object Array]"
  5. Object.prototype.toString.call(true) // "[object Boolean]"
  6. Object.prototype.toString.call(() => {}) // "[object Function]"
  7. Object.prototype.toString.call(null) // "[object Null]"
  8. Object.prototype.toString.call(undefined) // "[object Undefined]"
  9. Object.prototype.toString.call(Symbol(1)) // "[object Symbol]"

参考链接: