这应该是JavaScript系列教程第三期,这期准备讲一下数据类型,常量以及变量的定义。
数据类型
任何的编程语言都有自己的数据类型与数据结构,那么JavaScipt
也有自己的数据类型,可以将其分为基本数据类型与引用数据类型!基本数据类型指的是简单的数据段,引用数据类型指的是有多个值构成的对象。当我们把变量赋值给一个变量时,解析器首先要确认的就是这个值是基本类型值还是引用类型值。
基本数据类型
在JavaScipt
中,基本类型(基本数值、基本数据类型)是一种既非对象也无方法或属性的数据。有 7 种原始数据类型:
类型 | 说明 | 备注 |
---|---|---|
number | 数字,比如1,2,0.1,1.1之类的 | 常用 |
boolean | 布尔类型,说白了就是true和false | 常用 |
undefined | 声明未定义就是undefined,表示没有任何值 | 常用 |
null | 空,表示不存在,没有任何对象 | 常用 |
类型 | 说明 | 备注 |
BigInt | 数字类型,可以表示任意精度格式的整数 | 不常用 |
symbol | 这个新的数据类型,正常用的不多,至少我没咋用过 | 不常用 |
基本数据类型是保存在栈中的,存取的速度比较快。
引用数据类型
引用数据类型我们通常统称为Object
类型,大致上分为一下5种:
类型 | 说明 | 备注 |
---|---|---|
Object | 对象,可以说是万物皆对象 | 常用 |
Array | 数组 | 常用 |
Function | 函数 | 常用 |
Data | 日期 | 常用 |
RegExp | 正则 | 常用 |
引用数据类型是保存在堆当中的,这样说可能不准确,准确的说法应该是引用数据类型的对象保存在了堆当中。
堆和栈
将堆和栈进行一下对比:
堆 | 栈 | |
---|---|---|
进出 | 先进先出 | 先进后出 |
读取 | 慢 | 快 |
释放 | 手动释放 | 自动释放 |
我们定义一个基本数据类型在栈中,应该是以下的情况。
上面的栗子就是定义了
const a = 1
const b = 2
const c = 3
const d = 4
以上看起来是挺简单的一对一的形式储存的。
我们同样来定义一下引用数据类型:
const e = new Object()
const f = e
e.name = 'orange'
以上代码的存储形式应该如下:
解释一下上面图片,左边是一个栈,定义了一个引用数据类型,名称叫做e
,然后e
在堆中开辟了一个空间,有了一个地址,所以栈中的值就是这个空间的地址,然后又定义了一个引用数据类型,叫做f
,把e
赋值给f
,这个时候值也是指向了这个空间的地址。最后给这个空间加了一个值,name:'orange'
。最后就是e
和f
其实是一个东西了。
如果你没有听清楚,没搞明白,我来给你简单翻译一下!
假如你有一个空地,这个空地就是栈,然后这个空地上面来了a,b,c,d,e,f
这几个人(也就是名称),然后呢a.b,c,d
这四个人都是本地人,就在这个空地上修了个房间(也就是值),分别放了1,2,3,4
。但是呢,e,f
他不是本地人,人家有自己房子,跑到你的地方来了,他也修了东西,但是只是一个门,这个地址(也就是值)是他家(也就是堆),刚好f
和e
是一家人,所以就用了e
的门,也通向了这个家(堆)。
不知道以上的解释清楚了没,在不清楚的话,私信我,我去做个动画给你描述清楚!!!!
类型判断与转化
在代码中,我们是怎么判断数据类型的,数据类型怎么转化呢?
类型判断
我们有很多方法可以用来判断。
方法 | 备注 |
---|---|
typeof | 常用 |
instanceof | |
Object.prototype.toString.call() | 常用 |
constructor.name | |
constructor.toString().indexOf() | |
改写constructor |
- typeof 基本只能判断出基本数据类型,引用类型除了
function
外,都是object 。
const typeOf = () => {
// 基本类型
console.log(typeof(1)); //number
console.log(typeof('1')); //string
console.log(typeof(null)); //object
console.log(typeof(false)); //boolean
console.log(typeof(undefined)); //undefined
console.log(typeof(Symbol())); //symbol
console.log(typeof(NaN)); //number
// 引用类型
console.log(typeof {}); //object
console.log(typeof []); //object
console.log(typeof Error('1')); //object
function A() {}
console.log(typeof A); //function
}
typeOf()
- instanceof 返回是
true
或false
,只能对引用数据类型进行判断。
const instanceOf = () => {
// 基本类型
console.log(1 instanceof Number); //false
console.log("1" instanceof String); //false
console.log(true instanceof Boolean); //false
console.log(null instanceof Object); //false
console.log(undefined instanceof Object); //false
console.log(Symbol() instanceof Symbol); //false
// 引用类型
console.log({} instanceof Object); //true
console.log([] instanceof Array); //true
console.log(Error('1') instanceof Error); //true
function A() {}
console.log(A instanceof Function); //true
}
instanceOf()
- Object.prototype.toString.call() 返回是一个
[object xxx]
的字符串,可以通过slice(8, -1)
的方式来获取完整的数据类型。
const stringCall = () => {
// 基本类型
console.log(Object.prototype.toString.call(1)); //[object Number]
console.log(Object.prototype.toString.call(1).slice(8, -1)) //Number
console.log(Object.prototype.toString.call('1').slice(8, -1)) //String
console.log(Object.prototype.toString.call(true).slice(8, -1)) //Boolean
console.log(Object.prototype.toString.call(null).slice(8, -1)) //Null
console.log(Object.prototype.toString.call(undefined).slice(8, -1)) //Undefined
console.log(Object.prototype.toString.call(NaN).slice(8, -1)) //Number
console.log(Object.prototype.toString.call(Symbol()).slice(8, -1)) //Symbol
// 引用数据类型
console.log(Object.prototype.toString.call({}).slice(8, -1)) //Object
console.log(Object.prototype.toString.call([]).slice(8, -1)) //Array
console.log(Object.prototype.toString.call(Error('1')).slice(8, -1)) //Error
function A() {}
console.log(Object.prototype.toString.call(A).slice(8, -1)) //Function
}
stringCall()
- 即可以判断基本数据类型,也可以判断引用数据类型,由于
null
和undefined
没有constructor
,所以判断不了,同时由于constructor
可以改变,所以此方法如果改写了constructor
,就不准确了。
const constructorName = () => {
// 基本数据类型
console.log((1).constructor.name); //Number
console.log('1'.constructor.name); //String
// console.log((null).constructor.name); //报错 Cannot read properties of null (reading 'constructor')
// console.log((undefined).constructor.name); //报错 Cannot read properties of undefined (reading 'constructor')
console.log((true).constructor.name); //Boolean
console.log((NaN).constructor.name); //Number
console.log((Symbol()).constructor.name); //Symbol
// 引用数据类型
console.log(({}).constructor.name); //Object
console.log(([]).constructor.name); //Array
console.log((Error('1')).constructor.name); //Error
function A() {}
console.log((A).constructor.name); //Function
}
constructorName()
- 可以判断基本数据类型,也可以判断引用数据类型,由于
null
和undefined
没有constructor
,所以判断不了。因为constructor.toString().indexOf()也是用到了constructor
,所以如果该写了constructor
后,就不准确了。
const toStringIndexOf = () => {
// 基本数据类型
console.log((1).constructor.toString()); //function Number() { [native code] }
console.log((1).constructor.toString().indexOf('Number') > -1) //true
console.log(('1').constructor.toString().indexOf('String') > -1) //true
// console.log((null).constructor.toString().indexOf('Null') > -1) //报错,Cannot read properties of null (reading 'constructor')
// console.log((undefined).constructor.toString().indexOf('Undefined') > -1) //报错, Cannot read properties of undefined (reading 'constructor')
console.log((Symbol()).constructor.toString().indexOf('Symbol') > -1) //true
console.log((true).constructor.toString().indexOf('Boolean') > -1) //true
console.log((NaN).constructor.toString().indexOf('Number') > -1) //true
// 引用数据类型
console.log(({}).constructor.toString().indexOf('Object') > -1) //true
console.log(([]).constructor.toString().indexOf('Array') > -1) //true
console.log((Error('1')).constructor.toString().indexOf('Error') > -1) //true
function A() {}
console.log((A).constructor.toString().indexOf('Function') > -1) //true
}
toStringIndexOf()
- 改写constructor
const num = new Number(1)
console.log((num).constructor.name); //Number
console.log((num).constructor.toString().indexOf('Number') > -1) //true
function A() {}
num.constructor = A
console.log((A).constructor.name); //Function
console.log((A).constructor.toString().indexOf('Function') > -1) //true
类型转化
这里说的类型转换是字符串和数值之间的转换。
转换成字符串
- toString(),
18.toString()
- String(),
String(18)
- 拼接,
18+''
以上三种办法都可以将数值类型转化为字符串类型。
转换为数值
- Number(),
Number('18')
- parseInt(),
parseInt('18')
- parseFloat(),
parseFloat('18')
- +或-,
-'18'
或者+'18'
以上四种方法都可以将字符串转化为字符串。
常量与变量
我们在定义的时候,分为常量与变量,一般可以使用var,const,let
来定义。
var
es5
的时候我们都是用var
来定义常量与变量。但是很容易造成变量提升或者变量的全局污染。所以我们现在很少使用这个了。
const
es6
的方法,使用const
来定义常量与变量。比如定义基础数据类型的常量,const a = 1
,这个就是定义一个a
的常量,不可以更改。这里的不可以更改指的是基础数据类型不能更改,引用数据类型不能更改其类型,但是可以更改其值。
const a = 1
const b = {
name:'orange',
age:18
}
// 修改a
a = 2 //这个肯定要报错的
b.age = 20 //这个可以更改
let
这也是es6
的语法,使用let
定义变量,不管是基础数据类型还是引用数据类型都可以,同时可以更改。
let a = 1
let b = {
name:'orange',
age:18
}
// 修改a
a = 2
b.age = 20
b = 3