3

前言

无论是 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. 比较的是内存地址

引用类型的比较使用 === 或 == 时,比较的是内存地址是否相同,而不是对象的内容是否一致。

image.png

  1. 函数参数是引用传递
    当函数接收一个引用类型作为参数时,函数内对参数的操作会影响原始对象。
    image.png

浅拷贝与深拷贝

浅拷贝

浅拷贝只复制对象的第一层属性,对于嵌套对象仍然是通过引用共享。

image.png

深拷贝

深拷贝会递归地复制所有层级的属性,生成一个完全独立的对象。可以使用JSON.parse(JSON.stringify(obj)) 或第三方工具如 Lodash)会生成一个全新的实例。

image.png

什么是 Instance(实例)?

实例的定义

实例是通过类(class)或构造函数(constructor)创建出来的具体对象,它是类的一个实际化表现。

每个实例都在内存中占据独立的空间,拥有自己的属性和方法。修改一个实例的属性不会影响其他实例。

image.png

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;
  }

控制台出现报错:

image.png

在ngOnInit已经初始化了:

image.png

审阅历史的一些写法:定义了一个变量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 组件了。

image.png

翻阅文档后:nzRemove是回调函数。
image.png

其实在写法上我们就可以知道是回调方法,因为没有加括号:([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 检查类型

zZ_jie
449 声望9 粉丝

虚心接受问题,砥砺前行。