-
导入(Import)的内存模型及原理
-
内存布局
- 当使用
import
语句(如import MyTreeTableWrapper from '@/service/prd/test/MyTreeTableWrapper.js';
)时,JavaScript引擎会在内存中为导入的模块创建一个模块环境记录(Module Environment Record)。这个记录包含了模块导出的绑定(bindings)信息。 - 在模块加载过程中,JavaScript引擎会解析被导入的模块文件。对于像
MyTreeTableWrapper
这样的导入,它会查找模块内部定义的变量、函数、类等,并在模块环境记录中创建相应的引用。
- 当使用
-
指针关系
- 导入的模块实际上是通过引用(指针)来访问的。例如,当你在当前模块中使用
MyTreeTableWrapper
时,你并不是复制了整个MyTreeTableWrapper
模块的内容到当前模块的内存空间,而是创建了一个指向被导入模块的指针。这个指针指向被导入模块的模块环境记录,这样当你访问MyTreeTableWrapper
中的内容时,实际上是通过这个指针找到被导入模块中的相应定义。
- 导入的模块实际上是通过引用(指针)来访问的。例如,当你在当前模块中使用
-
内存管理
- 模块只被加载和解析一次,无论它被导入多少次。这意味着在内存中只有一份模块代码的实例。如果多个模块导入同一个模块,它们共享这个模块在内存中的实例,通过各自的模块环境记录中的引用来访问。这有助于节省内存,避免不必要的代码重复加载。
-
-
导出(Export)的内存模型及原理
-
内存布局
- 在定义模块(如
MyTreeTableConstructor
模块)时,当使用export
关键字(例如export default MyTreeTableConstructor;
),JavaScript会将被导出的内容标记为可被外部访问的。对于默认导出(default
),它在模块内部是一个特殊的绑定。在模块的内存环境中,这个被导出的内容(这里是MyTreeTableConstructor
函数)被存储在模块特定的内存区域。
- 在定义模块(如
-
指针关系
- 当模块被导出时,其他模块通过导入获取的是对这个导出内容的引用(指针)。以
MyTreeTableConstructor
为例,当其他模块导入这个函数时,它们得到的是一个指向MyTreeTableConstructor
函数在其原模块内存中的指针。这使得在调用MyTreeTableConstructor
时,实际上是在调用原始模块中定义的函数,而不是创建一个副本。
- 当模块被导出时,其他模块通过导入获取的是对这个导出内容的引用(指针)。以
-
内存管理
- 被导出的内容在模块的生命周期内存在于模块的内存空间中。如果模块被卸载(在某些支持动态模块加载和卸载的环境中),相关的内存资源可能会被回收,但只要模块存在于内存中(例如在一个长期运行的应用程序中),其导出的内容就可供其他模块通过导入使用。
-
总的来说,JavaScript的导入和导出机制通过引用(指针)来管理模块间的交互,以提高内存使用效率并确保模块的独立性和可维护性。
// 创建一个类来作为MyTreeTable的构造函数
import {defineComponent, h} from "vue";
import TreeTable from "primevue/treetable";
import Column from "primevue/column";class MyTreeTableWrapper {constructor(properties) {// 创建一个新的MyTreeTable组件实例const MyTreeTableInstance = defineComponent({validProperties: ['mytreeData', 'property2', 'property3'],name: 'MyTreeTable',components: {TreeTable,Column},//在Vue 3的setup函数中,this是未定义的,因为setup函数是在组件实例被创建之前执行的,因此没有this上下文。setup() {// 接受外部的赋值let non_TreetableData_object_param_list=[];let treeData=[];const to_TransformData=()=> {treeData = transformData(non_TreetableData_object_param_list);};const transformData= (data)=> {const transform = (arr, parentKey = '') => {return arr.map((item, index) => {const newKey = parentKey? `${parentKey}-${index}` : `${index}`;const newItem = {key: newKey,data: {id_cases: item.id_cases,id_param: item.id_param,object_Name: item.object_Name,type: item.type,desc: item.desc,is_object: item.is_object,required: item.required,rule: item.rule},children: item.children? transform(item.children, newKey) : []};return newItem;});};return transform(data);};const displayNameBasedOnId= (typeId)=> {const typeMap = [{ name: "文本", id: 1 },{ name: "日期", id: 2 },{ name: "文本域", id: 3 },{ name: "数值", id: 4 },{ name: "文件", id: 5 },{ name: "限选项", id: 6 },{ name: "其他", id: 7 }];for (let i = 0; i < typeMap.length; i++) {if (typeMap[i].id === typeId) {return typeMap[i].name;}}return "未定义类型";};if (properties) {for (let prop in properties) {if (['mytreeData', 'property2', 'property3'].includes(prop)) {non_TreetableData_object_param_list = properties[prop];to_TransformData();}}}return () =>h(TreeTable, { value: treeData, tableStyle: 'min - width: 50rem' }, [h(Column, { field: 'object_Name', header: '分类名称', expander: true }),h(Column, { field: 'is_object', header: '分类类型' }),h(Column, { field: item => displayNameBasedOnId(item.type), header: '参数类型' }),h(Column, { field: 'required', header: '是否必须' }),h(Column, { field: 'desc', header: '描述' })]);}});return MyTreeTableInstance;}
}
export default MyTreeTableWrapper;
import MyTreeTableWrapper from '@/service/prd/test/MyTreeTableWrapper.js';
// // 使用示例
const MyTreeTable1 = new MyTreeTableWrapper({mytreeData:PrdServiceFunCasesInputParameters.zwgetPrdServiceFunCasesInputParameters(),
});
<Card><template #content><MyTreeTable2></MyTreeTable2></template></Card>
-
导入模块时的压栈顺序
-
当执行
import MyTreeTableWrapper from '@/service/prd/test/MyTreeTableWrapper.js';
:- 首先,JavaScript引擎会将
MyTreeTableWrapper.js
文件加载到内存中。这个过程涉及到文件系统的读取操作(如果是在浏览器环境下,可能是从服务器获取文件内容)。 - 然后,开始解析文件内容。在解析
MyTreeTableWrapper
类的定义时,会将类的结构(包括构造函数、内部的方法等)压入执行上下文的解析栈中。对于其中的import
语句(如import {defineComponent, h} from "vue";
和import TreeTable from "primevue/treetable";
以及import Column from "primevue/column";
),会先暂停当前文件的解析,去加载和解析被导入的模块。 - 以
import {defineComponent, h} from "vue"
为例,引擎会查找vue
模块(假设已安装并在模块查找路径内),加载并解析它,将defineComponent
和h
函数的定义压入栈中(或者是创建引用指向它们在vue
模块中的定义)。同样的过程也会发生在TreeTable
和Column
的导入过程中。
- 首先,JavaScript引擎会将
-
-
实例化类时的压栈顺序
-
当执行
const MyTreeTable1 = new MyTreeTableWrapper({mytreeData:PrdServiceFunCasesInputParameters.zwgetPrdServiceFunCasesInputParameters()});
:- 首先,会将
MyTreeTableWrapper
类的构造函数压入执行栈。在构造函数内部:- 当执行
const MyTreeTableInstance = defineComponent({...})
时,defineComponent
函数被调用,它内部的逻辑开始执行,相关的函数定义(如setup
函数内部定义的to_TransformData
、transformData
、displayNameBasedOnId
等)会被压入执行栈进行解析和执行。 - 在
setup
函数中,当执行if (properties) {...}
循环时,根据传入的属性进行操作。如果涉及到函数调用(如to_TransformData
函数中的transformData
函数调用),这些函数也会被压入执行栈。 - 当
setup
函数中的return () => h(TreeTable, {...})
语句执行时,h
函数被调用,它内部的逻辑会被压入执行栈,包括对TreeTable
和Column
组件的渲染逻辑处理。
- 当执行
- 最后,当
MyTreeTableWrapper
类的构造函数执行完毕,返回MyTreeTableInstance
,这个结果被赋值给MyTreeTable1
,此时相关的临时变量(如在构造函数内部定义的局部变量)会从执行栈中弹出,但MyTreeTable1
会持有对返回结果的引用。
- 首先,会将
-
总体而言,代码的压栈顺序遵循JavaScript的模块加载、解析和函数调用的执行顺序,从外层的模块导入到内层的类实例化和组件构建相关的函数调用。