资讯专栏INFORMATION COLUMN

JavaScript基础之数据类型

pinecone / 2745人阅读

摘要:原始数据类型和原始数据类型实在太简单,所以只简单划几个重点原始数据类型不可改变原始数据类型一个非常重要的特征就是不可改变。引用数据类型这里的不是狭义的,包含的预定义引用类型,对,这些都是引用数据类型。

JavaScript是脚本语言

计算机语言可以分为三类,机器语言、汇编语言、高级语言。高级语言又可以简单分为解释类和编译类。这个知道就够了。

机器语言: 计算机所能识别的二进制语言,一般也不会直接拿来用于编程,无法理解且难以记忆
汇编语言: 底层程序可以直接理解的指令,一般是英文缩写,一般简短、简单(功能简单),只能做一些非常细微的操作,复杂的操作往往伴随着大量的指令,我等一般接触不多
高级语言: 简单理解,我们平常接触到的听说过的基本都是高级语言。高级语言又分为解释类和编译类。解释类语言和编译类语言都需要转换成机器语言才能被机器执行,区别在于转换的时间,解释类语言也就是一般通称的脚本语言,依赖于解释器,边解释边执行,编译类是全部转换(编译)好了,打包拿出去执行。JavaScript不需要编译,但是需要在自己的解释器上执行,比如我们常用的浏览器。
内存、地址、指针

有过C语言基础的人一定听说过这么一句话,指针是C语言的灵魂。但是似乎在JavaScript中,并没有接触过所谓的指针的概念,但JavaScript的解释器(JavaScript引擎)不管用什么编写,有的是C,有的是C++,也或者是Java,甚至是JavaScript自举实现的JavaScript解释器(元循环虚拟机),都逃不脱内存和指针,在JaVaScript中也有体现。所以了解下这些概念,对于学习JavaScript,总归是有好处的。

计算机内存最小单位是位,8位一个字节(byte),实际计算机中,内存最小单位是字节(byte),通俗来讲,可以把内存条当做内存,计算机运行时临时存储数据的地方。也可以把它看做一个大的图书馆,有无数个格子,每个格子都有一个编号,这个编号就是地址,每个地址对应唯一一段内存。我们通常所说的系统为数据分配一段内存,也就是给这个数据分配格子,一个格子放不下,那就给分三五个格子来放。而指针则是固定占用4个格子(4byte),里面放的不是真实的数据,而是放的另外一段内存的地址,只是个地址。

原始数据类型

Undefined、Null、Boolean、Number、String和Symbol(ES6)

原始数据类型实在太简单,所以只简单划几个重点:

原始数据类型不可改变 原始数据类型一个非常重要的特征就是不可改变。原始数据类型是保存在栈中的,一旦声明一个变量 var a = "老李";解释器会申请一块内存来存储"老李",a是标识符(标识符存储的是内存地址,但在经过解释/编译后会就不需要了),如果此时其他操作尝试修改a,比如a += ",你好!";,此时打印a,虽然会输出"老李,你好!";但是实际这其中改变的是a的地址指向,解释器会为"老李,你好!"申请一片新的内存来存储,a中存储的指向改变了,原先的"老李"所占用的内存会被回收但本身并未被改变。

原始数据类型是按值传递 原始数据类型的赋值,也是新开辟一片内存地址来存放新的指针和值,比如:var b = a;虽然看起来b和a一样,但实际上b和a一点点关系都没有,各自有各自的标识符和占用的内存,只是刚好值相同。

引用数据类型

Object
这里的Object不是狭义的Object,包含JavaScript的预定义引用类型:Object、Array、Date、Boolean、Number、String,对,这些都是引用数据类型。也就是一个数字/日期/布尔值/字符串他们的字面量声明方式和构造函数声明方式会造成完全不一样的结果。也就是上面划的两个重点,这里需要重新划一下。

引用数据类型可以改变 我想说的不是这句废话,引用数据类型和原始数据类型存储在 栈和堆中,栈中存储的是标识符和指针,堆中存储的才是实际地址。画个表(表也懒得画了,下面的凑活看)吧:

var a = 1;
var a1 = a;
var b = {value: 1};
var b1 = b;
var c = new Object(1);
var c1 = c;
var d = new Number(1);
var d1 = d;

          栈                                               堆    
a         1                                                无
a1        1(和a的1占用的不同的内存)                          无
b         指针,{value: 1}所占的内存地址                      {value: 1}
b1        指针,指向和b相同,但指针本身存储在新的内存中           同上,且是同一块内存中的相同的值
c         指针,1所占的内存地址                               1(object)
c1        指针,1所占的内存地址,但指针本身存储在新的内存中        同上,且是同一块内存中的相同的值
d         指针,1所占的内存地址                               1(number)
d1        指针,1所占的内存地址,但指针本身存储在新的内存中        同上,且是同一块内存中的相同的值

简单讲,原始数据类型,永远是一个标识符对应一个值(一段内存)且都存放在栈里;引用数据类型永远是一个标识符对应一个指针指向同一个值(同一段内存),前二者存储在栈中,最后一个在堆中。来几个例子帮助理解下:

var a = 1;
var a1 = a;

a1 = 2;

console.log(a, a1);      //1 2

这个很好理解大家各自有各自的标识符和内存地址,你变你的,不影响我。下一个例子:

var b = {value: 1};
var b1 = b;

b1.value = 2;

