Typescript export 导出分析-是引用还是值的形式?

Typescript  export 导出分析-是引用还是值的形式?

在 TypeScript 里,export 导出的内容是否为引用,要依据具体导出的内容类型来判断。

 

1. 导出原始类型(如数字、字符串、布尔值)

原始类型以值的形式导出,并非引用。在导出原始类型时,导出的是值的副本,而非引用。

// 导出原始类型
export const num = 10;

// 导入原始类型
import { num } from './module';
// 这里的 num 是原始值 10 的副本

 

2. 导出const 对象和数组

如果用 export const 导出,导入的绑定是只读的(不能直接 myObj = {}),虽然不能重新赋值,但可以修改对象属性。

当你导出一个对象或者数组时,实际上导出的是对该对象或数组的引用。这意味着导入模块修改这个对象或数组时,会影响到导出模块中的原始对象或数组。

 

// 导出对象
export const person = { name: 'Alice', age: 25 };

// 导入对象
import { person } from './module';
person.age = 26; 
// 这里修改的是同一个对象,导出模块中的 person 对象的 age 也会变为 26

TypeScript/ES 模块的这种设计使得状态共享和模块间通信更加灵活高效。

 

3. 导出 let 对象

在 TypeScript 中,使用 export let 导出对象时,导出的是引用(reference),而不是副本。这与 JavaScript 的 ES 模块规范一致。

导入方获取的是对原始对象的引用,任何修改都会反映在所有导入该对象的地方。由于是 let 声明,原始模块可以重新赋值,而导入方会看到新值。如果导出的是对象,修改其属性会在所有导入方可见

// module.ts
export let myObj = { value: 1 };

export function updateObj() {
  myObj.value = 2;  // 修改对象属性
}

export function replaceObj() {
  myObj = { value: 3 };  // 重新赋值(因为是 let)
}


// main.ts
import { myObj, updateObj, replaceObj } from './module';

console.log(myObj); // { value: 1 }

updateObj();
console.log(myObj); // { value: 2 } - 属性修改对所有导入方可见

replaceObj();
console.log(myObj); // { value: 3 } - 重新赋值也可见(因为是 let 导出)

 

 

4. 导出函数

函数同样是以引用的形式导出的。函数导出后,导入模块使用的是同一个函数实例。

// 导出函数
export function greet() {
    return 'Hello!';
}

// 导入函数
import { greet } from './module';
// 这里调用的是同一个函数实例

 

5. 1.导出class类

在 TypeScript 里,导出类定义是按引用的形式进行的。当把一个类导出并在其他模块中导入时,导入的是同一个类定义。这意味着,无论是在导出模块还是导入模块里对类进行静态属性修改、添加方法等操作,都会影响到这个类的所有引用。

以下是示例代码:

// exportClass.ts
// 定义一个类并导出
export class ExampleClass {
    static staticProperty = 'Initial value';
    constructor() {}
    public instanceMethod() {
        return 'This is an instance method.';
    }
}
// importClass.ts
// 导入类
import { ExampleClass } from './exportClass';

// 修改类的静态属性
ExampleClass.staticProperty = 'Modified value';

// 创建实例
const exampleInstance = new ExampleClass();
console.log(exampleInstance.instanceMethod());
console.log(ExampleClass.staticProperty);

 

在上述代码中,ExampleClass 被导出后在另一个模块导入,修改其静态属性 staticProperty 会影响到类的所有引用。

5.2. 类实例化的情况

虽然类是按引用导出,但每次实例化类时都会创建一个新的对象实例。不同的实例之间是相互独立的,对一个实例的属性或方法进行修改,不会影响到其他实例。

// 创建两个不同的实例
const instance1 = new ExampleClass();
const instance2 = new ExampleClass();

// 修改 instance1 的属性不会影响 instance2

 


// 如果是值拷贝(实际不是这样):
let exportedObj = { value: 1 };
let importedObj = exportedObj; // 实际行为类似这样,但模块系统有更多约束

// 修改会互相影响
exportedObj.value = 2;
console.log(importedObj.value); // 2

总结来说,原始类型是按值导出,对象、数组和函数则是按引用导出。TypeScript 中导出类是按引用形式,即导出的是类定义的引用。不过,每次实例化类时会创建独立的对象实例。

 

6. 如何设置:属性是只读的

虽然类是按引用导出,但每次实例化类时都会创建一个新的对象实例。不同的实例之间是相互独立的,对一个实例的属性或方法进行修改,不会影响到其他实例。

但如果你希望导出的对象的某些属性是只读的(即导入方不能修改),有几种方法可以实现:

在导出对象的类型中标记某些属性为 readonly,这样导入方就无法修改这些属性。

方法 1:使用 readonly 修饰符

在导出对象的类型中标记某些属性为 readonly,这样导入方就无法修改这些属性。

 

// module.ts
export interface MyObject {
  readonly id: number;  // 只读属性
  name: string;        // 可修改属性
}

export const myObj: MyObject = {
  id: 1,
  name: "Alice"
};

// main.ts
import { myObj } from './module';

myObj.name = "Bob";  // ✅ 允许修改
myObj.id = 2;        // ❌ 编译错误:无法修改只读属性

方法 2:使用 Readonly<T> 或 Readonly<Partial<T>>

如果你希望整个对象的所有属性都是只读的,可以使用 Readonly<T> 泛型。

// module.ts
export interface MyObject {
  id: number;
  name: string;
}

export const myObj: Readonly<MyObject> = {
  id: 1,
  name: "Alice"
};


// main.ts
import { myObj } from './module';

myObj.name = "Bob";  // ❌ 编译错误:所有属性都是只读的
myObj.id = 2;        // ❌ 编译错误

方法 3:使用 Object.freeze()(运行时只读)

如果你不仅想在编译时限制修改,还想在运行时阻止修改,可以使用 Object.freeze()

// module.ts
export const myObj = Object.freeze({
  id: 1,
  name: "Alice"
});

// main.ts
import { myObj } from './module';

myObj.name = "Bob";  // ❌ 运行时静默失败(严格模式下会报错)
myObj.id = 2;        // ❌ 同上

注意Object.freeze() 是浅冻结,如果对象包含嵌套对象,内部对象仍然可以修改。如果需要深冻结,可以使用 deep-freeze 等库。

 

总结

方法编译时检查运行时保护适用场景
readonly 修饰符只需要 TS 类型检查
Readonly<T>整个对象只读
Object.freeze()需要运行时保护
Readonly + Object.freeze()最严格保护

如果你希望:

  • 仅限制 TypeScript 编译时修改 → 用 readonly 或 Readonly<T>

  • 确保运行时也不能修改 → 用 Object.freeze()

  • 最严格的保护 → 同时使用 Readonly<T> 和 Object.freeze()

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值