变量类型
在脚本中,无论是属性、数据库还是临时变量,每个数据都会以类型进行区分。
例如,在数据库中,可以存储数字、文本、真假值。
在这个过程中,可能会涉及到类型的比较与转换。
var 数字变量 = 1
var 文本变量 = '一个文本'
var 真假值变量 = true
var 真假值变量2 = 2 > 1 // true
我们称数字、文本、真假值、undefined、null为标量类型。因为它们之间,每个值是唯一的。例如,1会和1相等,false会和false相等,诸如此类。
其中一个例外是 NaN,NaN 是数字类型,表示该数字是无效的。NaN 总是不等于 NaN,需要使用
isNaN(值)
来判断一个值是否为 NaN。var 数字1 = 123
var 数字2 = 123
数字1 === 数字2 // true
var 无效数字 = NaN
无效数字 === NaN // false
isNaN(无效数字) // true
与标量类型相对应的,是对象和数组类型。这两个类型是按引用传递的,根据引用来比较两个值是否相等。例如,如果声明两个空数组,它们之间是不相等的。
var 数组1 = []
var 数组2 = []
数组1 === 数组2 // false
数字
数字(number)类型是所有变量中最常见的类型。
可以对数字进行加减乘除的运算。
1 + 2 // 返回 3
2 * 6 // 返回 12
+5 // 返回 5
可以使用
Number(数字)
将其它值强制转换为数字。如果被转换的值无法转换成数字,则会被转换成NaN
。NaN
的全称为 “Not a Number”,表示这个值不是一个合法数字。即便如此,它依然是数字类型。Number("123") // 返回 123
Number("123") === 123 // true
Number('123.') // 返回 123
Number(true) // 1
Number(false) // 0
Number("123d") // NaN
Number("ABC") // NaN
Number(undefined) // NaN
如前文所述,NaN 总是不等于 NaN,需要使用
isNaN(值)
来判断一个值是否为 NaN。var 无效数字 = NaN
无效数字 === NaN // false
isNaN(无效数字) // true
数字类型包括整数和小数。
255 === 255.0 // true
值得注意的是,在 JavaScript 中,由于小数在内部通过特殊方法存储,导致在对小数计算时,会存在误差。因此,会出现不符合直觉的情况,例如:
0.3 === 0.1 + 0.2 // false
0.1 + 0.2 // 0.30000000000000004
因此,在对小数进行运算和处理时,要小心谨慎。特别是将数字转换成文本后,小数可能会产生非常长的一段文本。
String(0.1 + 0.2) // '0.30000000000000004'
这时,可以通过
.toFixed()
对小数长度进行截取。var 小数变量 = 12345.6789;
小数变量.toFixed(); // 返回 "12346"
小数变量.toFixed(1); // 返回 "12345.7"
小数变量.toFixed(2); // 返回 "12345.78"
也可以使用
Math.floor(小数)
、Math.ceil(小数)
、Math.round(小数)
对小数进行向下取整、向上取整和四舍五入。Math.floor(1.7) // 返回 1,向下取整到 1
Math.ceil(1.7) // 返回 2,向上取整到 2
Math.round(1.7) // 返回 2,四舍五入到 2
此外,JavaScript 的整数也是有精度限制的。当数字超过
9007199254740991
时(包括取负号),会丢失精度。文本
文本(string),同样是 JavaScript 中非常常用的类型。可以使用单引号
'
、双引号"
和反引号`
来表示。var 文本变量1 = '这是一个文本'
var 文本变量2 = "这也是一个文本"
var 文本变量3 = `这还是一个文本`
如果文本中需要包含引号,可以使用反斜线
\
进行转义。var 包含引号的文本 = "这是一个包含\"引号\"的文本"
使用
\n
可以让文本换行。var 包含换行的文本 = '段落1\n段落2'
文本类型也可以进行拼接。可以使用加号
+
,将两个文本拼接成一个文本。var 文本1 = 'Hello, '
var 文本2 = 'world!'
var 拼接后的文本 = 文本1 + 文本2 // 'Hello, world!'
当使用反引号时,可以使用
${变量}
在文本中插入变量。var 文本1 = `你的金钱数量:${属性.金钱}。`
var 文本2 = `打 7 折后的价钱为:${(100*0.7).toFixed(2)}。`
使用
.length
获取文本的长度。var 文本变量 = '这是一个文本'
文本变量.length // 返回 7
使用
文本[位置]
获取文本中指定位置的字符。位置从 0 开始计数。var 文本变量 = '这是一个文本'
文本变量[1] // 返回 '是'
使用
.slice(开始位置, 结束位置)
截取文本的一部分。var 文本变量 = '这是一个文本'
文本变量.slice(2, 4) // 返回 '一个'
使用
String(xxx)
将其它类型强制转换为文本。String(123) // 返回 '123'
String(true) // 返回 'true'
String(undefined) // 返回 'undefined'
String(null) // 返回 'null'
使用
.indexOf()
和 .lastIndexOf()
查找文本中指定子文本的位置。如果找不到,则返回 -1。var 文本变量 = '这是一个文本,是吗?'
文本变量.indexOf('是') // 返回 1,“是”第一次出现的位置
文本变量.lastIndexOf('是') // 返回 8,“是”最后一次出现的位置
使用
.toUpperCase()
和 .toLowerCase()
将文本中的字母转换成大写或小写。var 文本变量 = 'Hello World!'
文本变量.toUpperCase() // 返回 'HELLO WORLD!'
文本变量.toLowerCase() // 返回 'hello world!'
使用
.replaceAll()
将文本中的子文本全部替换成另一个子文本。var 文本变量 = '这是一个文本'
文本变量.replaceAll('是', '不是') // 返回 '这不是一个文本'
使用
.split(分割文本)
将文本分割成一个数组。'这是一个文本'.split('') // ['这', '是', '一', '个', '文', '本']
'这是一个文本'.split('是') // ['这', '一个文本']
'a,b,c,d,e,f'.split(',') // ['a', 'b', 'c', 'd', 'e', 'f']
使用
.trim()
去除文本的两端的空白字符。var 文本变量 = ' 这是一个文本 '
var 去除空白后的文本 = 文本变量.trim() // '这是一个文本'
真假值
真假值(boolean),也称布尔值。包括
true
和 false
两个值。使用感叹号,可以将真假值取反。
!true // false
!!true // true (取反两次,先变成 false 再变成 true)
可以通过由比较符号(==, ===,>=,<=,<,>)组成的表达式来生成真假值,例如:
var 真假值变量 = 属性.金钱 > 100
也可以通过
Boolean(xxx)
将其它类型强制转换为真假值。如果被转换的值是 0、空字符串''
、undefined、null,则转换后的值为 false。其它的值,包括负数、空数组[]
、空对象{}
,都会被转换为 true。Boolean(0) // false
Boolean(1) // true
Boolean('') // false
If 会根据括号内的真假值,决定是否要执行花括号里的命令。如果括号里是别的类型,则先强制转换为真假值,再进行判断(相当于在外面套了层
Boolean(xxx)
)。if (真假值) {
}
比较符号 == 和 ===
在 JavaScript 中,有两种方式来比较两个值是否相等:
==
和 ===
。==
是一种宽松的相等检查。当使用 ==
比较两个值时,如果它们的类型不同,JavaScript 会尝试将它们转换为相同的类型,然后再进行比较。例如:123 == '123' // true
true == 1 // true
undefined == null // true
在上述例子中,尽管比较的两个值的类型不同,但是
==
还是返回了 true
。这是因为 ==
在比较前进行了类型转换。与
==
不同,===
是一种严格的相等检查。当使用 ===
比较两个值时,如果它们的类型不同,===
就会直接返回 false
,不会进行任何类型转换。例如:123 === '123' // false
true === 1 // false
undefined === null // false
在编写 JavaScript 代码时,你应当尽可能的使用
===
进行比较,从而避免由于类型转换带来的一些意想不到的结果。undefined 和 null
在 JavaScript 中,
undefined
和 null
是两种特殊的类型。undefined
当你声明了一个变量但还没有赋值,那么它的值就是
undefined
。也可以明确地将变量赋值为 undefined
。var 未定义变量;
未定义变量 // undefined
var 变量2 = undefined;
变量2 // undefined
如果你尝试获取一个数组、对象和数据库中不存在的值,也会返回
undefined
。var 对象 = {};
对象.不存在的属性 // undefined
var 数组 = [];
数组[0] // undefined
var 变量 = 数据.读(['不存在', '的', '路径'])
变量 // undefined
null
null
通常用于表示变量的值故意被置为空。var 空变量 = null;
?? 操作符
??
操作符用于判断一个值是否为 undefined
或 null
,如果是,则返回另一个值,否则返回这个值本身。var 变量 = undefined ?? '默认值';
变量 // '默认值'
var 变量2 = null ?? '默认值';
变量2 // '默认值'
var 变量3 = '已定义的值' ?? '默认值';
变量3 // '已定义的值'
转换为其他类型
当
undefined
或 null
转换为其他类型时,也有一些特殊的规则。转换为布尔值时,
undefined
和 null
都会转换为 false
。Boolean(undefined) // false
Boolean(null) // false
在转换为字符串时,
undefined
转换为 "undefined"
,而 null
转换为 "null"
。String(undefined) // "undefined"
String(null) // "null"
当转换为数字时,
undefined
转换为 NaN
,而 null
转换为 0
。Number(undefined) // NaN
Number(null) // 0
在实际开发中,
undefined
和 null
都表示变量没有值。通常情况下,我们会把变量初始化为 null
,表示变量已经被初始化但目前还没有值。而 undefined
通常表示系统级的、出乎意料的或定义自己的缺少的,尚未赋值的情况。数组
数组(array)是一种特殊的对象,用于表示和操作一组有序的值。
在 JavaScript 中,使用方括号
[]
来创建一个数组。例如:var 数组变量 = ['元素1', '元素2', '元素3'];
在这个例子中,我们创建了一个数组,它有三个元素:
'元素1'
、'元素2'
和'元素3'
。通过索引(从0开始的整数)来访问数组的元素:
数组变量[0] // '元素1'
通过赋值操作符
=
来修改数组的元素:数组变量[0] = '新元素';
数组变量[0] // '新元素'
使用
length
属性来获取数组的长度:数组变量.length // 3
使用
push
来向数组的末尾添加新的元素:数组变量.push('新元素');
数组变量.length // 4
数组变量[3] // '新元素'
使用
pop
来删除并返回数组的最后一个元素:数组变量.pop() // '新元素'
数组变量.length // 3
使用
shift
来删除并返回数组的第一个元素:数组变量.shift() // '新元素'
数组变量.length // 2
使用
unshift
来向数组的开头添加新的元素:数组变量.unshift('新元素');
数组变量.length // 3
数组变量[0] // '新元素'
使用
indexOf
来查找数组中某个元素的索引:数组变量.indexOf('元素2') // 1
数组变量.indexOf('不存在的元素') // -1
使用
slice
来获取数组的一部分:数组变量.slice(1, 3) // ['元素2', '元素3']
使用
splice
来删除、替换或添加数组的元素:数组变量.splice(1, 1, '新元素') // ['元素2']
数组变量 // ['新元素', '元素3']
使用
join
来将数组的元素连接成一个字符串:数组变量.join(', ') // '新元素, 元素3'
使用
...
操作符来将数组的元素展开,并合并到新数组中:var 数组变量 = ['元素1', '元素2', '元素3'];
var 新数组变量 = [...数组变量, '元素4'];
新数组变量 // ['元素1', '元素2', '元素3', '元素4']
对象
对象(object)可以包含多个属性,每个属性都由一个键(key)和一个值(value)组成。对象的键是文本,而值可以是任何类型的数据。
在 JavaScript 中,我们可以使用花括号
{}
来创建一个对象。例如:var 对象变量 = {
键1: '值1',
键2: '值2',
键3: '值3'
}
这个代码中创建了一个对象,它有三个属性:
键1
、键2
和键3
,它们的值分别是'值1'
、'值2'
和'值3'
。通过
.
操作符来访问对象的属性:对象变量.键1 // '值1'
也可以使用
[]
操作符来访问对象的属性,特别是当属性名包含特殊字符或者属性名是变量时:对象变量['键1'] // '值1'
var 属性名 = '键2';
对象变量[属性名] // '值2'
通过赋值操作符
=
来修改对象的属性,如果不存在则添加该属性:对象变量.键1 = '新值';
对象变量.键1 // '新值'
使用
delete
操作符来删除对象的属性:delete 对象变量.键1;
对象变量.键1 // undefined
对象变量 // { 键2: '值2', 键3: '值3' }
使用
in
操作符来检查对象是否包含某个属性:'键2' in 对象变量 // true
'不存在的键' in 对象变量 // false
使用
Object.keys(对象)
来获取对象的所有属性名:Object.keys(对象变量) // ['键2', '键3', '新键']
使用
Object.values(对象)
来获取对象的所有属性值:Object.values(对象变量) // ['值2', '值3', '新值']
使用
Object.entries(对象)
来获取对象的所有属性名和属性值:Object.entries(对象变量) // [['键2', '值2'], ['键3', '值3'], ['新键', '新值']]
使用
...
操作符来将对象展开并合并到新的对象中:var 对象变量2 = {
...对象变量,
键4: '值4'
}
对象变量2 // { 键2: '值2', 键3: '值3', 新键: '新值', 键4: '值4' }
函数
函数(function)也可以作为变量类型的一种。它可以接收参数,执行一段代码,并返回一个值。
JavaScript 中的函数与 Realm 在领域中提供的“全局函数”在功能上很相似,但是“全局函数”可以被所有脚本调用,而在 JavaScript 中声明的函数只能被当前脚本调用。
在 JavaScript 中,使用
function
关键字来声明一个函数。例如:function 加法(参数1, 参数2, 参数3) {
return 参数1 + 参数2 + 参数3;
}
在这个例子中,我们声明了一个函数
加法
,它接收三个参数 参数1
、参数2
和参数3
,并返回这三个参数的和。声明函数后,我们可以通过函数名来调用它,并传入实际的参数值:
加法(1, 2, 3); // 返回 6
同时,在函数内的代码,可以访问外部声明的临时变量。
var 手续费率 = 0.01;
function 计算手续费(金额) {
return 金额 * 手续费率;
}
但是,在函数内声明的临时变量,外界却访问不了:
function 计算手续费(金额) {
var 手续费率 = 0.01;
return 金额 * 手续费率;
}
手续费率; // 这里访问不到 手续费率 临时变量
函数也可以直接赋值给变量:
var 变量1 = function(参数1, 参数2, 参数3) {
return 参数1 + 参数2 + 参数3;
}
变量1(1, 2, 3); // 返回 6
在这个例子中,我们声明了一个匿名函数,并将它赋值给了变量
变量1
。这个匿名函数和前面的 加法
函数是一样的,只是它没有名字。因为函数可以作为变量,所以它可以像其它普通的变量一样,存放在数组、对象中,或者作为参数传递给其它函数。
将函数存放在数组中:
var 函数1 = function(参数1, 参数2, 参数3) {
return 参数1 + 参数2 + 参数3;
}
var 函数2 = function(参数1, 参数2, 参数3) {
return 参数1 * 参数2 * 参数3;
}
var 函数数组 = [函数1, 函数2];
函数数组[0](1, 2, 3); // 返回 6
函数数组[1](1, 2, 3); // 返回 6
将函数存放在对象中:
var 对象变量 = {
属性1: function(参数1, 参数2, 参数3) {
return 参数1 + 参数2 + 参数3;
}
}
对象变量.属性1(1, 2, 3); // 返回 6
此外,当函数处于对象中时,可以使用
this
来访问当前对象的属性。var 变量1 = {
名字: '张三',
年龄: 20,
打招呼: function() {
return '你好,我叫' + this.名字;
},
庆祝生日: function() {
this.年龄++;
}
}
变量1.打招呼(); // 返回 '你好,我叫张三'
变量1.年龄; // 返回 20
变量1.庆祝生日();
变量1.年龄; // 返回 21
在这个例子中,
变量1
对象有两个属性 名字
和 年龄
,还有两个函数 打招呼
和 庆祝生日
。打招呼
函数会返回一个问候语文本,庆祝生日
函数会使 age
属性增加 1。this
表示当前对象,在 打招呼
函数中,this.名字
就相当于 变量1.名字
。在一些复杂情况下,我们可能希望
this
不被函数影响,这时,会用到箭头函数:var 对象变量 = {
属性1: (参数1, 参数2, 参数3) => {
// 这里面如果有 this 不会指向函数所在的对象
return 参数1 + 参数2 + 参数3;
}
}
(参数) => {}
相当于 function () {}
,如果在函数中没有用到 this,箭头函数就是普通函数的另一种写法。函数也可以作为参数或返回值。当函数作为参数时,我们称这个函数为回调函数。例如:
function 函数1(回调函数) {
return 回调函数();
}
函数1(function () {
return 'Hello, world!';
}); // 返回 'Hello, world!'
在这里,
函数1
接收一个回调函数作为参数,并在函数内部调用了这个回调函数。typeof 操作符
在 JavaScript 中,
typeof
可以用来检查一个变量的类型。typeof
操作符后面跟着一个变量或值,它会返回一个字符串,表示该变量或值的类型。例如:typeof 123 // "number"
typeof 'Hello' // "string"
typeof true // "boolean"
typeof undefined // "undefined"
typeof null // "object"
typeof {} // "object"
typeof [] // "object"
typeof function() {} // "function"
需要注意的是,对于
null
和数组,typeof
返回的是 "object"
。在实际编程中,
typeof
是一个非常有用的工具,它可以帮助我们在处理变量时,更好地理解变量的类型,从而避免一些类型相关的错误。你可以对 typeof
的返回值进行“提示”。提示(typeof 临时变量)
变量与 JSON 之间的转换
JSON 是一种将 JavaScript 对象或数组转换为文本的方法。
JSON.stringify()
JSON.stringify()
可以将对象或数组转换为文本。var 对象变量 = {
名称: "张三",
年龄: 30,
爱好: ["阅读", "旅行"]
};
var 文本变量 = JSON.stringify(对象变量); // '{"名称":"张三","年龄":30,"爱好":["阅读","旅行"]}'
JSON.parse()
与
JSON.stringify()
相对的是 JSON.parse()
,该命令将 JSON 文本还原成对象或数组。var 文本变量 = '{"名称":"张三","年龄":30,"爱好":["阅读","旅行"]}';
var 对象变量 = JSON.parse(文本变量);
对象变量.名称; // "张三"
对象变量.爱好[0]; // "阅读"
注意事项
如果想要将一个对象或数组转换为 JSON,请确保该对象或数组只含有数字、文本和真假值。在处理其它特殊变量(如 NaN、函数、Date等)时,可能会出现意料意料之外的情况。
例如,JSON 会将 NaN 转换为 null,并忽略 undefined 和函数值。
var 对象 = {
名称: "张三",
介绍: undefined,
打招呼: function() {
return `你好,我是${this.名称}。`;
}
};
JSON.stringify(对象); // '{"名称":"张三"}',undefined 和函数被忽略