c语言中NULL是什么数据类型,JS中基本数据类型有哪几种?null 是对象吗?基本数据和复杂数据类型有什么区别?...

基本数据类型

基本数据类型有6种

null

undefined

string

number

boolean

symbol(ES6新增)

复杂数据类型

复杂数据类型就一种

object

null是对象吗?

先看下MDN上的解释:

值 null 特指对象的值未设置。它是 JavaScript 基本类型 之一。

由此可见,null并不是一个对象,虽然typeof null返回的值为"object"。

《你不知道的JavaScript(上卷)》这本书说过:

null 有时会被当做一种对象类型,但是这其实只是语言本身的一个bug,即对null执行typeof null时会返回字符串"object"。实际上,null本身是基本类型。

原理是这样的,不同的对象在底层都表示为二进制,在JavaScript中二进制前三位都为0的话会被判断为object类型,null的二进制表示是全0,自然前三位也是0,所以执行typeof时会返回“object”。

思考:为什么typeof null会返回"object"而不是"null"?

大家可以看下MDN上的解释:

在 JavaScript 最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。由于 null 代表的是空指针(大多数平台下值为 0x00),因此,null的类型标签也成为了 0,typeof null就错误的返回了"object"。

ECMAScript提出了一个修复(通过opt-in),但被拒绝。这将导致typeof null === 'null'。

基本数据和复杂数据类型有什么区别?

1.声明变量时不同的内存分配

基本数据类型:存储在栈中的简单数据段,也就是说,它们的值直接存储在变量访问的位置。这是因为它们占据的空间是固定的,所以可将它们存储在较小的内存区域-栈。这样存储便于迅速查寻变量的值。

复杂数据类型:存储在堆中的对象,栈中存储的变量的值是一个指针,指向堆中的引用地址。这是因为复杂数据类型的值是会改变的,所以不能把它放在栈中,否则会降低变量查寻的速度。

2.不同的访问机制

在JavaScript中,是不允许直接访问保存在堆内存中的对象的,所以在访问一个对象时,首先得到的是这个对象在堆内存中的地址,然后再按照这个地址去获得对象中的值。这就是传说中的按引用访问。

而基本数据类型的值是可以直接访问得到的,即按值访问。

3.复制变量时的不同

基本数据类型:在将保存着原始值的变量复制给另一个变量时,会将原始值的副本赋值给新变量,此后这两个变量是完全独立的,不会相互影响,只是它们拥有相同的value而已。

看下面的例子:

var a = 10;

var b = a;

b = 20;

console.log(a); // 10

上面的代码说明:b获取的是a值的一份拷贝,虽然两个变量的值相等,但是两个变量保存了两个不同的基本数据类型,它们之间不会相互影响。

复杂数据类型:在将一个保存着对象内存地址的变量复制给另一个变量时,会把这个内存地址赋值给新变量,也就是说两个变量都指向了堆内存中d的同一个对象,它们中任何一个作出的改变都会反映在另一个身上。(这里要理解的一点就是,复制对象时并不会在堆内存中新生成一个一模一样的对象,只是多了一个保存指向这个对象的指针罢了)

看下面的例子:

var a = {

name: 'dazhi'

}

var b = a;

b.name = 'dazhi_fe';

console.log(a.name); // "dazhi_fe"

上面的代码说明:a和b都指向了同一个堆中的对象,所以对其中一个作出改变,另一个也会跟着改变。

4.参数传递的不同

首先我们应该明确一点:ECMAScript中所有函数的参数都是按值来传递的。这也是我们容易疑惑的地方,因为访问变量有按值和按引用两种方式,而参数只能按值传递。这一点等下我们举例来说明。

基本数据类型:拷贝的是值

看例子:

function addTen(num) {

num += 10;

return num;

}

var count = 20;

var result = addTen(count);

console.log(count); // 20,没有变化

console.log(result); // 30

只是把变量的值传递给参数,之后参数和这个变量互不影响。

复杂数据类型:拷贝的是引用地址

看例子:

function setName(obj) {

obj.name = "Nicholas";

}

var person = {

name: 'jack'

}

setName(person);

console.log(person.name); // "Nicholas"

以上代码创建了一个对象,并将其保存在了变量person中。然后这个变量被传递到setName()函数之中就被复制给了oobj。在这个函数内部,ojb和person引用的是同一个对象。于是在函数内部修改了name属性后,函数外部的person也会有所反映。所以我们会错误的认为:在局部作用域中修改的对象会在全局作用域中反映出来,就说明参数是按引用传递的。

为了证明对象是按值传递的,我们再来看一个例子:

var obj1 = {

value: '111'

}

var obj2 = {

value: '222'

}

function changeStuff(obj) {

obj.value = '333';

obj = obj2;

return obj.value;

}

var foo = changeStuff(obj1);

console.log(foo); // 222 参数obj指向了新的对象obj2

console.log(obj1.value); // 333

obj1仍然指向原来的对象,之所以value改变了,是因为changeStuff里的第一条语句,这个时候obj是指向obj1的;如果是按引用传递的话,这个时候obj1.value应该是等于'222'的。

实际上,在函数内部重写obj时,这个变量引用的就是一个局部对象了。而这个局部对象会在函数执行完毕后立即销毁。

参考:

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值