数据类型与对象

392 阅读6分钟

Author:eret9616


不知不觉已经到了7月了,还有5个月就能过年了,加油鸭...

最近我所在的项目中开始引入TypeScript,其中涉及到了强类型的一些概念,今天我们就来一起梳理一下数据类型、对象的概念,

正文:

当你每天嚷嚷着面向对象编程的时候,你知道什么是对象嘛
虽然你可能没有对象,但是你可以学习什么是对象


C语言中的对象

在C语言中,对象指结构体的实例

// 声明一个结构体
struct student{
   Int a;  //4byte
   char b; // 1byte
   char c; // 1byete
   short d; // 2byte
}

这句话声明了student结构体这种数据类型,

告诉C编译器student结构体将占用内存8byte大小,


当写下并执行下面这句话时
struct student s1 = {12,'a','b',2} 就进行了实例化的操作,
然后会在内存栈空间分配8个byte大小,并填充上面你定义的数据,


如果声明的结构体中有函数指针,那么实例化的对象中就能调用方法了。

数据类型的本质

数据类型的本质是固定长度大小内存块的别名。

各种数据类型,在编译器眼里只是别名,

int 是4字节内存块的别名,char是1字节内存块的别名, 当你声明了一种结构体,你就是在告诉编译器这个名字是多少长度内存块的别名。在C语言中,通过sizeof操作符,可以查看数据类型所占用的空间大小,sizeof(struct Student)就可以拿刚刚声明的结构体所占用的字节8, 拿到字节后可以在堆空间去malloc(sizeof(struct Student)),分配空间后,可以赋值并完成在堆空间上数据的创建。

对象

明确了数据类型的意义后,就可以给出对象的定义了: 对象是指自定义长度、结构的数据类型的实例,对象是区别于基本数据类型的实例的。 需要明白的是, 对象和他在堆空间还是在栈空间上没有关系,刚才的例子里一开始在栈空间创建了对象,后面也提到用sizeof获取大小并在堆空间创建对象。

数组是对象吗

在C语言中初始化数组不涉及到结构体,因为数组内部结构是固定的,所以数组不是对象,数组是连续的每个单元大小固定的结构固定的一种数据结构,它不是对象。

但是JavaScript中的数组是对象,Array继承于Object,并且可以向上添加方法

// 数组添加方法
var a = [1,2,3]
a.b = function(){...}

简单的说,JS的数组并不是C中的真正的数组,在内存中存储的方式不是C数组那么简单的结构,他是复杂的数据结构,因为上面能够调用方法,还能自动append长度,类比List,Stack,Map,Set这些数据结构,因为内部可以调用方法,他们在内存中的实际存储方式都是结构体方式,结构体内部有函数指针。

堆空间与栈空间

操作系统进程内存模型分为不同的区域,堆和栈是其中的两个区域,栈的空间相比堆要小很多,遇到占用大空间的数据(如自定义的对象)一般要放到堆上存储。

随着时间推移,到了C++时代,C++中出现了类的概念,类其实就是结构体。只是加了一些特性的结构体,所以, 在声明类时你可以定义它的构造函数(C语言中没有构造函数的概念)

// 类
class Student{
   Int a;  //4byte  
   char b; // 1byte
   char c; // 1byete
   short d; // 2byte
   // 构造函数
public:Student(){
     cout << “Hello” << endl; 
}
}

构造函数是指当这个类被实例化初始成一个对象时会被执行的函数,那想一下它的实现…其实就是带了函数指针的结构体,在被实例化的时候C++编译器会去执行这个函数指针指向的你定义的构造函数。

new

C++引入的new操作符相当于malloc && 执行构造函数。当new一个类的时候, 就是在堆空间进行malloc,然后去执行这个类的构造函数。JavaScript中的new不仅仅这么简单,但了解了最原始的new,你就明白了new到底是在做什么。

高级语言

JavaScript的解释器引擎由C/C++编写,不同浏览器运行着不同厂家编写的引擎,只是因为这些引擎都遵守着ECMA规范,所以看起来好像跑起来都一样。

在JS中,数据类型被分为 原语类型(primitive )和对象(Object)

原语类型包含Boolean,Null,Undefined,Number,BigInt,String,Symbol

JavaScript暴露的内容不涉及手动在堆与栈分配内存,

也没有sizeof方法来判断某个数据类型的大小,

但我们可以在语言规范中一窥这些基本数据类型的定义


在ECMA规范中:

Number: primitive value corresponding to a double-precision 64-bit binary format IEEE 754 value
双精度64位浮点

String: primitive value that is a finite ordered sequence of zero or more 16-bit unsigned integer
字符串中每个值都是16位无符号整数

......


所谓的原语类型,是基于语言规范定义的,String类型虽然是原语类型,但却是不定长的,从规范来看他就是一个数组,数组中每个元素都是16位无符号整数,所以当你初始化一个字符串的时候,他的长度是基于你字符串内容的。但可以肯定的是,它的结构是不能被自定义的,数组中的每个元素都是依照这一规范的,它不能被添加方法。
var a = 'asdf'
a.b = function(){...}
a.b // undefined

原语类型调用方法

在JavaScript中,原语数据类型是没有方法的,

当你尝试对原语数据类型进行操作时,引擎会进行"装箱":

var a = 1  
var b = a.toString()

a是一个基本数据类型,不是对象,不应该有方法, 但当你执行a.toString() 或尝试调用方法时,引擎会创建一个对象

1、调用Number类,创建一个实例
2、在实例上调用该方法
3、销毁这个实例

这个过程也可以类似用代码来表示:

var _a = new Number(1)  
var b = _a.toString()   
_a = null   

参考资料:

developer.mozilla.org/en-US/docs/…
www.ecma-international.org/ecma-262/5.…
www.github.com/getify/You-…
stackoverflow.com/questions/3…