你了解JS的数据类型吗? 这应该是js中最基础的一个问题了, 可是就从这最基础的一个问题, 你能挖掘多深呢?
本文将从以下几个方面进行梳理
文章目录
js的基本数据类型有哪些
1.js基本数据类型有六种
- undefined
- Boolean
- Number
- String
- BigInt(可以用任意精度表示整数, 安全的存储和操作大整数)
- Symbol
2.null是一种特殊的数据类型, 在被typeof判断的时候会被判断成object
3.引用数据类型
包括对象, 数组, 函数等
基本数据类型和引用数据类型的区别是什么
- 基本数据类型存放在栈内存中, 而引用数据类型存放在堆内存中
- 基本数据类型复制可以直接拿到值本身, 而引用类型复制时只能拿到数据的内存地址, 因此需要进行深拷贝
- 判断类型时, 基本类型使用typeof即可判断,但是typeof检测引用类型时只会判断出是object, 不能得到具体的类型. 所以引用类型必须要通过instanceof判断或者原型的方法判断
判断数据类型的方法
判断基本数据类型
undefined:typeof instance === "undefined"
Boolean:typeof instance === "boolean"
Number:typeof instance === "number"
String:typeof instance === "string
BigInt:typeof instance === "bigint"
Symbol :typeof instance === "symbol"
对于复杂类型
var a = [1,2,3];
var b = new Date();
var c = function(){}
//结果如下
typeof a === 'object' //true
typeof b === 'object' //true
typeof c === 'function' //true
无法判断Object类型中的具体类型, 所以这时需要用到instanceof
判断Object类型
顾名思义, instanceof的原理就是判断当前元素是否是某构造函数的实例
a instanceof Array //true
b instanceof Date //true
c instanceof Function //true
a instanceof Object //true
b instanceof Object //true
c instanceof Object //true
为什么a instanceof Object
为真呢?
因为所有函数包括Array,Date等构造函数, 都是Object的实例
其实也可以理解为, Array等构造函数的原型肯定是一个对象, 那对象的构造函数肯定是Object;
也可以理解
Array.prototype.__proto__ = Object.prototype
还有一些特殊情况
Object instanceof Function // true
Function instanceof Object //true
可以理解为是Object
本身就是一个构造函数, 所以肯定是Function
的实例
而Function
的原型又是一个对象, 所以反之也成立
通过Object.prototype判断
Object.prototype.toString.call(a) // 'object Array'
Object.prototype.toString.call(b) // 'object Date'
Object.prototype.toString.call(c) // 'object Function'
Object.prototype.toString.call(null) // 'object Null' //特殊记忆
值得一提的是,就是toString
方法,下面来看
toString方法
var num = 123
num.toString() // '123'
var str = 'hello'
str.toString() // 'hello'
var bool = false
bool.toString() // 'false'
var arr = [1, 2, 3]
arr.toString() // '1,2,3'
var obj = {lang:'zh'}
obj.toString() // '[object Object]'
var fn = function(){}
fn.toString() // 'function(){}'
null.toString() // Cannot read property 'toString' of null
undefined.toString() // Cannot read property 'toString' of undefined
平时我们用到的toString
方法是将其他类型转换为字符串, 下面看一下对象Object.prototype上的toString方法
Object.toString()//"function Object() { [native code] }"
Object.prototype.toString()//"[object Object]"
对象上的toString
方法输出的是一个函数, 而原型上的toString
方法输出的是数据类型
其实在我们熟知的Array
Function
Object
等构造函数上都有定义toString
方法
不同数据类型之间的转换
既然toString
是将其他类型转换为字符串类型, 那么不同数据类型之间怎么转换呢
我们进行计算或转换的数据类型通常是字符串和数组, 数字之间的转换
字符串和数字的转换
字符串转数字, 有parseInt, parseFloat,Number三种, 具体区别不多说
let a = '123'
parseInt(a) //123
parseFloat(a) //123
Number(a) //123
let b = '123.4'
parseInt(b) //123
parseFloat(b) //123.4
Number(b) //123.4
let c = '123.4c'
parseInt(c) //123
parseFloat(c) //123.4
Number(c) //NaN
数字转字符串
let a = 1
let b = a+'' //'1'
let c = a.toString() //'1'
字符串和数组的转换
字符串转数组
let a = '123'
let b = a.split('') // ['1','2','3']
数组转字符串
let a = ['1','2','3']
let b = a.join('') //'123'
堆和栈的区别
js中基本数据类型存储在栈内存中, 引用类型存储在堆内存中, 那么堆和栈的主要区别有哪些呢?
主要区别有:
- 在c++中栈内存是系统自行分配的; 堆内存是手动申请的
- 栈内存是一段连续的有限空间; 堆内存是不连续的随机的空间(引用类型所占内存不固定)
- 栈的存取速度比较快, 使用完成后立即释放,会被垃圾回收; 堆内存存取速度比较慢, 但是申请使用比较灵活; 但是要所有的引用都销毁之后才会被垃圾回收
null存在栈内存中
闭包中的基本数据类型变量是保存在堆内存里的,当函数执行完弹出调用栈后,返回一个内部函数的一个引用,这时候函数的变量就会转移到堆上,因此内部函数依然能访问到上一层函数的变量。
题外话: 原本以为每天写一篇小面试题还挺容易的, 没想到想写的详细还挺费时间的, 不知道自己能坚持几天, 也不知道有没有人看