JavaScript数据类型

一、数据类型

最新的 ECMAScript 标准定义了 8 种数据类型:

1.七种简单数据类型(也称 原始数据类型)

  1. Undefined,一个特殊的关键字,表示变量未赋值时的属性。
  2. Null ,一个特殊的关键字,逻辑上null 表示一个空对象指针,这也是给typeof 传递一个null ,会返回'object '的原因。另外null 是由undefined 派生而来的,ECMA将它们定义为表面相等,所以null == undefined 为 true
  3. 布尔值(Boolean) ,有 2 个值分别是:true 和 false。 要将一个其他类型的值转换为布尔值,可以调用Boolean()转型函数。转换规则如下:
数据类型 转换为true的值 转换为false的值
String 非空字符串 ""(空字符串)
Number 非零数值(包括无穷值) 0、NaN
Object 任意对象 null
Undefined N/A undefined
  1. 数字(Number ),整数或浮点数,例如: 42、0、-3.1415926、0x1f(16进制)、NaN(不是数值,No a Number)等。具备有效数值范围,若超出,可以使用BigInt数据类型。
  2. 字符串(String),一串表示文本值的字符序列。可以通过toString()或 + ''的方式转换为字符串类型。
  3. 符号(Symbol),ECMAScript 6 中新增的数据类型,一种实例是唯一且不可改变的数据类型。
  4. 任意精度的整数 (BigInt),可以安全地存储和操作大整数,甚至可以超过数字的安全整数限制。

2.一种复杂数据类型(也称 引用数据类型)

引用数据类型Object,包括

  1. 对象(Object):键值对的集合。
  2. 数组(Array):有序的值的列表。
  3. 函数(Function):可执行的代码块。
  4. 日期(Date):表示日期和时间的对象。
  5. 正则表达式(Regular Expression):用于模式匹配的对象。

二、基本数据类型和引用数据类型的特点

1.基本类型

基本数据类型存储在栈中(栈区指内存里的栈内存),占用的内存较小,可以直接操作它们的值,而且是按值传递的,即一个变量的值是直接存储在变量中的,它们的比较也是按值进行的。

例如:有以下几个基本类型的变量:

ini 复制代码
var name = 'jozo';
var city = 'guangzhou';
var age = 22;

那么它的存储结构如下图:

栈区包括了变量的标识符和变量的值。

2.引用类型

引用类型的对象存储于堆中,占用的内存较大,不能直接操作它们的值,而是需要通过引用来访问它们的属性和方法,它们的赋值和比较也是按引用进行的,即一个变量的值是一个指向实际对象的引用。

例如:有以下几个对象:

ini 复制代码
js
复制代码
var person1 = {name:'jozo'};
var person2 = {name:'xiaom'};
var person3 = {name:'xiaoq'};

则这三个对象的在内存中保存的情况如下图:

由于基本类型和引用类型的差异,它们在使用上也有所不同。当我们对基本类型进行赋值、传参和比较时,只是对它们的值进行操作,而不会影响其他变量的值。但是对于引用类型,如果我们将一个引用类型变量赋值给另一个变量,那么两个变量实际上是指向同一个对象的引用。这意味着,如果我们在其中一个变量上进行修改,另一个变量也会受到影响。

例如: 1.基本类型和引用类型在参数传递中的区别

ini 复制代码
let a = 10;
let obj = { value: 20 };

function change(x, y) {
  x = 20;
  y.value = 30;
}

change(a, obj);

console.log(a); // 输出 10
console.log(obj.value); // 输出 30

解析:基本类型的参数传递是值传递,函数内部对参数的修改不会影响原变量的值,因为函数内部修改的是参数的副本。而引用类型的参数传递是引用传递,函数内部对参数的修改会影响原变量的值,因为函数内部修改的是参数指向的对象的属性值。

2.基本类型和引用类型在赋值中的区别

ini 复制代码
let a = 10;
let b = a;
a = 20;
console.log(b); // 输出 10

let obj1 = { value: 10 };
let obj2 = obj1;
obj1.value = 20;
console.log(obj2.value); // 输出 20

解析:基本类型的赋值是将变量的值复制一份给新变量,修改其中一个变量的值不会影响另一个变量的值。而引用类型的赋值是将变量的指针复制一份给新变量,两个变量指向同一个对象,修改其中一个变量指向的对象的属性值会影响另一个变量指向的对象。

3.基本类型和引用类型的相等比较

ini 复制代码
console.log(10 === 10); // 输出 true
console.log({} === {}); // 输出 false

let obj1 = { value: 10 };
let obj2 = obj1;
console.log(obj1 === obj2); // 输出 true

