在构造函数和作为构造函数调用的函数返回对象之间有什么区别? [英] What difference is there in JavaScript between a constructor function, and function returning object which is invoked as a constructor?

查看:179
本文介绍了在构造函数和作为构造函数调用的函数返回对象之间有什么区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道这不是推荐的做法,但如果我声明以下函数,然后调用它们作为构造函数,将产生的对象之间的差异(如果有)?

I know this is not the recommended way of doing it, but if I declare the following functions, and then invoke them as constructors, what will be the difference (if any) between the resulting objects?

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();

x y z 之间有什么区别?

I.e. what will differ between x, y and z here?

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

Wouldn't something2 be a much better way of writing the constructor, since whether you use new or not will not affect the result of the function?

BTW应该 something2 大写这里? (我认为,因为Crockford对资本化非常坚定,因为函数会破坏全局命名空间...)

BTW should something2 be capitalized here? (I assume not since Crockford is so adamant on the capitalization, for functions will clobber the global namespace...)

推荐答案

short:

new something2() instanceof something2 === false

相关地,如果你扩展你的例子使用原型属性

Relatedly, if you extend your example to use the prototype property

Something.prototype.method = function () { };
something2.prototype.method = function () { };

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

you will find that the prototype is not inherited in the latter case:

typeof (new Something()).method === "function"
type (new something2()).method === "undefined"






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


The real answer is that you are tapping into entirely different underlying machinery. Calling with new invokes the [[Construct]] mechanism, which involves setting the [[Prototype]] property according to the .prototype property of the constructor.

有趣的事情发生在[[Construct]]算法的步骤8--10:在设置一个新的空对象,然后附加它的[[Prototype]]之后,它对实际的构造函数做[[Call]],使用这个新的空加原型对象作为 this 。然后,在步骤9中,如果结果是该构造函数返回了一个东西---它抛弃了原型绑定,传递为 - 这个对象,它花了所有

But a funny thing happens in steps 8--10 of the [[Construct]] algorithm: after setting up a new, empty object, and then attaching its [[Prototype]], it does a [[Call]] to the actual constructor, using this new empty-plus-prototype object as this. And then, in step 9, if it turns out that that constructor returned something---it throws away that prototypally-bound, passed-as-this object that it spent all that time setting up!

注意:你可以访问对象的[[Prototype]](这不同于构造函数的 .prototype )与 Object.getPrototypeOf

Note: you can access an object's [[Prototype]] (which is different from a constructor's .prototype) with Object.getPrototypeOf:

Object.getPrototypeOf(new Something()) === Something.prototype // steps 5 & 6
Object.getPrototypeOf(new something2()) === Object.prototype // default



< hr>

要回答一些元问题:


To answer some meta-questions:


  • 不,不要大写< c $ c> something2 ,因为它是一个工厂函数,而不是一个构造函数。如果某事物被大写,它应该有构造函数语义,例如。 new A()instanceof A

  • 如果你担心全局命名空间被破坏的危险, a strict; 严格模式, / code>在文件的顶部。严格模式的许多不错的清理之一是这默认为未定义,而不是全局对象。在构造函数尝试将属性附加到 undefined 时,调用不带 new 的构造函数将导致错误。
  • 工厂函数(也称为闭包模式)通常是构造函数和类的合理替代,只要你(a)不使用继承; (b)不构造太多的该对象的实例。后者是因为,在闭包模式中,将每个方法的一个新实例附加到每个新创建的对象,这对内存使用情况不是很好。 IMO的最大收益是关闭模式是使用私有变量(这是一个好东西,不要让任何人告诉你:P)。

  • No, don't capitalize something2, since it is a factory function and not a constructor. If something is capitalized, it is expected to have constructor semantics, e.g. new A() instanceof A.
  • If you're worried about the danger of clobbering the global namespace, you should start using strict mode, by putting "use strict"; at the top of your files. One of the many nice cleanups of strict mode is that this defaults to undefined, not the global object, so e.g. calling a constructor without new will result in errors the moment the constructor tries to attach properties to undefined.
  • Factory functions (aka the "closure pattern") are in general a reasonable substitute for constructors and classes, as long as you are (a) not using inheritance; (b) not constructing too many instances of that object. The latter is because, in the closure pattern, you attach a new instance of every method to every newly-created object, which is not great for memory usage. The biggest payoff, IMO, of the closure pattern is the ability to use "private" variables (which are a good thing, and don't let anyone tell you otherwise :P).

这篇关于在构造函数和作为构造函数调用的函数返回对象之间有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