1.JavaScript 中的基本类型有哪些?以及各个数据类型是如何存储的?
javaScript 的数据类型包括原始类型和引用类型(对象类型)。
原始数据类型包括
- String
- Number
- Boolean
- null
- undefined
- Symbol
引用类型统称为 Object 类型,如果细分的话,分为以下 5 个
- Object
- Array
- Date
- RegExp
- Function
数据类型的存储形式
栈(Stack)和堆(Heap),是两种基本的数据结构。Stack 在内存中自动分配内存空间的;Heap 在内存中动态分配内存空间的,不一定会自动释放。一般我们在项目中将对象类型手动置为 null 原因,减少无用内存消耗。
原始类型是按值形式存放在栈中的数据段,内存空间可以自由分配,同时可以按值直接访问。
var a = 10;
var b = a;
b = 30;
console.log(a); // 10值
console.log(b); // 30值
引用类型是存放在堆内存中,每个对象在堆内存中有一个引用地址,就像是每个房间都有一个房间号一样。引用类型在栈中保存的就是这个对象在堆内存的引用地址,我们所说的“房间号”。通过“房间号”可以快速查找到保存在堆内存的对象。
var obj1 = new Object();
var obj2 = obj1;
obj2.name = "小鹿";
console.log(obj1.name); // 小鹿
2.为什么 typeof null 等于 Object?
不同的对象在底层原理的存储是用二进制表示的,在 javaScript中,如果二进制的前三位都为 0 的话,系统会判定为是 Object类型。null的存储二进制是 000,也是前三位,所以系统判定 null为 Object类型。
扩展:
这个 bug 个第一版的 javaScript留下来的。俺也进行扩展一下其他的几个类型标志位:
- 000:对象类型
- 1:整型,数据是31位带符号整数。
- 010:双精度类型,数据是双精度数字。
- 100:字符串,数据是字符串。
- 110:布尔类型,数据是布尔值
3.数据类型的判断 typeof 与 instanceof 有什么区别?
typeof 是一元运算符,同样返回一个字符串类型。一般用来判断一个变量是否为空或者是什么类型。
除了 null 类型以及 array 类型不能准确判断外,其他数据类型都可能返回正确的类型
typeof undefined // 'undefined'
typeof '10' // 'String'
typeof 10 // 'Number'
typeof false // 'Boolean'
typeof Symbol() // 'Symbol'
typeof Function // ‘function'
typeof null // ‘Object’
typeof [] // 'Object'
typeof {} // 'Object'
既然 typeof 对对象类型都返回 Object 类型情况的局限性,我们可以使用 instanceof 来进行判断某个对象是不是另一个对象的实例。返回值的是一个布尔类型。
var a = [];
console.log(a instanceof Array) // true
instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性
class A{}
console.log(A instanceof Function) // true
注意:原型链中的prototype 随时可以被改动的,改变后的值可能不存在于 object的原型链上,instanceof返回的值可能就返回 false。
4.类型转换
javaScript是一种弱类型语言,变量不受类型限制,所以在特定情况下我们需要对类型进行转换
「类型转换」分为显式类型转换和隐式类型转换。每种转换又分为原始类型转换和对象类型转换。
显式类型转换
其他数据类型转字符串类型 默认调用 toString() 方法
数据类型 | String类型 |
---|---|
数字 | 转化为数字对应的字符串 |
true | “true“ |
null | “null“ |
undefined | “undefined“ |
Object | 转化为 “[object Object]” |
String(123); // "123"
String(true); // "true"
String(null); // "null"
String(undefined);// "undefined"
String([1,2,3]) // "1,2,3"
String({}); // "[object Object]"
console.log(String(NaN)) // NaN
console.log(String(Infinity)) // Infinity
console.log(String(-Infinity)) // -Infinity
除了特殊的几个值 ‘’、 undefined、 NAN、 null、 false、 0 转化为 Boolean 为 false 之外,其他类型值都转化为 true。
Boolean('') // false
Boolean(undefined) // false
Boolean(null) // false
Boolean(NaN) // false
Boolean(false) // false
Boolean(0) // false
Boolean({}) // true
Boolean([]) // true
- 转化为数字类型
数据类型 | 数字类型 |
---|---|
字符串 | 数字转化为对应的数字 ;其他转化为 NaN |
布尔类型 | true 转化为 1 ; false 转化为 0 |
null | 0 |
undefined | NaN |
数组 | 数组为空转化为 0; 数组只有一个元素转化为对应元素; 其他转化为NaN |
空字符串 | 0 |
Number(10); // 10
Number([]); // 0
Number([1,2]); // NaN
Number('10a'); // NaN
Number(undefined); // NaN
console.log(Number()) // +0
console.log(Number(undefined)) // NaN
console.log(Number(null)) // +0
console.log(Number(false)) // +0
console.log(Number(true)) // 1
console.log(Number("123")) // 123
console.log(Number("-123")) // -123
console.log(Number("1.2")) // 1.2
console.log(Number("000123")) // 123
console.log(Number("-000123")) // -123
console.log(Number("0x11")) // 17
console.log(Number("")) // 0
console.log(Number(" ")) // 0
console.log(Number("123 123")) // NaN
console.log(Number("foo")) // NaN
console.log(Number("100a")) // NaN
parseInt 只解析整数,parseFloat 则可以解析整数和浮点数,如果字符串前缀是 “0x” 或者 “0X”,parseInt 将其解释为十六进制数,parseInt 和 parseFloat 都会跳过任意数量的前导空格,尽可能解析更多数值字符,并忽略后面的内容。如果第一个非空格字符是非法的数字直接量,将最终返回 NaN:
console.log(parseInt("3 abc")) // 3
console.log(parseFloat("3.14 abc")) // 3.14
console.log(parseInt("-12.34")) // -12
console.log(parseInt("0xFF")) // 255
console.log(parseFloat(".1")) // 0.1
console.log(parseInt("0.1")) // 0
- 对象类型转原始类型
对象类型在转原始类型的时候,会调用内置的 valueOf()和 toString() 方法,这两个方法是可以进行重写的。
转化原始类型分为两种情况:转化为字符串类型或其他原始类型。
1.如果已经是原始类型,不需要再进行转化。
2.如果转字符串类型,就调用内置函数中的 toString()方法。
3.如果是其他基本类型,则调用内置函数中的 valueOf()方法。
4.如果返回的不是原始类型,则会继续调用 toString() 方法。
5.如果还没有返回原始类型,则报错。
小数取整
1,Math.ceil()方法向上取整,整数部分值+1:
eg:Math.ceil(3/2) 输出:2
2,Math.floor()方法向下取整,整数部分值不变:
eg:Math.floor(3/2) 输出:1
3,Math.round()方法四舍五入取整:
eg:Math.round(3/2) 输出:2
4,parseInt()方法 抛去小数部分,只取整数部分:
eg:parseInt(3/2) 输出:1