前言:
在这个数字化飞速发展的时代,前端开发已经成为互联网技术的核心领域之一。JavaScript,作为前端开发的基石,其重要性不言而喻。ESNext标准的推进带来了更多的新特性,同时也对开发者的技能提出了更高的要求。,本文将带你深入探讨JavaScript的数据类型和内存管理机制,从基础到高级,从理论到实践,全面解析这些关键概念。
为什么你需要了解JavaScript数据类型和内存管理?
- 提升代码性能:理解数据类型和内存管理可以帮助你优化代码,减少不必要的内存占用,提高应用程序的性能。
- 避免常见错误:深入理解JavaScript的内部机制,可以帮助你避免一些常见的陷阱和错误,编写更加健壮的代码。
- 应对复杂问题:在处理复杂的应用场景时,对数据类型和内存管理的深刻理解将是你解决问题的利器。
了解了为什么我们需要知道JavaScript数据类型和内存管理,那么就开始今天的学习了!
JavaScript数据类型全解:
哥们,你知道JS有多少种数据类型吗?
JavaScript数据类型:高手与高高手的区别
-
高手会讲8种:
- Number:数字,包括整数和浮点数。
- BigInt:大整数,ES10引入,解决大数精度问题。
- String:字符串,用来存储文本信息。
- Boolean:布尔值,表示真(
true
)或假(false
)。 - Null:空值,表示一个空对象引用。
- Undefined:未定义,表示一个声明但未赋值的变量。
- Symbol:唯一标识符,ES6引入,每次创建都是唯一的。
- Object:复杂数据类型,包括普通对象、数组、函数等。
-
高高手会讲7种:
- 其中的Numeric:包括
Number
和BigInt
,因为它们都是用来表示数值的。 - 其他不变
- 其中的Numeric:包括
这样如果当面试官问到类似的问题,你如此回答,哇哦,他一听,就知道哥们你是十年老JS了。 那么我们来详细的讲解一下数据类型里面的知识点吧!
我们来讲解的第一个是null这种数据类型:
null
是什么?在JavaScript的世界里,null
是一个特别的存在。它不仅仅是一个简单的值,更是编程世界中的一种哲学思考。它表示空值 表示一个空值或不存在的对象,是一个可以赋给变量的特殊值。它还有个很牛的作用,就是可以显示回收内存,这个知识点和底层的内存机制有关,所有我们得结合实例来看:
实例1:
let a=null; // 栈内存
console.log(a);
// 堆内存
let largeObject={
data: new Array(1000000).fill('a')
}
largeObject=null; // 释放堆中的内存 垃圾回收 // 哲学 // 不存在的对象
通过这个例子,largeObject
中的内存通过Null
进行了回收,这是其中一个作用,那么我们可以深入的去看看JS的底层内存是如何存储的。
内存分配机制揭秘
在JavaScript中,内存分配主要分为两种:栈(Stack)和堆(Heap)。
- 栈(Stack) :用于存储基本数据类型。栈内存分配速度快,但容量有限。当一个基本类型的数据被创建时,它的值直接存储在栈中。
- 堆(Heap) :用于存储复杂数据类型。堆内存分配较慢,但容量较大,适合存储大型对象。当一个对象被创建时,它实际上是在堆中创建,而在栈中只存储了一个指向该对象的引用。
这样我们对JS中的栈和堆有了一个简单的了解,那么来看看实例:
实例2:
let obj={
name:"张三",
job:"web",
company:"baidu"
}
obj.hometown="北京"
// 引用式
let obj2=obj;
let a=1;
// 拷贝式
let b=a;
b=3;
obj2.name="李四"
console.log(a,b);
console.log(obj,obj2);
看了上面的代码,大家不妨猜猜结果是什么?
公布答案:1 3 { name: '李四', job: 'web', company: 'baidu', hometown: '北京' } { name: '李四', job: 'web', company: 'baidu', hometown: '北京' }
问题:为什么obj1的输出和obj2的输出一样?
讲解:
- 当我们赋值给简单类型时,基本数据直接被压入栈中,加以保存,如上面的
a=1,b=a
,,简单数据类型拷贝。 - 当我们赋值给复杂类型时,是将堆内存地址放在栈内存中,如果出现
obj2=obj1
这种情况时并不是简单的拷贝,而是进行引用,将obj2和obj1指向同一个堆内存,这样就说明了为什么,为什么obj1
的name属性也随着obj2
的name属性改成一样了,由于obj2
和obj1
指向同一个对象,所以这个修改也会反映在obj1
上。
- 想必大家有疑问,为什么不直接复杂数据类型放入栈中呢?
-
动态内存管理:复杂数据类型的大小往往不是固定的,或者是在运行时才能确定。例如,动态数组、链表、树等数据结构的大小可能随着程序的执行而变化。这些类型的数据更适合存储在堆中,因为堆提供了更灵活的内存分配方式,可以按需申请和释放内存。
-
避免栈溢出:栈的大小是有限的,通常由操作系统设定。如果在栈上分配了过大的数据结构,可能会导致栈溢出,从而引发程序崩溃。将大型或复杂的对象放在堆中可以避免这种情况发生,因为堆的可用空间通常比栈大得多。
-
共享与传递:堆上的对象可以更容易地在不同的函数或线程之间共享。由于堆上的对象不受局部作用域限制,多个指针或引用可以指向同一个堆对象,这在多线程编程和跨模块通信中尤为重要。
-
图解:
当你理解好了JS的底层内存机制,本文的阅读就已经成功一半啦!
第二位向我们走来的是你独一无二的白月光 Symbol类型:
独一无二的标签,就如你少年时,窗外的白月光般, 有着像函数的外观,是一个简单的数据类型,进入实例:
// js 设计哲学 你!=你
console.log(Symbol());
console.log(Symbol('a')===Symbol('a'));
结果: Symbol() false
讲解: 就像是今天的你和昨天的你也是不一样的!symbol代表的就是独一无二的。
第三位是bigint:
这次先看案例:
let a=0.1;
let b=0.2;
console.log(a+b);
let num1= 999999999999999999999999;
let num2= 123456789123834348938394;
console.log(num1+num2);
结果: 1:0.30000000000000004 2:1.1234567891238343e+24
JS就像是一把双刃剑,是一个有很强大表现力的语言,但它并不适合运算,就得请我们的bigint来解决第二个因运算太大的麻烦了,只需要在后面加个n,它就变成了bigint类。
let num1= 999999999999999999999999n;
let num2= 123456789123834348938394n;
console.log(num1+num2);// 结果为:1123456789123834348938393n
其他数据类型就留给你们去好好钻研一下。既然有那么多数据类型,那么我们怎么去判断某个数据的数据类型呢?
实战技巧
类型判断:
typeof
操作符可以快速判断基本数据类型,但对null
和object
的判断有局限,废话少说进入实例:
// typeof js 类型 运算符
// console.log(typeof a,typeof(a));
// The Good Parts 什么好的,什么是坏的
let a=1;
console.log(typeof a,"1");
console.log(typeof "hellow");
console.log(typeof 12n);
console.log(typeof true);
console.log(typeof Symbol());
console.log(typeof undefined);
console.log(typeof null);// 不太行
console.log(typeof function(){});
结果:
- number 1
- string
- bigint
- boolean
- symbol
- undefined
- object
- function
讲解: 可以发现除了null
和object
的判断,其他都是对的
为什么会这样?
这个问题源于JavaScript的早期实现。在1995年,JavaScript的设计者Brendan Eich在设计语言时,由于时间和资源的限制,将 null
的类型错误地定义为了 object
。具体来说,null
被设计为一个表示“空对象引用”的值,而不是一个独立的类型。
这种设计在当时是为了与C++等语言保持一致,因为在C++中,nullptr
或 NULL
通常被定义为 (void*)0
,即一个空指针。因此,null
在JavaScript中被设计为一个特殊的对象引用,而不是一个独立的基本类型。
虽然这是一个历史遗留问题,但为了保持向后兼容,JavaScript一直没有修复这个问题。这意味着在现代JavaScript中,typeof null
仍然会返回 "object"
。
简单来讲就是一个BUG。
结语:
通过本文的学习,你不仅掌握了JavaScript的数据类型和内存管理机制,还了解了这些概念背后的原理和历史背景。这些知识将帮助你在日常开发中编写更高效、更健壮的代码。希望本文对你有所帮助,如果你有任何疑问或建议,欢迎在评论区留言交流。祝你在JavaScript的开发之旅中越走越远,越走越顺!