JavaScript 系列二:数据类型 (下)
在下篇中,我们将继续讨论以下数据类型
String 类型
BigInt 类型
Symbol 类型
Object 类型
数值类型转换
String 类型
String (字符串)数据类型表示零或多个 16 位 Unicode 字符序列。字符串可以使用双引号( "" )、单引号('')或反引号( ` ` )标示。
let xhsFirstName = 'John'
let xhsLastName = 'Jacob'
let xhsLastName = `Jingleheimerschmidt`
let xhsError = 'Nicholas"; // 语法错误:开头和结尾的引号必须是同一种
字符字面量
语法
字面量是由语法表达式定义的常量,或通过由一定字词组成的语词表达式定义的常量。
字符串数据类型包含一些字符字面量,用于表示非打印字符或有其他用途的字符。
字 面 量 | 含 义 |
\n | 换行 |
\t | 制表 |
\b | 退格 |
\r | 回车 |
\f | 换页 |
\ | 反斜杠(\) |
\ | 单引号('),在字符串以单引号标示时使用,例如'He said, \'hey.\'' |
\" | 双引号("),在字符串以双引号标示时使用,例如"He said, \"hey.\"" |
\` | 反引号(\`),在字符串以反引号标示时使用,例如\` He said, \` hey.\`` |
\xnn | 以十六进制编码 nn 表示的字符(其中 n 是十六进制数字 0~F),例如\x41 等于"A" |
\unnnn | 以十六进制编码 nnnn 表示的 Unicode 字符(其中 n 是十六进制数字 0~F),例如\u03a3 等于希腊字符"Σ" |
这些字符字面量可以出现在字符串中的任意位置,且可以作为单个字符被解释:
let text = 'This is the letter sigma: \u03a3.'
在这个例子中,即使包含 6 个字符长的转义序列,变量 text 仍然是 28 个字符长。因为转义序列表示一个字符,所以只算一个字符。
console.log(text.length) // 28 字符串的长度获取
这个属性返回字符串中 16 位字符的个数。
注意: 如果字符串中包含双字节字符,那么 length 属性返回的值可能不是准确的字符数。
字符串的特点
字符串是不可变的,意思是一旦创建,它们的值就不能变了。要修改某个变量中的字符串值,必须先销毁原始的字符串,然后将包含新值的另一个字符串保存到该变量。
let lang = 'Java'
lang = lang + 'Script'
这里,变量 lang
一开始包含字符串"Java"
。紧接着,lang
被重新定义为包含"Java"
和"Script"
的组合,也是"JavaScript"
。整个过程首先会分配一个足够容纳 10 个字符的空间,然后填充上"Java"
和"Script"
。最后销毁原始的字符串"Java"
和字符串"Script"
,因为这两个字符串都没有用了。
字符串插值
模板字面量最常用的一个特性是支持字符串插值,也就是可以在一个连续定义中插入一个或多个值。技术上讲,模板字面量不是字符串,而是一种特殊的 JavaScript
句法表达式,只不过求值后得到的是字符串。模板字面量在定义时立即求值并转换为字符串实例,任何插入的变量也会从它们最接近的作用域中取值。
字符串插值通过在 ${}
中使用一个 JavaScript
表达式实现:
let value = 5
let exponent = 'second'
// 以前,字符串插值是这样实现的:
let interpolatedString = value + ' to the ' + exponent + ' power is ' + value * value
// 现在,可以用模板字面量这样实现:
let interpolatedTemplateLiteral = `${value} to the ${exponent} power is ${value * value}`
console.log(interpolatedString) // 5 to the second power is 25
console.log(interpolatedTemplateLiteral) // 5 to the second power is 25
所有插入的值都会使用 toString()
强制转型为字符串,而且任何 JavaScript
表达式都可以用于插值。
- 嵌套的模板字符串无须转义:
console.log(`Hello, ${`World`}!`) // Hello, World!
- 将表达式转换为字符串时会调用
toString()
:let foo = { toString: () => 'World' } console.log(`Hello, ${foo}!`) // Hello, World!
- 在插值表达式中可以调用函数和方法:
function capitalize(word) { return `${word[0].toUpperCase()}${word.slice(1)}` } console.log(`${capitalize('hello')}, ${capitalize('world')}!`) // Hello, World!
其他类型转换为字符串
有两种方式把一个值转换为字符串。首先是使用几乎所有值都有的 toString()方法。这个方法唯一的用途就是返回当前值的字符串等价物。
let xhsAge = 11
let xhsAgeAsString = xhsAge.toString() // 字符串"11"
let xhsFound = true
let xhsFoundAsString = xhsFound.toString() // 字符串"true"
toString()
方法可见于数值、布尔值、对象和字符串值。(没错,字符串值也有 toString()
方法,该方法只是简单地返回自身的一个副本。)null
和 undefined
值没有 toString()
方法。
多数情况下,toString()
不接收任何参数,默认情况下返回十进制,也可以通过参数来设置进制数。
let xhsNum = 10
console.log(xhsNum.toString()) // "10"
console.log(xhsNum.toString(2)) // "1010"
console.log(xhsNum.toString(8)) // "12"
console.log(xhsNum.toString(10)) // "10"
console.log(xhsNum.toString(16)) // "a"
注意,默认情况下(不传参数)的输出与传入参数 10
得到的结果相同。
如果你不确定一个值是不是 null
或 undefined
,可以使用 String()
转型函数,它始终会返回表示相应类型值的字符串。 String() 函数
遵循如下规则。
- 如果值有
toString()
方法,则调用该方法(不传参数)并返回结果。 - 如果值是
null
,返回"null"
。 - 如果值是
undefined
,返回"undefined"
。let xhsValue1 = 10 let xhsValue2 = true let xhsValue3 = null let xhsValue4 console.log(String(xhsValue1)) // "10" console.log(String(xhsValue2)) // "true" console.log(String(xhsValue3)) // "null" console.log(String(xhsValue4)) // "undefined"
这里展示了将 4
个值转换为字符串的情况: 数值 、布尔值 、null 和 undefined 。
数值 和 布尔值 的转换结果与调用 toString()
相同。因为 null
和 undefined
没有 toString()
方法,所以 String()
方法就直接返回了这两个值的字面量文本。
注意: 用加号操作符给一个值加上一个空字符串""也可以将其转换为字符串
BigInt 类型
BigInt
是一种内置对象,它提供了一种方法来表示大于 2^53 - 1
的整数。这原本是 Javascript
中可以用 Number
表示的最大数字。 BigInt
可以表示任意大的整数。
描述 可以用在一个整数字面量后面加 n
的方式定义一个 BigInt
,如:10n
,或者调用函数 BigInt()
。
const theBiggestInt = 9007199254740991n
const alsoHuge = BigInt(9007199254740991)
// ↪ 9007199254740991n
const hugeString = BigInt('9007199254740991')
// ↪ 9007199254740991n
const hugeHex = BigInt('0x1fffffffffffff')
// ↪ 9007199254740991n
const hugeBin = BigInt('0b11111111111111111111111111111111111111111111111111111')
// ↪ 9007199254740991n
它在某些方面类似于 Number
,但是也有几个关键的不同点:不能用于 Math
对象中的方法;不能和任何 Number
实例混合运算,两者必须转换成同一种类型。在两种类型来回转换时要小心,因为 BigInt
变量在转换成 Number
变量时可能会丢失精度。
Symbol 类型
symbol
是一种基本数据类型( primitive data type
)。 Symbol()
函数会返回 symbol
类型的值,该类型具有静态属性和静态方法。它的静态属性会暴露几个内建的成员对象;它的静态方法会暴露全局的 symbol
注册,且类似于内建对象类,但作为构造函数来说它并不完整,因为它不支持语法:"new Symbol()"
。
每个从 Symbol()
返回的 symbol
值都是唯一的。一个 symbol
值能作为对象属性的标识符;这是该数据类型仅有的目的。
语法
参数 description 可选
Symbol([description])
可选的,字符串类型。对 symbol
的描述,可用于调试但不是访问 symbol
本身。
描述
直接使用 Symbol()
创建新的 symbol
类型,并用一个可选的字符串作为其描述。
var sym1 = Symbol()
var sym2 = Symbol('foo')
var sym3 = Symbol('foo')
上面的代码创建了三个新的 symbol
类型。 注意, Symbol("foo")
不会强制将字符串 “foo”
转换成 symbol
类型。它每次都会创建一个新的 symbol
类型:
Symbol('foo') === Symbol('foo') // false
下面带有 new
运算符的语法将抛出 TypeError
错误:
var sym = new Symbol() // TypeError
Object 类型
ECMAScript
中的对象其实就是一组数据和功能的集合。对象通过 new
操作符后跟对象类型的名称来创建。开发者可以通过创建 Object
类型的实例来创建自己的对象,然后再给对象添加属性和方法.
let xhsO = new Object()
ECMAScript
中的 Object
是派生其他对象的基类。 Object
类型的所有属性和方法在派生的对象上同样存在。每个 Object
实例都有如下属性和方法。
constructor
:用于创建当前对象的函数。在前面的例子中,这个属性的值就是Object()
函数。hasOwnProperty(*propertyName*)
:用于判断当前对象实例(不是原型)上是否存在给定的属性。要检查的属性名必须是字符串(如o.hasOwnProperty("name")
)或符号。isPrototypeOf(*object*)
:用于判断当前对象是否为另一个对象的原型。propertyIsEnumerable(*propertyName*)
:用于判断给定的属性是否可以使用for-in
语句枚举。与hasOwnProperty()
一样,属性名必须是字符串。toLocaleString()
:返回对象的字符串表示,该字符串反映对象所在的本地化执行环境。toString()
:返回对象的字符串表示。valueOf()
:返回对象对应的字符串、数值或布尔值表示。通常与toString()
的返回值相同。
因为在 ECMAScript
中 Object
是所有对象的基类,所以任何对象都有这些属性和方法。
数值类型转换
有 3 个函数可以将非数值转换为数值: Number()
、 parseInt()
和 parseFloat()
。 Number()
是转型函数,可用于任何数据类型。后两个函数主要用于将字符串转换为数值。对于同样的参数,这 3 个函数执行的操作也不同。
Number() 函数
基于如下规则执行转换。
- 布尔值,
true
转换为1
,false
转换为0
。 - 数值,直接返回。
null
,返回0
。undefined
,返回NaN
。-
字符串,应用以下规则。
- 如果字符串包含数值字符,包括数值字符前面带加、减号的情况,则转换为一个十进制数值。因此,
Number("1")
返回1
,Number("123")
返回123
,Number("011")
返回11
(忽略前面的零)。 - 如果字符串包含有效的浮点值格式如
"1.1"
,则会转换为相应的浮点值(同样,忽略前面的零)。 - 如果字符串包含有效的十六进制格式如
"0xf"
,则会转换为与该十六进制值对应的十进制整数值。 - 如果是空字符串(不包含字符),则返回
0
。 - 如果字符串包含除上述情况之外的其他字符,则返回
NaN
。
- 如果字符串包含数值字符,包括数值字符前面带加、减号的情况,则转换为一个十进制数值。因此,
- 对象,调用
valueOf()
方法,并按照上述规则转换返回的值。如果转换结果是NaN
,则调用toString()
方法,再按照转换字符串的规则转换。let xhsNum1 = Number('Hello world!') // NaN let xhsNum2 = Number('') // 0 let xhsNum3 = Number('000011') // 11 let xhsNum4 = Number(true) // 1
parseInt() 函数
- 字符串最前面的空格会被忽略,从第一个非空格字符开始转换
- 如果第一个字符不是数值字符、加号或减号,
parseInt()
立即返回NaN
- 如果第一个字符是数值字符、加号或减号,则继续依次检测每个字符,直到字符串末尾,或碰到非数值字符。比如,
"1234blue"
会被转换为1234
,因为"blue"
会被完全忽略。类似地,"22.5"
会被转换为22
,因为小数点不是有效的整数字符。
假设字符串中的第一个字符是数值字符, parseInt()
函数也能识别不同的整数格式(十进制、八进制、十六进制)。换句话说,如果字符串以 "0x"
开头,就会被解释为十六进制整数。如果字符串以 "0"
开头,且紧跟着数值字符,在非严格模式下会被某些实现解释为八进制整数。
let xhsNum1 = parseInt('1234blue') // 1234
let xhsNum2 = parseInt('') // NaN
let xhsNum3 = parseInt('0xA') // 10,解释为十六进制整数
let xhsNum4 = parseInt(22.5) // 22
let xhsNum5 = parseInt('70') // 70,解释为十进制值
let xhsNum6 = parseInt('0xf') // 15,解释为十六进制整数
parseInt()
也接收第二个参数,用于指定进制数。可以省略前面的 0x
或者 0
let xhsNum = parseInt('0xAF', 16) // 175
let xhsNum1 = parseInt('AF', 16) // 175
let xhsNum2 = parseInt('AF') // NaN
通过第二个参数,可以极大扩展转换后获得的结果类型。
let xhsNum1 = parseInt('10', 2) // 2,按二进制解析
let xhsNum2 = parseInt('10', 8) // 8,按八进制解析
let xhsNum3 = parseInt('10', 10) // 10,按十进制解析
let xhsNum4 = parseInt('10', 16) // 16,按十六进制解析
注意: 多数情况下解析的应该都是十进制数,此时第二个参数就要传入 10
。
parseFloat() 函数
该函数的工作方式跟 parseInt()
函数类似,都是从位置 0
开始检测每个字符。同样,它也是解析到字符串末尾或者解析到一个无效的浮点数值字符为止。这意味着第一次出现的小数点是有效的,但第二次出现的小数点就无效了,此时字符串的剩余字符都会被忽略。因此, "22.34.5"
将转换成 22.34
。
注意
- 它始终忽略字符串开头的零
- 十六进制数值始终会返回
0
- 如果字符串表示整数(没有小数点或者小数点后面只有一个零),则
parseFloat()
返回整数let xhsNum1 = parseFloat('1234blue') // 1234,按整数解析 let xhsNum2 = parseFloat('0xA') // 0 let xhsNum3 = parseFloat('22.5') // 22.5 let xhsNum4 = parseFloat('22.34.5') // 22.34 let xhsNum5 = parseFloat('0908.5') // 908.5 let xhsNum6 = parseFloat('3.125e7') // 31250000
题目自测
一:null 和 undefined 的区别是什么?
二:以下代码,哪个结果返回的是 NaN()
A. let a = Number('')
B.
let b = Number('xhs')
C.
let c = Number(true)
D.
let d = Number(120);
三: 以下代码输出什么?
let a = 12
let b = false
let c = null
let d = undefined
console.log(typeof a.toString())
console.log(typeof b.toString())
console.log(String(c))
console.log(String(d))
题目解析
一、null
和 undefined
都是基本的数据类型,它们都本身都只有一个值,就是 null
和 undefined
。 undefined 表示未定义,null 表示为空对象。
null == undefined // true
null === undefined // false
Number(null) // 0
Number(undefined) // NaN
二、
Answr:B
此处用到了数值类型转换中的 Number()
函数
A 为空字串,转换之后返回的是 0
, B 字符串中的其他类型,转化为 NaN
,C true
会先转化为 1
,然后转化为数值,D 普通数值,返回原来的值,所以是 120
三、toString()
方法将值都转化为字符串的方式输出。然而 null
和 undefined
没有 toString()
方法,可以使用 String()
直接转化为字符串。
// 'string'
// 'string'
// 'null'
// 'undefined'