前言
无论是 JavaScript 还是 TypeScript,Reference(引用) 和 Instance(实例) 都是非常重要的概念。
什么是 Reference(引用)?
引用的定义
在JS和TS中,应用表示对内存中某个对象的地址或指针,它指向了实际存储对象的内存位置。引用本身不是对象,而是操作的一种手段。
当我们对引用进行赋值、传传递或修改是,实际上是在操作对象在内存中的地址,而不是操作对象本身。因此,多个变量可以通过引用指向同对象。
引用类型和原始类型的区别
引用类型:存储的是对象的内存地址(引用),赋值或传递时,共享同一个内存地址。对其中一个引用进行修改,会影响其他引用。
- 包括:Object、array等。
原始类型:存储的是值本身,赋值或传递时,值会被复制,两个变量之间没有联系。
- 包括:string、number、boolean、null、undefined等。
示例:
// 引用类型:地址的共享
const obj1 = { value: 100 };
const obj2 = obj1 // obj2 引用了 obj1
obj2.value = 200;; // 修改 obj1 的属性
console.log(obj1.value); // 输出: "Bob"(因为 objA 和 objB 指向同一个对象)
// 原始类型:值的复制
let a = 10;
let b = a;
b = 20;
console.log(a); // 输出: 10(a 不受 b 的修改影响)
引用类型的特性
1. 共享内存地址
引用类型变量存储的并不是对象本身,而是对象的内存地址。多个变量可以引用同一个对象,因此修改其中一个变量的属性,会影响所有引用。即上面那个示例
2. 比较的是内存地址
引用类型的比较使用 === 或 == 时,比较的是内存地址是否相同,而不是对象的内容是否一致。
- 函数参数是引用传递
当函数接收一个引用类型作为参数时,函数内对参数的操作会影响原始对象。
浅拷贝与深拷贝
浅拷贝
浅拷贝只复制对象的第一层属性,对于嵌套对象仍然是通过引用共享。
深拷贝
深拷贝会递归地复制所有层级的属性,生成一个完全独立的对象。可以使用JSON.parse(JSON.stringify(obj)) 或第三方工具如 Lodash)会生成一个全新的实例。
什么是 Instance(实例)?
实例的定义
实例是通过类(class)或构造函数(constructor)创建出来的具体对象,它是类的一个实际化表现。
每个实例都在内存中占据独立的空间,拥有自己的属性和方法。修改一个实例的属性不会影响其他实例。
this 和实例
this 关键字在类的方法中,通常指向当前的实例。在 js 中,this 的指向是动态的,取决于函数的调用方式。
案例:之前用到的nz-upload,上传文件时,然后在删除文件的时候的问题。
当点击删除时 触发onAvatarRemove 方法。
// html
<nz-upload class="avatar-uploader"
...
[nzRemove]="onAvatarRemove">
<button type="button" nz-button>
<span nzType="upload" nz-icon>上传图片</span>
</button>
</nz-upload>
// AddComponent
onAvatarRemove() {
this.formGroup.get('avatar')?.setValue(null);
return true;
}
控制台出现报错:
在ngOnInit已经初始化了:
审阅历史的一些写法:定义了一个变量that,用来存储 当前上下文 this;
let that: AddComponent;
ngOnInit(): void {
that = this;
}
onAvatarRemove() {
that.formGroup.get('avatar')?.setValue(null);
return true;
}
虽然解决了问题,为什么当使用 nzRemove方法的时候 this中就没有了formGroup了呢,在onAvatarRemove方法中打印this,发现this不是 AddComponent组件了,而是:NzUploadComponent 组件了。
翻阅文档后:nzRemove是回调函数。
其实在写法上我们就可以知道是回调方法,因为没有加括号:([nzRemove]="onAvatarRemove" )如果是直接调用方法,则会立即执行 onAvatarRemove 并将它的返回值赋给 nzRemove,而不是将函数本身传递。
分析:
onAvatarRemove 被作为属性传递给 NzUploadComponent 的 [nzRemove],最终是由 NzUploadComponent 调用的。
因此,onAvatarRemove 中的 this 默认指向 NzUploadComponent,而不是 AddComponent。
最终写法:
onAvatarRemove = () : boolean => {
this.formGroup?.get('avatar')?.setValue(null);
return true;
}
小结:
“如果一个方法中有 this,这个函数有被上一级的对象所调用,那么 this 指向的就是上一级的对象。”
总结
概念 | Reference(引用) | Instance(实例) |
---|---|---|
定义 | 对内存中对象地址的引用 | 类的具体化表现,是独立的对象 |
特点 | 多个引用共享同一对象,操作相互影响 | 各实例独立存在,修改一个实例不会影响其他实例 |
比较 | 比较内存地址是否相同 | instanceof 检查类型 |
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。