JavaScript构造函数中的return语句

时间:2012-09-24 17:46:09

标签: javascript constructor

之间究竟有什么区别
function ObjA() {
  this.a = 'text';
}

var obj = new ObjA();

function ObjB() {
  return {
    a: 'text'
  };
}

var obj = new ObjB();

我问,因为我正在阅读this question并且我在其中一个答案中注意到了以下内容:

function Test() {
  this.a = 1;

  return {
    get A() { return this.a; },
    set A(v) { this.a = v; }
  };
}

所以我问自己,这和下面的区别是什么:

function Test() {
    this.a = 1;
}

Test.prototype = { 
    get A() { return this.a; },
    set A(v) { this.a = v; }
};

他们在评论中说,前者"记忆作为吸气剂和制定者是"独特"每个对象"。有人可以详细说明一下吗?

5 个答案:

答案 0 :(得分:1)

你的上一个例子不起作用。

function Test() {
    var a = 1;
}

Test.prototype = { 
    // This code has no clue what a is
    get A() { return a; },
    set A(v) { a = v; }
};

但如果是

function Test() {
    this.a = 1;
}

Test.prototype = { 
    get A() { return this.a; },
    set A(v) { this.a = v; }
};

然后两段代码将是相似的,除了使用Test.prototype的代码创建Test的实例,其中第一个示例(模块模式)总是创建一些基本类型{ {1}}使用Factory方法

答案 1 :(得分:1)

你实际上问了几个不同的问题。所以让我专注于第一个(修改变量名称以更容易地引用它们而不是覆盖Object):

之间究竟有什么区别:

function ObjA() {
  this.a = 'text';
}

var objA = new ObjA();

function ObjB() {
  return {
    a: 'text'
  };
}

var objB = new ObjB();

不同之处在于前一版本维护原型链,而后一版本则丢弃原型链。请考虑以下代码行:

ObjA.prototype.b = "something";
ObjB.prototype.b = "something";

以下情况变为现实:

objA.b; //is "something"
objB.b; //is undefined

原因是从“构造函数”返回的对象不附加ObjB的原型链。这是一个全新的对象。这就是“差异”。

第二个例子(使用.prototype与返回对象)实际上实际上并没有“浪费”内存,据我所知(请参阅更新)。因为在函数上调用new运算符的过程将创建对象原型的副本,然后调用其函数。好的部分是当您使用.prototype时,原型方法将在“构造函数”函数中可用,并且您将使用该版本维护原型链。但我不知道使用基于回归的方法有什么“错误”。

<强>更新

我查看了关于这个主题的ECMAScript规范(并且我的想法有点过时),看来我对内存浪费的看法不对。看起来“class”函数的prototype属性的方法/属性通过引用链接。所以它实际上浪费了一点内存来生成一个新对象,而不是使用原型。此外,在返回的对象中声明的任何属性都是实例级的,而在原型对象中声明的属性对于“类”是静态的(即由所有实例共享)。

正如其他人所说,您的示例有一个小错误(原型对象无法使用a)。但这对于手头的问题来说有点无关紧要,所以我忽略了它。(我看到你修复了这个错误)。

答案 2 :(得分:1)

之间的区别
function Obj () {
  this.a = 'text';
}

var obj = new Obj();

function Obj () {
  return {
    a: 'text'
  };
}

var obj = new Obj();

这是第一个被认为是不安全的吗?也就是说,如果您忘记使用new运算符,则会使用属性污染全局命名空间。

第二种定义对象的方法要好得多。您可以同时var obj = new Obj();var obj = Obj();,结果将完全相同。

此外,在构造函数中使用var将导致无法从构造函数本身的范围外访问它们。因此,您可以将它们用作私有并定义充当getter / setter的函数,例如:

function Obj () {
    var privateVar = 'xxx';

    return {
        getPrivateVar: function () {
            return privateVar;
        },
        setPrivateVar: function (val) {
            privateVar = val;
        }
    };
}

这样你就可以从构造函数外部访问变量,但是如果没有调用正确的函数(setter),你将无法修改它。

使用原型是一个广泛的主题。它允许您节省内存(方法在对象实例之间共享,而不是在每次创建新对象时创建),它允许您仅通过修改原型来修改对象的所有实例中的方法。此外,原型可用于模仿继承(寻找“原型链”)。

我建议阅读"JavaScript: The Good Parts"

答案 3 :(得分:0)

允许您创建没有私有方法/功能的对象(模拟,但它是)

   function Object() {
      // a can be change via OBJECTs API
      this.a = 7;
    }

允许使用函数和变量到“内部作业”,这在代码

中是不可访问的
 function Object() {
      // b CAN BE CHANGED FROM OBJECTs  API 
      var b = 125;          
      return {
        a: 7+b
      };
    }

答案 4 :(得分:0)

function Object() {
  this.a = 'text';
}
var obj = new Object();

function Object() {
  return {
    a: 'text'
  };
}
var obj = new Object();

每个都会像:

一样使用
console.log(obj.a); // 'text'

然而,

function Test() {
  var a = 1;

  return {
    get A() { return a; },
    set A(v) { a = v; }
  };
}
var obj = new Test();

将像

一样使用
console.log(obj.A); // 1
obj.A = "banana";
console.log(obj.A) // 'banana'

它使a变为私有,并向A / get创建外部属性set。这样做的好处是,它允许您创建属性staticreadonly,在获取/设置时进行计算以及许多其他事情。