数据类型

在 ES6 前,JavaScript 共六种数据类型,分别是:
Undefined、Null、Boolean、Number、String、Object
ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。
其中Object属于引用类型,其他属于基本数据类型。

基本数据类型是按值访问的,因为可以直接操作保存在变量中的实际值。 引用类型的值是保存在内存中的对象。比如:Object 、Array 、Function 、Data等

  • 与其他语言不同的是,JavaScript不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象。所以引用类型的值是按引用访问的。

类型转换

js是弱类型语言,类型之间的变量相遇会发生在大多数编程语言中不会发生的不可思议的事。

类型隐式转换

隐式转换中主要涉及到三种转换:
1、将值转为原始值,ToPrimitive()。
2、将值转为数字,ToNumber()。
3、将值转为字符串,ToString()。

基本类型转换

比如:
Number(true) // 1
Number(false) // 0
Javascript在遇到算数运算符(- 、* 、/ 和 %)的时候会在运算之前将参与运算的双方转换成数字。

‘+’运算符

JavaScript 首先会将操作符两侧的对象转换为 Primitive 类型。
它更偏爱字符串多一点,如果遇到有字符串,她会将数字等(toString())转换为字符串,然后执行字符串连接操作。否则隐式转换为数字,转换不了数字的

  1. 1 + 2 = 12
  2. true + 1 = 2
  3. true + '1' = 'true1'
  4. undefined + '1' = 'undefined1'
  5. 1 + [1] = '11'
  6. 1 + {} = '1[object Object]'

比较运算

JavaScript 为我们提供了严格比较与类型转换比较两种模式,严格比较(===)只会在操作符两侧的操作对象类型一致,并且内容一致时才会返回为 true,否则返回 false。而更为广泛使用的 == 操作符则会首先将操作对象转化为相同类型,再进行比较。对于 <= 等运算,则会首先转化为原始对象(Primitives),然后再进行对比。

条件判断运算 == 中的转换规则是这样的:

如果 x 或 y 中有一个为 NaN,则返回 false; 如果 x 与 y 皆为 null 或 undefined 中的一种类型,则返回 true(null == undefined // true);否则返回 false(null == 0 // false); 如果 x,y 类型不一致,且 x,y 为 String、Number、Boolean 中的某一类型,则将 x,y 使用 toNumber 函数转化为 Number 类型再进行比较; 如果 x,y 中有一个为 Object,则首先使用 ToPrimitive 函数将其转化为原始类型,再进行比较。

image.png
image.png
image.png

  1. null > 0 // false
  2. null < 0 // false
  3. null == 0 // false
  4. null >= 0 // true
  5. // 加法
  6. true + 1 // 1
  7. undefined + 1 // NaN
  8. let obj = {};
  9. {} + 1 // 1,这里的 {} 被当成了代码块
  10. { 1 + 1 } + 1 // 1
  11. obj + 1 // [object Object]1
  12. {} + {} // Chrome 上显示 "[object Object][object Object]",Firefox 显示 NaN
  13. [] + {} // [object Object]
  14. [] + a // [object Object]
  15. + [] // 等价于 + "" => 0
  16. {} + [] // 0
  17. a + [] // [object Object]
  18. [2,3] + [1,2] // '2,31,2'
  19. [2] + 1 // '21'
  20. [2] + (-1) // "2-1"
  21. // 减法或其他操作,无法进行字符串连接,因此在错误的字符串格式下返回 NaN
  22. [2] - 1 // 1
  23. [2,3] - 1 // NaN
  24. {} - 1 // -1

[] == ![] 这个比较运算,首先 [] 为对象,则调用 ToPrimitive 函数将其转化为字符串 “”;对于右侧的 ![],首先会进行显式类型转换,将其转化为 false。然后在比较运算中,会将运算符两侧的运算对象都转化为数值类型,即都转化为了 0,因此最终的比较结果为 true。在上文中还介绍了 null >= 0 为 true 的这种比较结果,在 ECMAScript 中还规定,如果 < 为 false,则 >= 为 true。

判断变量方式

  • typeof
  • instanceof
  • Object.prototype.toString

typeof

typeof 是一元操作符,放在其单个操作数的前面,操作数可以是任意类型。返回值为表示操作数类型的一个字符串。

ES6之前typeof能检测六种类型的值,(null比较特殊,返回’object’)分别是:
image.png
ES6新增的symbol类型也能检测,除此之外 Object 下还有很多细分的类型呐,如 Array、Date、RegExp、Error 等都只能返回’object’。
image.png

instanceof

instanceof 用于判断一个变量是否某个对象的实例。obj instanceof Object。
原理:基于原型链操作,判断左边的左操作数的对象的原型链上是否有右边这个构造函数的prototype属性。
左操作数为对象,不是就返回false,右操作数必须是函数对象或者函数构造器,不是就返回typeError异常。
image.png

instanceof在判断对象是不是数组,Data,正则等时很好用。 问题:不同window或iframe之间的对象类型检测不能使用instanceof!

Object.prototype.toString

当 toString 方法被调用的时候,下面的步骤会被执行:

  1. 如果 this 值是 undefined,就返回 [object Undefined]
  2. 如果 this 的值是 null,就返回 [object Null]
  3. 让 O 成为 ToObject(this) 的结果
  4. 让 class 成为 O 的内部属性 [[Class]] 的值
  5. 最后返回由 “[object “ 和 class 和 “]” 三个部分组成的字符串

通过规范,我们至少知道了调用 Object.prototype.toString 会返回一个由 “[object “ 和 class 和 “]” 组成的字符串,而 class 是要判断的对象的内部属性。

  1. Object.prototype.toString.call()一些变量,得到:
  2. var number = 1; // [object Number]
  3. var string = '123'; // [object String]
  4. var boolean = true; // [object Boolean]
  5. var und = undefined; // [object Undefined]
  6. var nul = null; // [object Null]
  7. var obj = {a: 1} // [object Object]
  8. var array = [1, 2, 3]; // [object Array]
  9. var date = new Date(); // [object Date]
  10. var error = new Error(); // [object Error]
  11. var reg = /a/g; // [object RegExp]
  12. var func = function a(){}; // [object Function]
  13. Object.prototype.toString.call(Math) // [object Math]
  14. Object.prototype.toString.call(JSON) // [object JSON]
  15. function a() {
  16. console.log(Object.prototype.toString.call(arguments)); // [object Arguments]
  17. }
  1. // 判断变量类型封装的方法
  2. let isType = function() {
  3. var class2type = {};
  4. // 生成class2type映射
  5. "Boolean Number String Function Array Date RegExp Object Error".split(" ").map(function(item, index) {
  6. class2type["[object " + item + "]"] = item.toLowerCase();
  7. })
  8. return function type(obj) {
  9. if (obj == null) {
  10. return obj + "";
  11. }
  12. return typeof obj === "object" || typeof obj === "function" ?
  13. class2type[Object.prototype.toString.call(obj)] || "object" :
  14. typeof obj;
  15. }
  16. }();

JavaScript 运算符规则与隐式类型转换详解