前端--关于值类型和引用类型(放心,术语很少)
2019-11-01 本文已影响0人
银魂飞雪
在帮同事解决问题时,经常遇到诸如:
- 我没有改过这个数据啊,为什么会变了...
- 为什么我在页面A修改了数据,页面B的也会变
原因通常都是引用类型,既然引用类型容易引起误解,那为什么还要设计引用类型?
答案是性能。
做个小测试,循环一定次数,给分别给值类型和引用类型赋值,观察
- 内存占用
- CPU占用
- 耗时
const cpuStat = require('cpu-stat');
function sub(x1, x2) {
let result = {};
for (const key in x2) {
result[key] = x2[key] - x1[key];
}
return result;
}
function loop(des, func, count) {
return new Promise((resolve) => {
// 强制GC,且在2秒后再运行代码
global.gc();
setTimeout(() => {
cpuStat.usagePercent(function (err, percent, seconds) {
if (err) {
return console.log(err);
}
console.log(`${des}CPU: ${percent}`);
});
const startM = process.memoryUsage();
const startTime = Date.now();
for (let i = 0; i < count; i++) {
func();
}
const endM = process.memoryUsage();
const endTime = Date.now();
console.log(`${des}Memory: ${JSON.stringify(sub(startM, endM), null, 2)}`);
console.log(`${des}Time: ${endTime - startTime}`);
setTimeout(() => {
resolve();
}, 3000)
},2000)
})
}
const count = 2000000000;
async function execute() {
const strSource = '某柏慧燕都非要玩要一二三五点五十旱地';
await loop('str', () => {
let str = strSource;
}, count);
const objSource = { x: strSource };
await loop('obj', () => {
let obj = objSource;
}, count);
}
execute();
运行三次的结果,平均来看
引用类型的内存占用有巨大的优势
内存
值类型(string)占用内存为:2330624字节
引用类型(object)占用内存为:733184字节
约3倍
耗时
值类型为:1021毫秒
引用类型为:779毫秒
约1.3倍
CPU占用
值类型为:9.039%
引用类型为:7.960%
约1.13倍
由此可见,引用类型在性能,特别是内存占用上有巨大的优势。所以,为了性能,必须要把引用类型弄清楚。
我们知道,计算机的临时数据是存在内存中,而每块内存又要有起始地址。
换一个形象的例子:有一排杯子,用来存东西,每个杯子上绑了一些线。杯子表示内存,线表示指向内存的变量
- 引用类型:每次赋值就是在杯子上绑一根线,定义1000个变量=这个杯子,相当于在杯子上绑了1000根线
- 值类型:每次赋值就是加一个新杯子,并在杯子上绑一线
其中,杯子就是占用的内存,线就是定义的变量
image.png image.png显示,对于
- 引用类型,其中通过其中一根获取到杯子,并往里面加了水。 对于绑在杯子上的其它线,水也增加了。
- 对于值类型,因为一根线只能对应一个杯子,所以通过某根线获取到杯子,并里面加水,不会影响到其它线绑定的杯子。
当然,有些语言,可以直接操作内存,比如C++不仅有指针,还有指针的指针,这里就不考虑了。
-------------附运行结果图------------
image.png
image.png
image.png