console.log(b.value, b1.value)    //2 2

也好理解,b和b1指向的是同一个东西,简单理解就是b和b1共用同一个东西。b1改完了b再来访问,拿到的肯定是改后的。下一个例子:

var c = new Object(1);
var c1 = c;

c1 = 2;

console.log(c, c1)        //{[[PrimitiveValue]]: 1}  2  PrimitiveValue就是指的原始值,这里其实只是将原始值1包装成Object,而这个原始值1依然不可更改

也很简单,c1 = 2;这句话重新声明了c1,代表着指针的c1被回收了,c1被重新声明为一个原始数据类型,这时候二者没关系了,如果是换一个方法,比如:

var c = new Object(1);
var c1 = c;

c1.value = 1;

console.log(c, c1)  //{value: 1,[[PrimitiveValue]]: 1} {value: 1,[[PrimitiveValue]]: 1} 

这样就没问题了。

参数中的原始数据和引用数据

原始数据类型是按值传递的,引用数据类型是按引用传递的,看例子:

var a = 1;
var b = {value: 1};

function foo(v){
    v = "new Value";
}

foo(a);

在函数调用时,其实进行了如下操作:
将a赋值给v,也就是v = a;,创建了a的副本,此时v得到了自己的内存,其中存放着1这个值,然后拿"new Value"去覆盖1,然而这一切发生在a的副本上,和a完全没有关系,所以此时打印出a,还是1。接着:

foo(b);

这个结果也很好猜,b也没有变,同样创建一个副本,副本有标识符、指针,指针指向的也是b的指针指向的值,但是v = ”new Value“;执行时,这个副本就被重新赋值位一个string了,原先那个指针被回收。接着:

var a = 1;
var b = {value: 1};
var c = new Number(1);

function foo(v){
    v.value = "new Value";
}

foo(a);
foo(b);
foo(c);

a依然是1,且不说原始数据不能被添加属性,即便被添加也只是a的副本的事,和a没一点关系;

b在函数执行中同样创建了副本,副本同样有指针,指向了{value: 1}所在的实际地址,此时通过指针改变了存储`{value:
1}`的内存中的value值,所以此时再通过b去访问,一样是输出改变后的值;

c和b原理一样,只不过c本来没有value属性,所以会被添加一个value属性,所以上面的abc结果分别是:

console.log(a);            // 1
console.log(b);            // {value: "new Value"} 
console.log(c);            // Number {value: "new Value", [[PrimitiveValue]]: 1}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/87334.html

相关文章

  • WebSocket系列JavaScript中数字数据如何转换为二进制数据

    摘要:以和为例,说明中的数字数据如何转换为二进制数据。对象用来表示通用的固定长度的原始二进制数据缓冲区。中的数字数据如何转换为二进制数据对和有了一个大概的了解,下面让我们来看下它是如何进行二进制数据操作的。 概述 本文主要通过对JavaScript中数字数据与二进制数据之间的转换,让读者能够了解在JavaScript中如何对数字类型(包括但不限于Number类型)进行处理。 二进制数据在日常...

    MASAILA 评论0 收藏0
  • javascript 基础类型转换

    摘要:类型转换和表示一个空对象。如果有其他类型想转换为或者类型,直接赋值就可以了。都能隐式的把数据类型转为类型。。。时间时间二数字类型转换为字符串默认是进制是一个对象类型,所以其他类型转化为通常都是。 前言 javaScript是一门可以自由进行数据类型转换的编程语言,类型转换是javaScript很重要的特色(坑点很多!!!),大家想以后写出更多严谨的代码(少出一些莫名其妙的Bug),还是...

    timger 评论0 收藏0
  • WebSocket系列字符串如何与二进制数据间进行互相转换

    摘要:总结通过使用和,我们能够在数据和二进制数据中进行互相转换。下一篇系列相关的博客,将会介绍如何通过来向后端传递二进制数据,以及如何处理通过收到的二进制数据。 概述 上一篇博客我们说到了如何进行数字类型(如Short、Int、Long类型)如何在JavaScript中进行二进制转换,如果感兴趣的可以可以阅读本系列第二篇博客——WebSocket系列之JavaScript中数字数据如何转换为...

    stackfing 评论0 收藏0
  • 进击的 JavaScript(二) 数据结构

    摘要:的垃圾回收器,进行回收。它们的数据就存放在堆内存中,大小不一定,动态分配内存,可随时修改。引用类型的变量存的是其在堆内存中的地址,值的读取,就是读取这个内存地址中储存的内容。 这东西还是很重要的,你要是搞懂了,就会去除很多困惑,比如不知道大家在学习js 的时候,有没有对 基础类型 和 引用类型 感到困惑过,两者之间 表现的不同之处。 js 不同其他编程语言,它是脚本语言。所以,它的数...

    BlackFlagBin 评论0 收藏0
  • Javascript基础-强制类型转换(二)

    摘要:所以无论还是都会进行类型转换,唯一的区别,就是会置否而不会。这时候,肯定会有人问,假如说我有其他的数据类型呢,又不是数字又不是字符串,比如说数组啊,对象啊,布尔值啥的,那么如果是引用数据类型,则先转为基本数据类型,再进行比较。 上一章主要讲了转换到数字,字符串和布尔类型的一些知识点,那么这一讲接着上面的继续讲。 思考下面这个问题: console.log(+123); // 123 ...

    kk_miles 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<