解析:基本类型的相等比较是值比较,只有两个变量的值完全相同才相等。而引用类型的相等比较是指针比较,只有两个变量指向同一个对象才相等。

4.基本类型和引用类型的类型判断

javascript 复制代码
console.log(typeof 10); // 输出 "number"
console.log(typeof {}); // 输出 "object"

let obj = { value: 10 };
console.log(obj instanceof Object); // 输出 true

解析:使用 typeof 运算符可以判断基本类型的类型,使用 instanceof 运算符可以判断引用类型的类型。因为引用类型的类型是 Object,所以 instanceof Object 运算符可以用来判断一个变量是否为引用类型。

三、typeof 和 instanceof

typeofinstanceof 都是判断数据类型的方法,区别如下:

  • typeof会返回一个运算数的基本类型instanceof 返回的是布尔值
  • instanceof 可以准确判断引用数据类型 ,但是不能正确判断原始数据类型
  • typeof可以判断原始数据类型null 除外),但是无法判断引用数据类型function 除外)

那为什么typeof判断null为object?

这是 JavaScript 语言的一个历史遗留问题,在第一版JS代码中用32位比特来存储值,通过值的1-3位来识别类型,前三位为000表示对象类型。而null是一个空值,二进制表示都为0,所以前三位也就是000,所以导致 typeof null 返回 "object"

四、instanceof 运算符的实现原理

instanceof运算符适用于检测构造函数的prototype属性上是否出现在某个实例对象的原型链上

instanceof 运算符的原理是基于原型链的查找。当使用 obj instanceof Constructor 进行判断时,JavaScript 引擎会从 obj 的原型链上查找 Constructor.prototype 是否存在,如果存在则返回 true,否则继续在原型链上查找。如果查找到原型链的顶端仍然没有找到,则返回 false

instanceof运算符只能用于检查某个对象是否是某个构造函数的实例,不能用于基本类型的检查,如stringnumber等。

五、null和undefined区别

UndefinedNull 都是基本数据类型,这两个基本数据类型分别都只有一个值,就是 undefinednull

  • undefined 代表的含义是未定义 ,一般变量声明了但还没有定义 的时候会返回 undefinedtypeofundefined
  • null 代表的含义是空对象 ,null主要用于赋值给一些可能会返回对象的变量,作为初始化,typeofobject
ini 复制代码
null == undefined // true

null === undefined //false

六、0.1+0.2 ! == 0.3

因为浮点数运算的精度问题。在计算机运行过程中,需要将数据转化成二进制,然后再进行计算。 因为浮点数自身小数位数的限制而截断的二进制在转化为十进制,就变成0.30000000000000004,所以在计算时会产生误差。

解决方案

  • 将其先转换成整数,再相加之后转回小数。具体做法为先乘10相加后除以10

    ini 复制代码
    let x=(0.1*10+0.2*10)/10;
    console.log(x===0.3)
  • 使用number对象的toFixed方法,只保留一位小数点。

    scss 复制代码
    (n1 + n2).toFixed(2)

七、判断数组的方式有哪些

  • 通过Object.prototype.toString.call()做判断

    javascript 复制代码
    Object.prototype.toString.call(obj).slice(8,-1) === 'Array';
  • 通过原型链做判断

    ini 复制代码
    obj.__proto__ === Array.prototype;
  • 通过ES6的Array.isArray()做判断

    ini 复制代码
    Array.isArrray(obj);
  • 通过instanceof做判断

    javascript 复制代码
    obj instanceof Array
相关推荐
轻口味1 小时前
命名空间与模块化概述
开发语言·前端·javascript
前端小小王2 小时前
React Hooks
前端·javascript·react.js
迷途小码农零零发2 小时前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
真滴book理喻5 小时前
Vue(四)
前端·javascript·vue.js
程序员_三木5 小时前
Three.js入门-Raycaster鼠标拾取详解与应用
开发语言·javascript·计算机外设·webgl·three.js
开心工作室_kaic7 小时前
springboot476基于vue篮球联盟管理系统(论文+源码)_kaic
前端·javascript·vue.js
川石教育7 小时前
Vue前端开发-缓存优化
前端·javascript·vue.js·缓存·前端框架·vue·数据缓存
搏博7 小时前
使用Vue创建前后端分离项目的过程(前端部分)
前端·javascript·vue.js
温轻舟7 小时前
前端开发 之 12个鼠标交互特效上【附完整源码】
开发语言·前端·javascript·css·html·交互·温轻舟
web135085886357 小时前
2024-05-18 前端模块化开发——ESModule模块化
开发语言·前端·javascript