js数据类型是js里面的基础,不过,也很容易出错,熟能生巧,所以得经常复习
最新的 ECMAScript 标准定义了哪 8 种数据类型
7 种基础类型:
- Boolean、Number、String
- Null、Undefined
- BigInt、Symbol(ES6)
1 种引用类型 :Object
null和undefined的区别
null表示”没有对象”,即该处不应该有值
undefined表示”缺少值”,就是此处应该有一个值,但是还没有定义
| 12
 3
 4
 5
 
 | Number(null)
 
 Number(undefined)
 
 
 | 
检查数据类型的方法
- typeof是检测一个变量是不是基本数据类型的最佳工具
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | console.log(typeof "");   
 console.log(typeof 1);
 
 console.log(typeof true);
 
 console.log(typeof undefined);
 
 console.log(typeof null);
 
 console.log(typeof {});
 
 console.log(typeof []);
 
 console.log(typeof function(){});
 
 console.log(typeof Symbol("foo"))
 
 
 | 
使用 typeof 可以准确判断出除 null 以外的基本类型,以及 function 类型、null 会被 typeof 判断为 object
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 
 | typeof Function; typeof new Function();
 typeof function() {};
 
 
 typeof Array;
 typeof Array();
 typeof new Array();
 typeof [];
 
 
 typeof Boolean;
 typeof Boolean();
 typeof new Boolean();
 
 
 
 typeof Math;
 typeof Math();
 typeof new Math();
 
 | 
构造函数 Array(..) 不要求必须带 new 关键字。不带时,它会被自动补上。 因此 Array(1,2,3) 和 new Array(1,2,3) 的效果是一样的
不推荐使用这种引用类型的基本包装对象
| 12
 3
 4
 
 | var a = new Boolean(false);if (!a) {
 console.log('Oops');
 }
 
 | 
- instanceof 检测当前实例是否隶属于某各类
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | console.log("1" instanceof String);  
 
 new Number(5) instanceof Number
 
 console.log(1 instanceof Number);
 
 console.log(true instanceof Boolean);
 
 console.log({} instanceof Object);
 
 console.log([] instanceof Array);
 
 console.log(function(){} instanceof Function)
 
 console.log(null instanceof Null);
 
 console.log(undefined instanceof Undefined);
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | let num = 1num.__proto__ === Number.prototype
 num instanceof Number
 
 num = new Number(1)
 num.__proto__ === Number.prototype
 num instanceof Number
 
 num.__proto__ === (new Number(1)).__proto__
 
 | 
- constructor 可以查看目标的构造函数
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | console.log(("1").constructor === String);   
 console.log((1).constructor === Number);
 
 console.log((true).constructor === Boolean);
 
 console.log(({}).constructor === Object);
 
 console.log(([]).constructor === Array);
 
 console.log((function() {}).constructor === Function);
 
 | 
