Javascript中的基本数据类型以及区别

概要

ECMAscript有6中基本数据类型,也成为原始数据类型:Undefined、Null、Boolean、Number、String、和Symbol。还有一种复杂的数据类型结构称为Object(对象),Object是一种无序键值对的数据集合。基本数据类型的含义如下:

  • “undifined”表示未定义
  • “boolean”表示值为布尔值
  • “string”表示值为字符串
  • “number”表示值为数值
  • “object”表示值为对象或null
  • “function”表示值为函数
  • “symbol”表示值为符号

Undifined类型

Undifined类型只有一个值,即为undifined。使用var或者let声明变量但没有初始化时,变量的默认值即为undifined

let name;
console.log(name===undifined);  //true

注意:值undifined主要用于比较,在ECMAScript第3版之前是不存在的,增加的主要目的是为了明确空对象指针null和未初始化变量的区别
如下例子说明undifined和未定义变量的区别:

let color

console.log(color)  // undifined
console.log(fruit)  // 报错

对未声明的变量只能进行一个有用的操作,那就是对它调用typeof

let color

console.log(typeof color) // undifined
console.log(typeof fruit) // undifined

Null

Null类型同样只有一个值,即为null,表示空对象指针,这就是null也是对象的原因

let color = null
console.log(typeof color) // object

因此在定义对象变量的时候,建议使用nul进行初始化,这样通过判断值是否为null,就可以知道变量是否为对象的引用

if (person != null) {
  // person是一个对象的引用
}

undifined是由null派生而来的,因此它俩表面上是相等的,实际上是不相等的

console.log(null == undefined)  // true
console.log(null === undefined)  // false

Boolean类型

Boolean类型有两个字面值:true和false,并且它们是区分大小写的,True和False是有效的标识符,但不是布尔值。
虽然布尔值只有两个,但其他类型的值都有相应布尔值的等价形式,要将其他类型的值转换为布尔类型,可以使用Boolean转型函数

let msg = 'Always believe that something good is about to happen'
let msgAsBoolean = Boolean(msg)

字符串msg会被转换为布尔值并保存在变量msgAsBoolean中,Boolean转型函数可以用在任何类型的数据上,始终返回一个布尔值
不同类型的值与布尔值之间的转换规则如下:

数据类型 转换结果为true 转换结果为false
Boolean true false
String 非空字符串 ""空字符串
Number 非零数值(包括无穷值) 0、NaN
Object 任意对象 null
Undifined N/A(不存在) undifined

Number类型

Number类型包含整数和浮点数,整数包括十进制、八进制、或者十六进制。八进制在严格模式下是无效的会导致JS引擎抛出语法错误,各进制表示如下:

// 十进制
let intN = 55
// 八进制
let octalN = 070
// 十六进制
let hexN = 0xA

注意:由于JS数值保存的规则,可能存在正零和负零的情况(+0,-0),正零和负零在所有情况下都是相等的。

1.浮点值

浮点值即数值中必须包含小数点,并且小数点后至少有一位数字,小数点前的整数不是必须的,但推荐加上

let float1 = 3.2
let float2 = 0.2
let float3 = .2 // 有效但不推荐

由于浮点值占用的内存是整数的两倍,所以JS总是尽量将值转换为整数。在小数点后没有值得情况下,数值就会变成整数,小数点后的数字是0(2.0),也会被转化为整数。
对于非常大或者非常小的数可以采用科学计数法,如:

let floatNum1 = 3.1415926e15
let floatNum2 = 6e-15

注意:永远不要测试某个特定的浮点值,因为0.1余0.2的和并不为0.3,这是因为使用了IEEE754数值,但0.05和0.25,0.15和0.15的和是0.3

2.数值范围

可以表示的最小的数值保存在Number.MIN_VALUE中,为5e-324,最大数值保存在Number.MAX_VALUE中,在大多数浏览器中是1.797 693 134 862 315 7e+308,如果计算的数值不在这个范围内,就会转换为Infinity(正无穷大)和-Infinity(负无穷大)

3.NaN

即为Not a Number,意思是“不是数值”,用于表示本来要返回数值的操作失败而不是抛出错误。比如:

console.log(0/0)  // NaN
console.log(-0/+0)  // NaN

