构造函数可以返回原语吗?

GOT*_*O 0 7 javascript primitive constructor new-operator

我问这个问题是因为我注意到 TypeScript 允许声明返回原始类型的构造函数,例如:

type Constructor1 = new () => string; // Primitive string
Run Code Online (Sandbox Code Playgroud)

相对于

type Constructor2 = new () => String; // String object
Run Code Online (Sandbox Code Playgroud)

这让我想知道 JavaScript 是否真的允许创建一个在使用语义调用时返回原始值的函数,即通过原始性测试的new值:

type Constructor1 = new () => string; // Primitive string
Run Code Online (Sandbox Code Playgroud)

不用说,我找不到任何生成原始值的构造函数调用的示例,因此我想这一定是 TypeScript 类型模型的另一个奇怪之处。或者原始构造函数真的存在吗?


作为参考,这是我尝试过的。

预定义构造函数

预定义的构造函数NumberBooleanString等在使用 调用时都会生成一个对象new,尽管它们在作为常规函数调用时返回一个原始值。IE

type Constructor2 = new () => String; // String object
Run Code Online (Sandbox Code Playgroud)

function isPrimitive(value) {
    return value !== Object(value);
}
Run Code Online (Sandbox Code Playgroud)

return在构造函数中

语句return会覆盖构造函数中的实例this,但前提是返回值是对象:

isPrimitive(new Number()) // false

isPrimitive(Number())     // true
Run Code Online (Sandbox Code Playgroud)

function isPrimitive(value) {
    return value !== Object(value);
}

console.log(isPrimitive(new Number()));
console.log(isPrimitive(Number()));
Run Code Online (Sandbox Code Playgroud)

construct陷阱

代理可以提供构造陷阱来处理对具有语法的函数的调用new。陷阱返回的任何对象也将由构造函数调用返回。但是,如果陷阱返回 以外的原始值undefined,则会发生 a TypeError

const OBJECT = { foo: "bar" };
const PRIMITIVE = "baz";

function TheObject() {
    return OBJECT;
}

function ThePrimitive() {
    return PRIMITIVE;
}

console.log(isPrimitive(new TheObject()));    // prints false
console.log(isPrimitive(new ThePrimitive())); // prints false
Run Code Online (Sandbox Code Playgroud)

function isPrimitive(value) {
    return value !== Object(value);
}

const OBJECT = { foo: "bar" };
const PRIMITIVE = "baz";

function TheObject() {
    return OBJECT;
}

function ThePrimitive() {
    return PRIMITIVE;
}

console.log(isPrimitive(new TheObject()));    // prints false
console.log(isPrimitive(new ThePrimitive())); // prints false
Run Code Online (Sandbox Code Playgroud)


更多想法?

tri*_*cot 5

构造函数可以返回原语吗?

ECMAScript 规范将构造函数定义为:

...支持 [[Construct]] 内部方法的对象。

尽管外来对象在实现内部方法方面有一定的自由度,但规范在6.1.7.3 基本内部方法的不变量中指出:

ECMAScript 引擎对象的内部方法必须符合下面指定的不变量列表。普通 ECMAScript 对象以及本规范中的所有标准外来对象都维护这些不变量。ECMAScript Proxy 对象通过对 [[ProxyHandler]] 对象上调用的陷阱结果进行运行时检查来维护这些不变量。

提供外来对象的任何实现也必须维护这些对象的这些不变量。违反这些不变量可能会导致 ECMAScript 代码出现不可预测的行为并产生安全问题。然而,违反这些不变量绝不能损害实现的内存安全。

实现不得允许以任何方式规避这些不变量,例如通过提供实现基本内部方法的功能而不强制执行其不变量的替代接口。

[...]

任何内部方法返回的值必须是具有以下任一内容的完成记录:

  • [[Type]] = normal、[[Target]] =empty和 [[Value]] = 下面所示的该内部方法的“正常返回类型”的值,或者
  • [[Type]] = throw、[[Target]] =empty和 [[Value]] = 任何 ECMAScript 语言值。

[...]

[[构造]] ( )

  • 正常的返回类型是Object。

[...]

所以总而言之,一个兼容的ECMAScript 实现不允许[[Construct]]内部方法的返回值是一个原语。

请注意,“正常返回类型”在这里有特定的含义,上面的引用中也介绍了这一点。这里的“正常”是指没有抛出错误的情况。


您还这样表述您的问题:

这让我想知道 JavaScript 是否真的允许创建一个在使用新语义调用时返回原始值的函数

13.3.5 新的 Operator中,规范规定Construct执行该过程(如果所有检查都通过):

  1. 返回 ?构造(构造函数argList)。

7.3.15 Construct ( F [ ,argumentsList [ , newTarget ] ] )中的过程依次指定:

  1. 返回 ?F .[[构造]](参数列表, newTarget ).

因此该new运算符将导致[[Construct]]内部方法的执行,因此上述内容适用。