对于 undefined 和 null,如果尝试读取其 constructor 属性,将会进行报错。
并且 constructor 返回的是构造函数本身,一般使用它来判断类型的情况并不多见
- Object.prototype.toString.call()
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | console.log(Object.prototype.toString.call("1"));   
 console.log(Object.prototype.toString.call(1));
 
 console.log(Object.prototype.toString.call(null));
 
 console.log(Object.prototype.toString.call(undefined));
 
 console.log(Object.prototype.toString.call(true));
 
 console.log(Object.prototype.toString.call({}));
 
 console.log(Object.prototype.toString.call([]));
 
 console.log(Object.prototype.toString.call(function () {});
 
 Object.prototype.toString.call(Symbol(1))
 
 
 | 
数据类型转换
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 
 | 强制转换Number()
 原始类型:有不能转为数字的,就是NaN
 Number(false) => 0
 Number(true) => 1
 Number(undefined) => NaN
 Number(null) => 0
 Number("1.2") => 1.2
 Number("12") => 12
 Number("1.2.3") => NaN
 Number(new object()) => NaN
 Number(50) => 50
 Number({}) => NaN
 String()
 原始类型值的转换规则
 数值:转为相应的字符串。
 字符串:转换后还是原来的值。
 布尔值:true转为"true",false转为"false"。
 undefined:转为"undefined"。
 null:转为"null"。
 String({a: 1}) => "[object Object]"
 String([1, 2, 3]) => "1,2,3"
 Boolean()
 false
 undefined
 null
 -0
 0或+0
 NaN
 false
 ''
 true
 所有对象,包括{}、布尔对象new Boolean(false)
 自动转换
 场景:
 不同类型的数据互相运算
 123 + 'abc' => "123abc"
 对非布尔值类型的数据求布尔值
 if ('abc')
 对非数值类型的数据使用一元运算符(即“+”和“-”)
 + {foo: 'bar'} => NaN
 本质:
 以强制类型为基础,转为需要的number、string、boolean
 
 
 | 
+ 运算符
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | console.log(1 + '1')
 
 console.log(1 + true)
 
 
 console.log(1 + false)
 
 
 console.log(1 + undefined)
 
 
 console.log('lucas' + true)
 
 
 | 
当使用 + 运算符计算 string 和其他类型相加时,都会转换为 string 类型;其他情况,都会转换为 number 类型,但是 undefined 会转换为 NaN,相加结果也是 NaN
当使用 + 运算符计算时,如果存在复杂类型,那么复杂类型将会转换为基本类型,再进行运算
“对象类型转基本类型”,具体过程:
对象在转换基本类型时,会调用该对象上 valueOf 或 toString 这两个方法,该方法的返回值是转换为基本类型的结果
具体是调用valueOf 还是toString, 这是ES规范所决定的,实际上这取决于内置的toPrimitive调用结果。主观上说,就是这个对象倾向于转换成什么,就会优先调用哪个方法,如果倾向于Number类型,则会优先调用valueOf,如果倾向于转换String类型,就只调用toString
《JavaScript 高级程序设计》以及《你不知道的 JavaScript》介绍对象转换成基本类型,会先调用valueOf,再调用toString
valueOf 以及toString是可以被开发者重写的。比如:
| 12
 3
 4
 5
 6
 7
 8
 
 | const foo () {valueOf () {
 return 27
 }
 toString() {
 return 'cm'
 }
 }
 
 | 
这时候再调用
这里“隐式转换“,使用toString方法将foo对象转换成基本数据类型
这时候的隐式转换倾向于使用valueOf方法,将其转换成基本数据类型,然后进行相加
总结:
对于 + 规则,如果两边都是Number,其规则是: 
- 如果 + 两边存在 NaN, 则结果为 NaN (typeOf NaN 是 ‘number’)
- 如果是 Infinity + Infinity , 结果是 Infinity
- 如果是 -Infinity + (-Infinity) , 结果是 -Infinity
- 如果是 Infinity + (-Infinity) , 结果是 NaN
如果 + 两边,至少有一个是字符串:
- 如果都是字符串,则进行字符串拼接
- 如果两边只有一个值是字符串,则将另外的值转为字符串,再进行拼接
- 如果两边有一个对象,则调用valueOf()或者 toString()方法取得值,转为基本类型再进行拼接
什么情况下会发生布尔值的隐式强制类型转换
(1) if (..) 语句中的条件判断表达式。
(2) for ( .. ; .. ; .. ) 语句中的条件判断表达式(第二个)。
(3) while (..) 和 do..while(..) 循环中的条件判断表达式。
(4) ? : 中的条件判断表达式。
(5) 逻辑运算符 ||(逻辑或)和 &&(逻辑与)左边的操作数(作为条件判断表达式)。
|| 与 &&
== 与 ===
常见的误区是“== 检查值是否相等,=== 检查值和类型是否相等”
正确的解释是:“== 允许在相等比较中进行强制类型转换,而 === 不允许。”
显示转换
我们也可以进行显示转换,往往使用Number, Boolean, String, parseInt 等方法进行转换
经典题目
a == 1 && a == 2 && a == 3 可能为 true 吗?
直观分析,a不可能是基本 Number 类型, 这是不可能为true, 因此我们应该考虑a是一个对象,转换成基本类型,再进行运算
方案一: 改写valueOf, toString方法
| 12
 3
 4
 5
 6
 7
 
 | const a = {value: 1,
 toString () {
 return a.value++;
 }
 }
 a == 1 && a == 2 && a == 3
 
 | 
重写valueOf方法同样也能做到
方案二: Object.defineProperty()将a定义为一个全局对象window的属性
| 12
 3
 4
 5
 6
 7
 
 | let value = 0Object.defineProperty(window, 'a', {
 get: function () {
 return ++value
 }
 })
 a == 1 && a == 2 && a == 3
 
 | 
封装一个 javascript 的类型判断函数?
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | function getType(value) { 
 if (value === null) {
 return value + "";
 }
 
 if (typeof value === "object") {
 let valueClass = Object.prototype.toString.call(value),
 type = valueClass.split(" ")[1].split("");
 type.pop();
 return type.join("").toLowerCase();
 } else {
 
 return typeof value
 }
 }
 
 |