繁体   English   中英

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

[英]What difference is there in JavaScript between a constructor function, and function returning object which is invoked as a constructor?

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

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

也就是说xyz之间的区别是什么?

会不会something2是编写构造的一个更好的方法,因为无论你使用new或不将不影响功能的结果呢?

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

简而言之:

new something2() instanceof something2 === false

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

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

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

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

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

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

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

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

回答一些元问题:

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

在第二种情况下,返回的对象不会从构造函数继承任何东西,因此使用它没有什么意义。

> var x = new Something();
> var y = new something2();
> var z = something2();

也就是说x,y和z之间的区别是什么?

x继承自Somethingyz都不会从something2继承。

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

有呼吁没有点something2作为一个构造函数,因为它返回的对象是未分配给它的新构造的对象this是从继承something2.prototype ,这是另一些可能是打电话时得到new something2()

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

不,因为将其称为构造函数是有点无意义的,因此将其描述为一个会产生误导。

调用函数作为构造函数(即使用new keyword )运行以下步骤:

  1. 创建一个新对象
  2. 将该对象的prototype设置为函数的prototype属性中的对象
  3. 在该对象的上下文中执行构造函数(即this是新对象)
  4. 返回该对象(如果构造函数没有return语句)

所以,你的第二个解决方案只返回一个带有属性“foo”的普通对象。 但是, yz都不是instanceof Something2instanceof Something2 ,也不会从该原型继承。 有这样的函数,是的,但它们不应该被称为构造函数(没有大写命名,没有new调用)。 它们属于工厂模式。

如果您想要一个可以在没有new的情况下执行的构造函数,请使用该代码:

function Something(params) {
    if (! this instanceof Something)
         return new Something(params);
    // else use "this" as usual
    this.foo = "bar";
    ...
 }

我要说最重要的是返回对象的原型。

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

  Something.prototype = {
    // Something prototype code
    hello: function(){
     //...
    }
  }

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

  something2.prototype = {
      // something2 prototype code
      greetings : function() {
      //...
      }
  }

  var x = new Something();
  var y = new something2();
  var z = something2();

  typeof x.hello === function // should be true
  typeof y.greetings === undefined // should be true
  typeof z.greetings === undefined // should be true

换句话说,我说你没有用某些东西实例化对象,你正在创建从Object继承的纯粹新对象。

  1. 当您使用new关键字时,Something()将为您提供“Something”类型的新对象。
  2. something2()将为您提供“Object”类型的新对象,它将立即返回一个新的空对象。
  3. new something2效率低下,因为您正在创建一个空白范围,您可以从中创建一个新对象

     var that = {}; 

    这相当于

     var that = new Object(); 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM