什么时候用JavaScript创建新对象';类中的构造函数vs? 构造函数

什么时候用JavaScript创建新对象';类中的构造函数vs? 构造函数,javascript,ecmascript-6,ecmascript-2017,Javascript,Ecmascript 6,Ecmascript 2017,当通过一个好的旧ES5构造函数创建新对象时:什么时候创建新对象 猜测:当JS引擎遇到new关键字时,是否会在执行构造函数之前立即创建猜测 等级 与上面类似,但对于类:新对象是何时创建的 猜测:由于我们可以使用类语法对内置对象进行子类化,因此我认为引擎必须知道其父对象是什么类型(外来vs普通)。因此,我在想,当引擎遇到extends关键字并且可以读取父对象的类型时,可能会创建新对象 最后 在这两种情况下,何时设置prototype属性?它是在执行构造函数/类主体之前还是之后 笔记 注1:如果

当通过一个好的旧ES5构造函数创建新对象时:什么时候创建新对象

猜测:当JS引擎遇到
new
关键字时,是否会在执行构造函数之前立即创建猜测


等级 与上面类似,但对于类:新对象是何时创建的

猜测:由于我们可以使用
语法对内置对象进行子类化,因此我认为引擎必须知道其父对象是什么类型(
外来
vs
普通
)。因此,我在想,当引擎遇到
extends
关键字并且可以读取父对象的类型时,可能会创建新对象


最后 在这两种情况下,何时设置prototype属性?它是在执行构造函数/类主体之前还是之后


笔记 注1:如果答案中能包含两个创造物各自出现的位置的链接,那就太好了。我一直在四处搜索,一直无法找到正确的算法步骤

注2:使用“created”(已创建)是指至少在内存和类型集中分配的空间(外来与普通)。

将调用,然后调用相关函数的内部。这里我只讨论正常的[[Construct]],而不关心代理的自定义行为,因为这与主题无关


在标准场景(no
extends
)中,在步骤5.a中,[[Construct]]调用,该调用的返回将用作
(请参阅,其中它用作参数)。请注意,OrdinaryCallEvaluationeBody在后面的步骤中出现-在计算构造函数之前创建对象。对于
newf
,它基本上是
对象。创建(f.prototype)
。通常,它是
Object.create(newTarget.prototype)
。这与
和ES5方式相同。原型机显然也设置在那里


混淆可能源于使用
extends
的情况。在这种情况下,[[ConstructorKind]]不是“base”(请参见的步骤15),因此在[[Construct]]中,步骤5.a不再适用,也不会调用OrdinaryCallBindThis。这里最重要的部分发生在。长话短说,它使用超级构造函数和当前的newTarget调用Construct,并将结果绑定为
this
。因此,如您所知,在超级调用之前访问
会导致错误。因此,“新对象”是在超级调用中创建的(请注意,所讨论的方法再次适用于该构造调用-如果超级构造函数不扩展任何内容,则为非派生情况,否则为此情况-唯一的区别是newTarget)

为了详细说明newTarget转发,下面是一个该行为的示例:

class A{constructor(){console.log(`newTarget:${new.target.name}`);}
类B扩展了{constructor(){super();}}
console.log(
`prototype的原型:${Object.getPrototypeOf(B.prototype).constructor.name}.prototype`
);
log(“正在执行`newa();`:”);
新A();
log(“正在执行`new B();`:”);
新B()将调用,然后调用相关函数的内部函数。这里我只讨论正常的[[Construct]],而不关心代理的自定义行为,因为这与主题无关


在标准场景(no
extends
)中,在步骤5.a中,[[Construct]]调用,该调用的返回将用作
(请参阅,其中它用作参数)。请注意,OrdinaryCallEvaluationeBody在后面的步骤中出现-在计算构造函数之前创建对象。对于
newf
,它基本上是
对象。创建(f.prototype)
。通常,它是
Object.create(newTarget.prototype)
。这与
和ES5方式相同。原型机显然也设置在那里


混淆可能源于使用
extends
的情况。在这种情况下,[[ConstructorKind]]不是“base”(请参见的步骤15),因此在[[Construct]]中,步骤5.a不再适用,也不会调用OrdinaryCallBindThis。这里最重要的部分发生在。长话短说,它使用超级构造函数和当前的newTarget调用Construct,并将结果绑定为
this
。因此,如您所知,在超级调用之前访问
会导致错误。因此,“新对象”是在超级调用中创建的(请注意,所讨论的方法再次适用于该构造调用-如果超级构造函数不扩展任何内容,则为非派生情况,否则为此情况-唯一的区别是newTarget)

为了详细说明newTarget转发,下面是一个该行为的示例:

class A{constructor(){console.log(`newTarget:${new.target.name}`);}
类B扩展了{constructor(){super();}}
console.log(
`prototype的原型:${Object.getPrototypeOf(B.prototype).constructor.name}.prototype`
);
log(“正在执行`newa();`:”);
新A();
log(“正在执行`new B();`:”);
新B()
当通过一个好的旧ES5构造函数创建新对象时:什么时候创建新对象

对象构造行为的规范级定义由
[[Construct]]
函数定义。对于标准JS函数(
function Foo(){}
,此函数的定义在
functionKind
中初始化,其中
functionKind
设置为“正常”
。然后您可以在步骤
9.a
中看到,
[[ConstructorKind]]
插槽声明为指向,并且
[[ConstructorKind]
设置为
“基本”

当用户公司
function Parent(){}
function Child(){
  Base.apply(this, arguments);
}
Object.setPrototype(Child.prototype, Parent.prototype);

new Child();
class Parent {
  constructor() {
  }
}
class Child extends Parent {
  constructor() {
    super();
  }
}
console.log(value);
const value = 4;
class Parent extends Array {
  constructor() {
    console.log(new.target); // Child
    super();
  }
}
class Child extends Parent {
  constructor() {
    console.log(new.target); // Child
    super();
  }
}
new Child();