持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第11天,点击查看活动详情
前面有篇文章已经介绍了js的语言类型,那是基于js的语言类型来划分的。这篇文章我们就来介绍一下哪些是值类型,哪些是引用类型,以及它们之间是如何区分的?值类型和引用类型是基于JavaScript中变量的类型来进行区分的。也就是说值类型和引用类型是基于js的语言类型的基础上进一步划分的。
值类型
值类型指的是JavaScript的基本数据类型,包括:字符串(string)、数值(number)、布尔(boolean)、null、undefined、代表(symbol)(es6新增的)、bigInt。 这几种类型的具体含义在js的语言这篇文章中已经具体介绍了,这里就不再重复了,感兴趣的可以参考我的另外一篇文章: js的语言类型
引用类型
引用类型指的是JavaScript的复杂数据类型,包括:对象(object)、数组(array)、函数(function)、日期(date)、正则表达式(regExp)、基本包装类型对象、单体内置对象。
1. 对象(object)
object是JavaScript的一种数据类型。用于储存各种键值集合和更复杂的实体。
2. 数组
数组是一种列表对象,它的原型中提供了遍历和修改元素的相关操作。
常见操作
2.1 创建数组
let fruits = ['Apple', 'Banana']
2.2 通过索引访问数组元素
let first = fruits[0]
// Apple
let last = fruits[fruits.length - 1]
// Banana
2.3 遍历数组
fruits.forEach(function(item, index, array) {
console.log(item, index)
})
// Apple 0
// Banana 1
2.4 添加元素到数组的末尾
let newLength = fruits.push('Orange')
// ["Apple", "Banana", "Orange"]
2.5 删除数组末尾的元素
let last = fruits.pop() // remove Orange (from the end)
// ["Apple", "Banana"]
2.6 添加元素到数组的头部
let newLength = fruits.unshift('Strawberry') // add to the front
// ["Strawberry", "Banana"]
2.7 删除数组头部的元素
let first = fruits.shift() // remove Apple from the front
// ["Banana"]
2.8 找出某个元素在数组中的索引
fruits.push('Mango')
// ["Strawberry", "Banana", "Mango"]
let pos = fruits.indexOf('Banana')
// 1
2.9 通过索引删除某个元素
let removedItem = fruits.splice(pos, 1) // this is how to remove an item
// ["Strawberry", "Mango"]
2.10 从一个索引位置删除多个元素
let vegetables = ['Cabbage', 'Turnip', 'Radish', 'Carrot']
console.log(vegetables)
// ["Cabbage", "Turnip", "Radish", "Carrot"]
let pos = 1
let n = 2
let removedItems = vegetables.splice(pos, n)
console.log(vegetables)
// ["Cabbage", "Carrot"] (the original array is changed)
console.log(removedItems)
// ["Turnip", "Radish"]
2.11 复制一个数组
let shallowCopy = fruits.slice() // this is how to make a copy
// ["Strawberry", "Mango"]
3. 函数
每个 JavaScript 函数实际上都是一个 Function 对象。运行 (function(){}).constructor === Function // true 便可以得到这个结论。
function test () {
}
4. 日期
Date 对象则基于 Unix Time Stamp,即自 1970 年 1 月 1 日(UTC)起经过的毫秒数。
创建日期的方式:
new Date();
new Date(value);
new Date(dateString);
new Date(year, monthIndex [, day [, hours [, minutes [, seconds [, milliseconds]]]]]);
参数:
4.1 没有参数
如果没有提供参数,那么新创建的 Date 对象表示实例化时刻的日期和时间。
4.2 Unix时间戳
- value:一个 Unix 时间戳(Unix Time Stamp),它是一个整数值,表示自 1970 年 1 月 1 日 00:00:00 UTC(the Unix epoch)以来的毫秒数,忽略了闰秒。请注意大多数 Unix 时间戳功能仅精确到最接近的秒。
- 时间戳字符串 dateString: 表示日期的字符串值。该字符串应该能被 Date.parse() 正确方法识别(即符合 IETF-compliant RFC 2822 timestamps 或 version of ISO8601)。
4.3 分别提供日期与时间的每一个成员
当至少提供了年份与月份时,这一形式的 Date() 返回的 Date 对象中的每一个成员都来自下列参数。没有提供的成员将使用最小可能值(对日期为1,其他为0)。
- year:表示年份的整数值。0 到 99 会被映射至 1900 年至 1999 年,其它值代表实际年份。参见 示例。
- monthIndex:表示月份的整数值,从 0(1 月)到 11(12 月)。
- date可选:表示一个月中的第几天的整数值,从 1 开始。默认值为 1。
- hours 可选:表示一天中的小时数的整数值 (24 小时制)。默认值为 0(午夜)。
- minutes 可选:表示一个完整时间(如 01:10:00)中的分钟部分的整数值。默认值为 0。
- seconds 可选:表示一个完整时间(如 01:10:00)中的秒部分的整数值。默认值为 0。
- milliseconds 可选:表示一个完整时间的毫秒部分的整数值。默认值为 0。
5. 正则表达式
正则表达式是用于匹配字符串中字符组合的模式。在 JavaScript 中,正则表达式也是对象。这些模式被用于 RegExp 的 exec 和 test 方法,以及 String 的 match、matchAll、replace、search 和 split 方法。
6. 基本包装类型
基本包装类型通俗地理解就是js的基本类型所对应的引用类型(对象)。除了null和undefined外,其他的基本类型都有对应的包装对象。
- string --- String
- number --- Number
- bigInt --- BigInt
- boolean --- Boolean
- symbol --- Symbol
我们在基本类型变量上调用方法的时候,其实是调用的包装类型的对象上的方法。过程如下:
- 根据对象保存的基本类型值,创建对应类型的实例对象
- 在这个实例上调用我们所指定的方法
- 立即销毁这个实例
7. 单体内置对象
由ECMAScript 实现提供的、不依赖于宿主环境的对象。
单体内置对象主要有两种:Global对象和Math对象
7.1 Global对象
7.1.1 编码
let url = 'http://www.baidu.com';
console.log(encodeURI(url)); // 'http://www.baidu.com'
console.log(encodeURIComponent(url)); // 'http%3A%2F%2Fwww.baidu.com'
7.1.2 解码
let url = 'http%3A%2F%2Fwww.baidu.com';
console.log(decodeURI(url)); // 'http://www.baidu.com'
console.log(decodeURIComponent(url)) // 'http://www.baidu.com'
7.1.3 eval()
eval() 函数会将传入的字符串当做 JavaScript 代码进行执行。
eval(new String("2 + 2")); // 返回了包含"2 + 2"的字符串对象
eval("2 + 2"); // returns 4
建议不要使用
7.1.4 isNaN()
isNaN() 函数用来确定一个值是否为NaN
isNaN(NaN); // true
isNaN(undefined); // true
isNaN({}); // true
isNaN(true); // false
isNaN(null); // false
isNaN(37); // false
// strings
isNaN("37"); // false: 可以被转换成数值 37
isNaN("37.37"); // false: 可以被转换成数值 37.37
isNaN("37,5"); // true
isNaN('123ABC'); // true: parseInt("123ABC") 的结果是 123,但是 Number("123ABC") 结果是 NaN
isNaN(""); // false: 空字符串被转换成 0
isNaN(" "); // false: 包含空格的字符串被转换成 0
// dates
isNaN(new Date()); // false
isNaN(new Date().toString()); // true
isNaN("blabla") // true: "blabla"不能转换成数值
// 转换成数值失败,返回 NaN
7.1.5 isFinite()
isFinite() 函数用来判断被传入的参数值是否为一个有限数值(finite number)
isFinite(Infinity); // false
isFinite(NaN); // false
isFinite(-Infinity); // false
isFinite(0); // true
isFinite(2e64); // true,在更强壮的 Number.isFinite(null) 中将会得到 false
isFinite("0"); // true,在更强壮的 Number.isFinite('0') 中将会得到 false
7.1.6 parseInt()
parseInt(string, radix) 解析一个字符串并返回指定基数的十进制整数,radix 是 2-36 之间的整数,表示被解析字符串的基数。
parseInt("0xF", 16); // 15
parseInt("F", 16); // 15
parseInt("17", 8); // 15
parseInt(021, 8); // 15
parseInt("015", 10); // 15 parseInt(015, 8); 返回 13
parseInt(15.99, 10); // 15
parseInt("15,123", 10); // 15
parseInt("FXX123", 16); // 15
parseInt("1111", 2); // 15
parseInt("15 * 3", 10); // 15
parseInt("15e2", 10); // 15
parseInt("15px", 10); // 15
parseInt("12", 13); // 15
7.1.7 parseFloat()
parseFloat() 函数解析一个参数(必要时先转换为字符串)并返回一个浮点数。
parseFloat(3.14); // 3.14
parseFloat('3.14'); // 3.14
parseFloat(' 3.14 '); // 3.14
parseFloat('314e-2'); // 3.14
parseFloat('0.0314E+2'); // 3.14
parseFloat('3.14some non-digit characters'); // 3.14
parseFloat({ toString: function() { return "3.14" } }); // 3.14
7.2 Math对象
Math 是一个内置对象,它拥有一些数学常数属性和数学函数方法。 Math 用于 Number 类型 与其他全局对象不同的是,Math 不是一个构造器。Math 的所有属性与方法都是静态的。引用圆周率的写法是 Math.PI,调用正余弦函数的写法是 Math.sin(x),x 是要传入的参数。Math 的常量是使用 JavaScript 中的全精度浮点数来定义的。
特别说明:
由于篇幅原因,上面这些引用都没有展开详细介绍。后续我会分别根据这些引用对象输出详细的文章,敬请期待哦。
值类型和引用类型之间的区别
- 在内存上存储的地方不一样,值类型存在栈中,引用类型存在堆中。
- 在传递值类型和传递引用类型的时候,传递的方式不一样。值类型我们称之为值传递,引用类型我们称之为引用传递。