0%

js数据类型

js数据类型是js里面的基础,不过,也很容易出错,熟能生巧,所以得经常复习

最新的 ECMAScript 标准定义了哪 8 种数据类型

7 种基础类型:

  • Boolean、Number、String
  • Null、Undefined
  • BigInt、Symbol(ES6)

1 种引用类型 :Object

null和undefined的区别

null表示”没有对象”,即该处不应该有值

undefined表示”缺少值”,就是此处应该有一个值,但是还没有定义

1
2
3
4
5
Number(null)
// 0

Number(undefined)
// NaN
检查数据类型的方法
  1. typeof是检测一个变量是不是基本数据类型的最佳工具
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
console.log(typeof "");   // string

console.log(typeof 1); // number

console.log(typeof true); // boolean

console.log(typeof undefined); // undefined

console.log(typeof null); // object

console.log(typeof {}); // object

console.log(typeof []); // object

console.log(typeof function(){}); // function

console.log(typeof Symbol("foo")) // symbol

使用 typeof 可以准确判断出除 null 以外的基本类型,以及 function 类型、null 会被 typeof 判断为 object

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
typeof Function; // 'function'
typeof new Function(); // 'function'
typeof function() {}; // 'function'

// 引用类型的子类型
typeof Array; // 'function' Array是一个构造函数
typeof Array(); // 'object' Array()构造出来的结果是一个Array, 所以打印Object
typeof new Array(); // 'object'
typeof []; // 'object'

// 引用类型的基本包装类型
typeof Boolean; // "function" Boolean是一个构造函数
typeof Boolean(); // "boolean" Boolean()直接执行得到布尔值
typeof new Boolean(); // "object" new出来的是一个Boolean对象
// 通过构造函数创建出来了的是封装了基本类型的封装对象


typeof Math; // 'object' Math是内置的对象,不是函数,也不是构造器
typeof Math(); // Math is not a function
typeof new Math(); // Math is not a constructor

构造函数 Array(..) 不要求必须带 new 关键字。不带时,它会被自动补上。 因此 Array(1,2,3) 和 new Array(1,2,3) 的效果是一样的

不推荐使用这种引用类型的基本包装对象

1
2
3
4
var a = new Boolean(false);
if (!a) { // 这里 a 是一个封装对象,而不是一个布尔值,所以永远都是true
console.log('Oops'); // 执行不到这里
}
  1. instanceof 检测当前实例是否隶属于某各类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
console.log("1" instanceof String);  // false
// 是因为 1 是基本类型,它并不是 String 构造函数构造出来的实例对象

new Number(5) instanceof Number // true

console.log(1 instanceof Number); // false

console.log(true instanceof Boolean); // false

console.log({} instanceof Object); // true

console.log([] instanceof Array); // true

console.log(function(){} instanceof Function) // true

console.log(null instanceof Null); // 报错

console.log(undefined instanceof Undefined); // 报错
1
2
3
4
5
6
7
8
9
let num = 1
num.__proto__ === Number.prototype // true
num instanceof Number // false

num = new Number(1)
num.__proto__ === Number.prototype // true
num instanceof Number // true

num.__proto__ === (new Number(1)).__proto__ // true
  1. constructor 可以查看目标的构造函数
1
2
3
4
5
6
7
8
9
10
11
console.log(("1").constructor === String);   // true

console.log((1).constructor === Number); // true

console.log((true).constructor === Boolean); // true

console.log(({}).constructor === Object); // true

console.log(([]).constructor === Array); // true

console.log((function() {}).constructor === Function); // true

对于 undefined 和 null,如果尝试读取其 constructor 属性,将会进行报错。
并且 constructor 返回的是构造函数本身,一般使用它来判断类型的情况并不多见

  1. Object.prototype.toString.call()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
console.log(Object.prototype.toString.call("1"));   // {object  String}

console.log(Object.prototype.toString.call(1)); // {object Number}

console.log(Object.prototype.toString.call(null)); // {object Null}

console.log(Object.prototype.toString.call(undefined)); // {object Undefined}

console.log(Object.prototype.toString.call(true)); // {object Boolean}

console.log(Object.prototype.toString.call({})); // {object Object}

console.log(Object.prototype.toString.call([])); // {object Array}

