1

到底有什么区别

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

var obj = new ObjA();

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

var obj = new ObjB();

我之所以问,是因为我正在阅读这个问题,并且在其中一个答案中注意到以下内容:

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; }
};

他们在评论中说,前者“占用内存,因为每个对象的 getter 和 setter 都是“唯一的””。有人可以详细说明一下吗?

4

5 回答 5

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第一个示例(模块模式)的实例的代码总是Object通过使用工厂方法创建基本类型的东西

于 2012-09-24T17:55:03.907 回答
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 的原型链。这是一个全新的对象。这就是“差异”。

第二个例子(使用.prototypevs. 返回一个对象)实际上据我所知,并没有真正“浪费”记忆(见更新)。因为在new函数上调用操作符的过程会创建对象原型的副本,然后调用它的函数。好的部分是原型方法将在您使用时在“构造函数”函数中可用.prototype,并且您将使用该版本维护原型链。但我不知道使用基于返回的方法真的有什么“错误”。

更新:

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

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

于 2012-09-24T17:58:15.967 回答
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,在构造函数中使用 s 将导致无法从构造函数本身的范围之外访问它们。因此,您可以将它们用作私有并定义作为 getter/setter 工作的函数,例如:

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

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

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

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

我推荐阅读“JavaScript:好的部分”

于 2012-09-24T18:10:36.680 回答
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
      };
    }
于 2012-09-24T17:54:22.487 回答
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创建一个外部属性。这样做的好处是它允许您在获取/设置时创建属性或进行计算,以及许多其他事情。Agetsetstaticreadonly

于 2012-09-24T17:58:36.073 回答