Date 与 new Date() 有何区别
抱歉,我需要您提供要翻译的完整文本内容。请把文章的其余部分粘贴在这里,我会帮您将其翻译成简体中文,并保留原始的格式和代码块。
介绍
昨天我深入研究了构造函数签名。今天我们将看看使用 new 关键字(构造函数签名)和直接调用函数(调用签名)之间的区别,尤其是针对像 Date 这样的内置对象。
如果你还没有阅读过关于调用构造函数的内容,请查看这篇文章:
Build a simple mini‑dayjs clone logger middleware by call signatures in TypeScript
构造函数 vs. 调用签名
在 JavaScript 中,你可能会看到如下代码:
Boolean();
new Date();
new Array();
new Promise(() => {});
区别如下:
| 签名 | 使用方式 | 返回值 |
|---|---|---|
构造函数(需要 new) | new Date(); | 对象(实例) |
| 调用(函数调用) | Date(); 或 dayjs(); | 原始值(或函数返回的任何值) |
为什么 new 返回对象
new 会创建一个 实例,而实例必须是对象,这样它才能拥有属性、方法以及原型链。原始值无法具备这些特性,因此语言设计规定 new 必须返回对象。
console.log(typeof String); // function
console.log(typeof String.prototype); // object
console.log(typeof new String()); // object
Source: …
原型继承概述
JavaScript 提供三种实现原型继承的方式:
- 对象字面量
- 构造函数
- 类
使用类的示例
class Human {}
console.log(typeof new Human()); // object
使用构造函数的示例
function Animal() {}
Animal.prototype.eat = function () {
console.log("Nhoammmm");
};
function inheritPrototype(proto) {
function ChainLink() {}
ChainLink.prototype = proto;
return new ChainLink();
}
function Human() {}
Human.prototype = inheritPrototype(Animal.prototype);
Human.prototype.work = function () {
console.log("Coding and earning money!");
};
const kelvynThai = new Human();
console.log(kelvynThai instanceof Human); // true
console.log(typeof kelvynThai); // object
kelvynThai.work(); // Coding and earning money!
kelvynThai.eat(); // Nhoammmm
TypeScript:为构造函数和调用签名添加类型
您可以描述一种类型,使其既可以作为构造函数(使用 new)又可以作为普通函数(调用签名)使用。
type MyDate = {
// Constructor signature – returns a String object
new (dateStr: string): String;
// Call signature – returns a primitive string
(dateNum?: number): string;
};
const MyDate: MyDate = function (this: unknown, d?: string | number) {
if (new.target) {
// When called with `new`, return a String object
return new String(`PARSED_DATE:${d}`);
}
// When called as a function, return a primitive string
return d !== undefined ? `TIMESTAMP:${d}` : "DEFAULT_DATE";
} as MyDate;
// Using the constructor
const dateWithNew = new MyDate("Sat 7 Feb 2026");
console.log(dateWithNew, typeof dateWithNew);
// [String: 'PARSED_DATE:Sat 7 Feb 2026'] object
// Using the call signature
const dateWithoutNew = MyDate(123456);
console.log(dateWithoutNew, typeof dateWithoutNew);
// TIMESTAMP:123456 string
// Built‑in example
console.log(new Date(), typeof new Date());
// 2026-02-07T13:58:57.212Z object
思维模型
new→ 创建一个 对象(实例)- 直接调用 → 返回一个 原始值(或函数返回的任何内容)
理解此模型后,TypeScript 的构造函数类型定义就容易得多。
当这些知识有帮助时
- 阅读内置 API – 知道函数是否需要
new。 - 设计灵活的库 – 在适当时同时提供构造函数和调用签名。
- 在 TypeScript 中建模函数行为 – 编写准确的类型定义。
- 掌握 JavaScript 内部机制 – 了解对象、原型和实例是如何创建的。
希望这能阐明它们之间的区别。祝编码愉快! 🚀