如果分子非0,分母为0或-0则返回Infinity或-Infinity

注意:任何上涉及NaN的操作都会返回NaN,并且NaN不等于NaN,如果要判断一个数值不是数值可以用isNaN(),任何不能转换为数值的值都会返回true

4.数值转换

Number()、parseInt()、parseFloat()这几个函数可以将非数值转换为数值。Number是转型函数,可以用于任何类型数据,parseInt()、parseFloat()主要用于将字符串转换为数值。
Number()函数转换规则如下:

  1. 布尔值,true转为1,false转为0
  2. 数值,直接返回
  3. null,返回0
  4. undifined,返回NaN
  5. 字符串,有如下规则
  • 如果字符串包含数值字符,则尽可能转为十进制整数
  • 如果字符串包含有效的浮点值(1.1),则转为相应的浮点值
  • 如果字符串包含有效的16进制数值(0xf),则转换为十进制整数
  • 如果是空字符串则返回0
  • 除上述情况之外则返回NaN
  1. 对象,调用valueOf()方法,按照上述规则转换,如果转换结果为NaN,则调用toString()方法,在按照转换字符串的方法转换

parseInt()方法更专注于字符串是否包含数值模式,字符串最前面的空格会被忽略,比如“12345apple”会被转换为12345,22.5会被转换为22
parseInt()可以接收第二个参数,用于指定底数,如:

let num1 =parseInt("20", 2)
let num1 =parseInt("20", 8)
let num1 =parseInt("20", 10)
let num1 =parseInt("20", 16)

parseFloat()的工作方式类似parseInt,只有首次出现的小数点有效,parseFloat只解析十进制数值,因此不能指定底数

String类型

字符串有若干16位Unicode字符序列组成,可以用双引号(“”),单引号(‘’),反引号(``)表示,如下都是合法的表示形式:

let color = "red"
let color = 'red'
let color = `red`

字符串是不可变的,一旦创建值就不能改变,只能销毁原先的字符串,将新的字符串赋值到该变量

1. 字符串字面量

字符串类型包含一些字符串字面量,用于表示非打印字符或其他用途的字符,如下表:

字面量 含义
\n 换行
\t 制表
\b 退格
\r 回车
\f 换页
\ 反斜杠
' 单引号
" 双引号
` 反引号
\xnn 以16进制nn表示的字符,如\x41等于'A'
\unnnn 以16进制nnnn表示的Unicode字符,如\u03a3表示‘∑’

这些字符串字面量可以出现在字符串的任意位置,可以作为单个字符被解释,如:

let msg = 'Hello, do you know this letter: \u03a3

注意:转义字符只算做一个字符,如果字符串中包含双字节字符,那么length属性返回的长度可能不准确

2. 字符串转换

把一个值转为字符串有两个方法,toString()和String()转型函数。
几乎所有的数据类型都有toString()方法,出了null和undifined,在数值调用toString()方法时,可以传入一个底数参数,用来表示输出数据的字符串啊表示,如:

let num = 11
console.log(num.toString()) // "11"
console.log(num.toString(2)) // "1011"
console.log(num.toString(8)) // "13"
console.log(num.toString(16)) // "b"

如果不确定一个值是不是null或者undifined,可以调用String()转型函数,它始终会返回相应类型值的字符串。它的转换规则如下:

  • 如果有toString()方法,则调用方法
  • 如果是null,返回‘null’
  • 如果是undifined返回undifined

3. 模板字面量

模板字面量是ES6新增的,和单引号和双引号相比较,模板字面量可以保留换行字符,并且可以跨行定义字符串

let msg = `Hello \n world`
let msg = `Hello
world`
let template = `
<div>
  <p>每个不曾起舞的日子,都是对生命的辜负</p>
