我要从String切换到RegExp,因为String有一个皱纹我稍后会提到*。
实例接口(如RegExp 和JQuery)通常表示可以存在多个不同实例的对象类型。关联的静态接口(如RegExpConstructor 和JQueryStatic)通常表示创建或返回这些实例的对象类型;并且通常只有这些静态对象中的一个存在。所以只有一个RegExpConstructor 对象可以生成许多RegExp 对象,而只有一个JQueryStatic 对象可以生成许多JQuery 对象。
实践中一个常见的混淆来源是name collision between values and types。单个静态对象的名称(例如,RegExp 或 jQuery)往往与实例接口的名称相同。但是那个静态对象的类型不是实例接口的类型。因此,运行时名为RegExp 的值 的类型为RegExpConstructor,而不是RegExp。而在运行时名为jQuery 的值 的类型为JQueryStatic,而不是JQuery。这很令人困惑,但可能是最好的,因为它可以让你在运行时说出 x instanceof Y 之类的东西,而在编译时 x 的类型是 Y。
无论如何,如果有一个属性或方法的行为取决于特定的实例,它通常位于实例接口上。如果某些属性或方法的行为不依赖于特定实例,则通常位于静态接口上。
构造函数接口是一个静态接口,专门允许您在其上使用new operator 来创建新实例。在 TypeScript 中,这类似于函数调用签名,但名称为 new,如下所示:
type F = (x: string) => number[];
type C = new(x: string) => number[];
F 类型表示一个函数,它接受一个string 参数并生成一个numbers 数组,而C 类型表示一个构造函数,它接受一个@987654356 @ 参数并产生一个numbers 的数组:
declare const f: F;
declare const c: C;
const arr1 = f("hey"); // number[]
const oops1 = new f("hey"); // error, f is not newable
const arr2 = new c("hey"); // number[]
const oops2 = c("hey"); // error, c is not callable
有一个静态接口也是一个构造函数接口是很常见的;所有class 静态接口都是构造函数接口。但并不是每个静态接口都是构造函数接口。 JQueryStatic 接口就是一个例子。要从 JQueryStatic 对象中获取 JQuery 实例,您可以像调用函数一样调用它(这就是 (query: string): JQuery; 签名的含义)。
这就是JQueryStatic/JQuery 对和RegExpConstructor/RegExp 对之间的主要区别,也是问题主要答案的结尾。
*回到String 皱纹。名为String 的类型特指通过在String 构造函数上调用new 运算符构造的object。还有一种名为string(带有小写“s”)的类型,它指的是primitive 数据类型。实际上,您处理的所有字符串都是string 类型的原语,而String 是一个相对不常见的wrapper object,它拥有string 值。 string 和 String 大多可以互换:
const stringPrimitive = "hello"; // type is string
const stringObject = new String("hello"); // type is String
console.log(stringPrimitive+"!"); // "hello!"
console.log(stringObject+"!"); // "hello!"
console.log(stringPrimitive.charAt(4)); // "o"
console.log(stringObject.charAt(4)); // "o"
除非它们不可互换:
console.log(typeof stringPrimitive); // "string"
console.log(typeof stringObject); // "object"
console.log(stringPrimitive instanceof String); // false
console.log(stringObject instanceof String); // true
当您意识到StringConstructor 也可以像函数一样被调用并产生一个原语string时,情况变得更加混乱:
console.log(typeof "hey"); // "string"
console.log(typeof new String("hey")); // "object"
console.log(typeof String("hey")); // "string"
所以这是一团糟。这里的规则几乎是always use string; never use String。这就是为什么我将代码示例从 String 更改为 always-an-object RegExp,没有原始数据类型 (typeof /foo/ === "object") 妨碍。
好的,希望对您有所帮助。祝你好运!