JavaScript在构造函数和作为构造函数调用的函数返回对象之间有什么区别?

zra*_*ajm 11 javascript constructor function

我知道这不是推荐的方法,但如果我声明以下函数,然后将它们作为构造函数调用,那么结果对象之间的区别(如果有的话)是什么?

function Something() {
    this.foo = "bar";
}

function something2() {
    var that = {};
    that.foo = "bar";
    return that;
}

var x = new Something();
var y = new something2();
var z = something2();
Run Code Online (Sandbox Code Playgroud)

即什么都会有所不同x,yz在这里?

something2编写构造函数不是更好的方法,因为你是否使用new不会影响函数的结果?

BTW应该something2在这里大写?(我假设不是因为Crockford对大小写非常坚定,因为函数会破坏全局命名空间......)

Dom*_*nic 15

简而言之:

new something2() instanceof something2 === false
Run Code Online (Sandbox Code Playgroud)

相关地,如果您扩展您的示例以使用prototype属性

Something.prototype.method = function () { };
something2.prototype.method = function () { };
Run Code Online (Sandbox Code Playgroud)

你会发现原型在后一种情况下不会继承:

typeof (new Something()).method === "function"
type (new something2()).method === "undefined"
Run Code Online (Sandbox Code Playgroud)

真正的答案是你正在利用完全不同的底层机器.调用new调用[[Construct]]机制,该机制涉及根据.prototype构造函数的属性设置[[Prototype]]属性.

但是有趣的事情发生在[[Construct]]算法的第8-10步中:在设置一个新的空对象,然后附加其[[Prototype]]之后,它会对实际执行[[Call]]构造函数,使用这个新的empty-plus-prototype对象作为this.然后,在步骤9中,如果事实证明该构造函数返回了某些东西---它抛弃了原型绑定,传递给this对象,它花了所有时间设置!

注意:您可以使用以下命令访问对象的[[Prototype]](与构造函数不同.prototype)Object.getPrototypeOf:

Object.getPrototypeOf(new Something()) === Something.prototype // steps 5 & 6
Object.getPrototypeOf(new something2()) === Object.prototype // default
Run Code Online (Sandbox Code Playgroud)

回答一些元问题:

  • 不,不要大写something2,因为它是工厂函数而不是构造函数.如果某些东西是大写的,那么它应该具有构造函数语义,例如new A() instanceof A.
  • 如果您担心破坏全局命名空间的危险,您应该开始使用严格模式,方法是放在"use strict";文件的顶部.严格模式的许多很好的清理之一是this默认undefined,而不是全局对象,所以例如调用构造函数不会new在构造函数尝试附加属性时导致错误undefined.
  • 工厂函数(又称"闭包模式")通常是构造函数和类的合理替代,只要您(a)不使用继承; (b)不构造该对象的太多实例.后者是因为,在闭包模式中,您将每个方法的新实例附加到每个新创建的对象,这对于内存使用来说并不是很好.关闭模式的最大收益IMO是使用"私有"变量的能力(这是一件好事,不要让任何人告诉你:P).