console.log(Object.prototype.toString.call(function () {}); // {object Fuction}

Object.prototype.toString.call(Symbol(1)) // "[object Symbol]"

数据类型转换
1
2
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

+ 运算符
1
2
3
4
5
6
7
8
9
10
11
12
13
14
console.log(1 + '1')
// 11

console.log(1 + true)
// 2

console.log(1 + false)
// 1

console.log(1 + undefined)
// NaN

console.log('lucas' + true)
// lucastrue

当使用 + 运算符计算 string 和其他类型相加时,都会转换为 string 类型;其他情况,都会转换为 number 类型,但是 undefined 会转换为 NaN,相加结果也是 NaN

1
2
console.log({} + true)
// [object Object]true

当使用 + 运算符计算时,如果存在复杂类型,那么复杂类型将会转换为基本类型,再进行运算

“对象类型转基本类型”,具体过程:
对象在转换基本类型时,会调用该对象上 valueOf 或 toString 这两个方法,该方法的返回值是转换为基本类型的结果

具体是调用valueOf 还是toString, 这是ES规范所决定的,实际上这取决于内置的toPrimitive调用结果。主观上说,就是这个对象倾向于转换成什么,就会优先调用哪个方法,如果倾向于Number类型,则会优先调用valueOf,如果倾向于转换String类型,就只调用toString

《JavaScript 高级程序设计》以及《你不知道的 JavaScript》介绍对象转换成基本类型,会先调用valueOf,再调用toString

valueOf 以及toString是可以被开发者重写的。比如:

1
2
3
4
5
6
7
8
const foo () {
valueOf () {
return 27
}
toString() {
return 'cm'
}
}

这时候再调用

1
alert(foo); // cm

这里“隐式转换“,使用toString方法将foo对象转换成基本数据类型

1
console.log(1 + foo); // 28

这时候的隐式转换倾向于使用valueOf方法,将其转换成基本数据类型,然后进行相加

总结:
对于 + 规则,如果两边都是Number,其规则是:

  1. 如果 + 两边存在 NaN, 则结果为 NaN (typeOf NaN 是 ‘number’)
  2. 如果是 Infinity + Infinity , 结果是 Infinity
  3. 如果是 -Infinity + (-Infinity) , 结果是 -Infinity
  4. 如果是 Infinity + (-Infinity) , 结果是 NaN

如果 + 两边,至少有一个是字符串:

  1. 如果都是字符串,则进行字符串拼接
  2. 如果两边只有一个值是字符串,则将另外的值转为字符串,再进行拼接
  3. 如果两边有一个对象,则调用valueOf()或者 toString()方法取得值,转为基本类型再进行拼接
什么情况下会发生布尔值的隐式强制类型转换

(1) if (..) 语句中的条件判断表达式。
(2) for ( .. ; .. ; .. ) 语句中的条件判断表达式(第二个)。
(3) while (..) 和 do..while(..) 循环中的条件判断表达式。
(4) ? : 中的条件判断表达式。
(5) 逻辑运算符 ||(逻辑或)和 &&(逻辑与)左边的操作数(作为条件判断表达式)。

|| 与 &&
1
2
3
4
a || b;
// 大致相当于(roughly equivalent to): a ? a : b;
a && b;
// 大致相当于(roughly equivalent to): a ? b : a;
== 与 ===

常见的误区是“== 检查值是否相等,=== 检查值和类型是否相等”
正确的解释是:“== 允许在相等比较中进行强制类型转换,而 === 不允许。”

显示转换

我们也可以进行显示转换,往往使用Number, Boolean, String, parseInt 等方法进行转换

经典题目

a == 1 && a == 2 && a == 3 可能为 true 吗?
直观分析,a不可能是基本 Number 类型, 这是不可能为true, 因此我们应该考虑a是一个对象,转换成基本类型,再进行运算

方案一: 改写valueOf, toString方法

1
2
3
4
5
6
7
const a = {
value: 1,
toString () {
return a.value++;
}
}
a == 1 && a == 2 && a == 3 // true

重写valueOf方法同样也能做到

方案二: Object.defineProperty()将a定义为一个全局对象window的属性

1
2
3
4
5
6
7
let value = 0
Object.defineProperty(window, 'a', {
get: function () {
return ++value
}
})
a == 1 && a == 2 && a == 3
封装一个 javascript 的类型判断函数?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function getType(value) { 
// 判断数据是 null 的情况
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
}
}