JS中的this指向
在JS代码中,对于this我们只需要关注它的指向,确保返回的是一个正确的值。this的指向由下面这几点决定:
- 对象调用某函数,其中的this就指向该对象
- 通过apply、bind、call来显示指定函数的this
- new一个函数,函数中的this指向返回的实例化对象
- 箭头函数的this指向父级作用域的this
TS中的this指向和this类型
但是在TS代码中,我们要使用this,还需要确认this的类型
下面我们看一个代码
你知道getOption中的this指向谁吗?答案应该是不知道,因为非箭头函数的this指向,只在调用时才能确定,静态编译期是确定不了的。const option = {
x: 1,
y: 2,
methods: {
getOption: function ():number[] {
return [this.x, this.y];
},
},
};
而在TS中,不仅要关心this的指向,还要关心this的类型。如果在编辑器中写上面的代码,编译器会报类型警告:图中所示,TS将this推断为含有
getOption
属性的对象,这不是我们想要的
我们想要的是,this代表option对象,通过this可以访问x、y。这里我们需要显示地定义this的类型。
应该怎么做呢
用interface定义this的类型
可以在形参的位置定义this的类型
interface I_Option {
x: number;
y: number;
getOption: () => [number, number];
}
const option = {
x: 1,
y: 2,
methods: {
getOption: function (this: I_Option) {
return [this.x, this.y];
},
},
};
这里先定义了一个接口I_Option
,其中的结构和option
相同。之后,在getOption
的形参中,对this的类型做了定义。现在不会报类型警告了
当然这个只是类型的推断,this的真正指向还要看代码运行阶段。
上面是解决定义this
类型定义的一个方法,还有一种方法,我们可以用TS内置函数ThisType<Type>
来实现
用ThisType实现对this类型的定义
定义一个通用的对象类型
const obj = {
data: {},
methods:{}
}
对象中的属性,无非就两种:数据,方法。所以上面的结构中,把数据全部放在了data里面,把方法全部放在了methods里面。
定义这样一个通用类型的对象,无非就是之后的接口类型定义能够方便一点
定义通用对象的接口类型
interface I_configObject<D,M>{
data: D;
methods: M
}
接口接收两个泛型,第一个泛型作为data的类型,第二个泛型作为methods的类型
定义一个创建对象的函数
function createObj<D, M>(configObj: I_configObject<D, M>) {
return {
...configObj.data,
methods: ...configObj.methods,
};
}
解释:
- 函数接收具有通用结构的configObj
- createObj也接受两个泛型,这两个泛型与data和methods的类型一致
- 你知道return中,为啥要这么做吗
使用createObj函数,看看效果
然后我们将符合通用类型的结构放进createObj函数中,就可以得到我们想要的option啦const option2 = createObj({
data: {
x: 1,
y: 2,
},
methods: {
getOption: function ():number[] {
return [this.x, this.y];
},
},
});
作者:额,心细的你是不是发现了什么?
读者:对,没有用ThisType啊,这连影子都没有见到。
作者:哦哦哦,对不起,立马加上如果你在编辑器中敲了上面的代码,发现还是会在this的地方报类型警告
interface I_configObject<D,M>{
data: D;
// 表示methods中的this是D & M类型的,
// 所以在methods中,可以访问D中的属性(x,y)
methods: M & ThisType<D & M>
}
现在可以了,不会报类型警告了
下图中,可以看到TS推断出的this类型:
这正是我们想要的
其次,也可以放在 createObj的形参中
//表示configObj中的this指向是D & M类型的
function createObj<D, M>(configObj: I_configObject<D, M> & ThisType<D & M>) {
return {
...configObj.data,
methods: configObj.methods,
};
}
效果是一样的
ThisType
总结:
- JS中的this指向
- TS中,不仅关心this指向,还要关注this的类型
- 使用interface中,在形参中对this进行类型注释
- 使用ThisType
对this进行类型注释 - 用ThisType
做类型注释真是磨人