</div>`

以前的字符串拼接通过“+”连接,使用模板字面量插值可以很方便的实现同样的功能

const color = 'green'
// 以前这样实现
let msg1 = color + 'is my favriate color'
// 现在这样实现
let msg2 = `${color} is my favriate color`

并且插入的值都会调用toString()方法强制转换为字符串,任何表达式都可用于插值,如:

const say = { toString: () => 'World' }
console.log(`Hello ${ say }`)  // Hello World

4. 模板字面量标签函数

通过标签函数可以自定义插值行为,标签函数接收的参数一次是原始字符串和对每个表达式求值的结果

let num1 = 3
let num2 = 2

function tagFunc (strings, ...expressions) {
  console.log(strings)
  for (const expression of expressions) {
    console.log(expression)
  }
}

let tagResult = tagFunc`${ num1 } + ${ num2 } = ${ num1 + num2 }`
// ["", " + ", " = ", ""]
// 3
// 2
// 5

5. 原始字符串

模板字面量可以获取原始模板字面量内容,而不是被转换后的字符,可以使用String.raw标签函数

console.log(`\u00A9`)
console.log(Stirng.raw`\u00A9`)

Symbol类型

Symbol作为JavaScript ES6新的原始数据类型,表示独一无二的值。它有以下几个特性:

1.无法用new进行显式定义

let a = Symbol()
let b = new Symbol() // 报错

2.typeOf返回的值为Symbol

var sym = Symbol('foo')
typeof sym    // 'symbol'

3.symbol属性是不可枚举的
symbol不会在for循环、for(...in...)中出现,因为这个属性是匿名的

let temp = {
    [Symbol('people')]: 'symbol类型',
    id: 123,
    des: '定义类型'
}

for (let prop in temp ) {   
    console.log(prop)   // 分别会输出:'id' 和 'des'
}

4.Object.getOwnPropertySymbols()该方法可以返回一个包含所有Symbol自有属性的数组

let temp = {    
    [Symbol('people')]: 'symbol类型',    
    id: 123,    
    des: '定义类型'
}
Object.getOwnPropertySymbols(temp) // [Symbol(people)]

5. Object.keys()和Object.getOwnPropertyNames()方法可以检索对象中所有的属性名,前一个方法返回所有的可枚举属性名.后一个方法不考虑属性的可枚举性一律返回,但都不能返回symbol属性

Object.keys(temp )   // ['id', 'des']
Object.getOwnPropertyNames(obj)   // ['id', 'des']

6. 定义两个相同的Symbol数据是不相等的
如果要创建就一个共享的Symbol需要用到Symbol.for()方法.
Symbol.for()方法首先在全局Symbol注册表中搜索键为‘uid’的Symbol是否存在,如果存在,直接返回已有的Symbol;否则,创建一个新的Symbol,并使用这个键在Symbol全局注册表中注册,随机返回新创建的Symbol。

let a = Symbol('AAA')
let b = Symbol('AAA')    
console.log(a === b) // false
    
let c = Symbol.for('uid')
let d = Symbol.for('uid')
    
console.log(c === d) // true

7. 使用JSON.stringify()时,以symbol值作为键的属性会被忽略

JSON.stringify({[Symbol('foo')]: 'foo'});                 
// '{}'

Object类型

ECMA中的对象其实就是一组数据和功能的集合。对象可以通过执行new操作符后跟要创建的对象类型的名称来创建。而创建Object类型的实例并为其添加属性和方法,就可以创建自定义对象,这个语法与Java中创建对象的语法相似。但在ECMA中,如果不给构造函数传递参数,则可以省略后面的那一对圆括号。如下所示:

var o = new Object()
var o = new Object

在ECMA中,Object类型是所有它的实例的基础。Object类型所具有的任何属性和方法也同样存在于更具体的对象中,就像Java中的java.lang.object对象一样。

Object的每个实例都具有下列属性和方法:

  • constructor:保存着用于创建当前对象的函数。对于前面的例子而言,构造函数(constructor)就是Object()。
  • hasOwnProperty(propertyName):用于检查给定的属性在当前对象实例中(而不是在实例的原型中)是否存在。其中,作为参数的属性名必须以字符串形式指定。如:o.hasOwnProperty("name")。
  • isPrototypeOf(object):用于检查调用的对象是否是传入对象的原型。
  • propertyIsEnumerable(propertyName):用于检查给定的属性是否能够使用for-in语句来枚举。作为参数的属性名必须以字符串形式指定。
  • toLocaleString():返回对象的字符串表示,该字符串与执行环境的地区对应。
  • toString():返回对象的字符串表示。
  • valueOf():返回对象的字符串、数值或布尔值表示。通常与toString()方法的返回值相同。
posted @ 2021-07-12 22:15  Elwin0204  阅读(314)  评论(0编辑  收藏  举报