听君一席话,如听君一席话《聊聊javaScript中的null、undefined、NAN、那几个数据类型吧》

1,026 阅读7分钟

当您开始面试,一旦涉及到javaScript的null和undefined、等等类型时, 别慌!都给你整得明明白白的

从大到小来说

基本类型:指的是简单的数据段。在JavaScript中有五种基本数据类型:undefinednullbooleannumberstring。基本类型都是按值访问的,就是说可以操作保存在变量中的实际值, 数据大小确定,内存空间大小可以分配,它们是直接按值存放的。

代码:

let a=10
let b=a
b=20
console.log(a) //10

分析代码:

1651110963548.png

大白话:把a赋值给b, 虽然这两个变量的值相等,但是它们保存的是两个不同的基本数据类型的值。b只是保存了a复制的一个副本。所以,b的改变,对a没有影响。

引用类型:对象、数组、函数。对象是属性和方法的集合。引用类型可以拥有属性和方法,属性又可以包含基本类型和引用类型。引用类型的值保存在内存中的对象,JavaScript不能直接操作对象的内存空间,操作对象时,实际上是操作对象的引用而不是实际的对象。引用类型的值是按引用访问的

  1. 引用数据类型:由多个值构成的对象,保存在堆内存中的对象,在栈内存中保存的实际上是对象在堆内存中的引用地址,通过这个引用地址可以快速查找到保存中堆内存中的对象,因为不可以直接访问堆内存空间中的位置和操作堆内存空间,只能操作对象在栈内存中的引用地址。
  2. 存放在堆内存中的对象,每个空间大小不一样,要根据情况进行特定的配置。变量其实是保存的在栈内存中的一个指针,指针保存的是堆内存中的引用地址,指针指向堆内存。
  3. 引用数据类型也是对象数据类型,分为Object、Array、Function、Date、Math、RegExp, 在JS中除了基本数据类型以外的都是对象

代码:

let obj1 = {}
let obj2 = obj1
obj2.name = '靓仔'
console.log(obj1.name) // 靓仔

分析代码:

1651115517578.png

大白话:可以很直观地看到,obj1赋值给onj2,实际上这个堆内存对象在栈内存的引用地址复制了一份给了obj2,但是实际上他们共同指向了同一个堆内存对象,实际上改变的是同一个堆内存对象。

原始数据类型与引用数据类型的区别:

  1. 声明变量时不同的内存分配 1)原始值:存储在栈(stack)中的简单数据段,也就是说,它们的值直接存储在变量访问的位置。这是因为这些原始类型占据的空间是固定的,所以可将他们存储在较小的内存区域 – 栈中,这样存储便于迅速查寻变量的值。 2)引用值:存储在堆(heap)中的对象,也就是说,存储在变量处的值是一个指针(point),指向存储对象的内存地址。这是因为引用值的大小会改变,所以不能把它放在栈中,否则会降低变量查寻的速度。相反,放在变量的栈空间中的值是该对象存储在堆中的地址。 地址的大小是固定的,所以把它存储在栈中对变量性能无任何负面影响。
  2. 不同的内存分配机制也带来了不同的访问机制 1)在javascript中是不允许直接访问保存在堆内存中的对象的,所以在访问一个对象时,首先得到的是这个对象在堆内存中的地址,然后再按照这个地址去获得这个对象中的值,这就是传说中的按引用访问。 2)原始类型的值则是可以直接访问到的。
  3. 复制变量时的不同 1)原始值:在将一个保存着原始值的变量复制给另一个变量时,会将原始值的副本赋值给新变量,此后这两个变量是完全独立的,他们只是拥有相同的value而已。 2)引用值:在将一个保存着对象内存地址的变量复制给另一个变量时,会把这个内存地址赋值给新变量,也就是说这两个变量都指向了堆内存中的同一个对象,他们中任何一个作出的改变都会反映在另一个身上。 3)注意:复制对象时并不会在堆内存中新生成一个一模一样的对象,只是多了一个保存指向这个对象指针的变量。多了一个指针。
  4. 参数传递的不同(把实参复制给形参的过程) 1)ECMAScript中所有函数的参数都是按值来传递的 2)原始值:只是把变量里的值传递给参数,之后参数和这个变量互不影响。 3)引用值:对象变量它里面的值是这个对象在堆内存中的内存地址。它传递的值也就是这个内存地址,函数内部对这个参数的修改会体现在外部,都指向同一个对象。

开始整活儿

null


null不是一个空引用, 而是一个原始值; 它只是期望此处将引用一个对象, 注意是"期望", typeof null结果是object, 这是个历史遗留bug. 在ECMA6中, 曾经有提案为历史平反, 将type null的值纠正为null, 但最后提案被拒了. 理由是历史遗留代码太多, 不想得罪人, 不如继续将错就错当和事老

1651148126511.png

否定null值返回true,但将其与false(或true)进行比较则会给出false

1651148244258.png

在基础数学运算中,null值将被转换为0

1651148400330.png

undefined


全局属性nundefined表示原始值undefined。它也是JavaScript的原始数据类型(MDN)。undefined是全局作用域的一个变量。undefined的最初值就是原始数据类型undefined。一个没有被赋值的变量的类型是undefined。如果方法或者是语句中操作的变量没有被赋值,则会返回undefined

1651148609321.png

当你声明一个变量但没有声明它的值时,JavaScript会给它赋值undefined

1651148654820.png

如果你尝试在任何运算中使用undefined,你会得到NaN的值。与null相似,否定undefined值返回true,但将其与truefalse作比较则为false

1651148750687.png

null vs undefined


那么nullundefined两者之间有什么区别呢?通过上面的内容,我们来比较一下他们之间的相似点和不同之处

相似之处:

  • 当被否定时,两者的值都是true
  • 代表了一些不存在的东西...

差异之处:

  • null表示无,完全不存在的;undefined表示东西没有定义
  • undefined有自己的数据类型(undefined),null只是一个对象
  • 在基本算术运算中,null被视为0undefined返回的NaN

1651148943945.png

第二个语句,undefined === null和第一个语句有点不同,他们还在比较数据类型(除了比值,还要比两者数据类型),加上JavaScript很聪明,可以看出他们之间的区别,所以返回的值是false

NAN


全局NaN属性是一个表示非数字的值(MDN)。

我认为这个定义很清楚。当我们要得到的数字不是数字时,JavaScript会返回这个值。例如,当你试图用cucumber减去10或者用12除以R2D2时,它们返回的值为NaN

1651149508193.png

但是,要注意的是 如果JavaScript看到+符号和一个字符串,它会自动将第二个元素添加到字符串中

1651149579808.png

NaN实际上是一个数字

1651149630013.png

那么NAN跟boolean比较呢?

1651150315772.png

如何判读是NAN呢?

1651150769647.png 但是有个坑要注意这个isNAN方法,就算不传值,返回结果也是true,这是为什么呢?请大家给小弟解释吧!(滑稽)

祝大家发财