对象创建功能

时间:2013-02-02 22:55:53

标签: javascript memory-management

前几段描述了我想要实现的目标,实际的问题是最后的。感谢

以前,我只是使用new关键字来创建对象,并使用原型来分配方法和处理继承。然而,最近(部分受到CoffeeScript生成的JS的启发)我决定使用一个看起来像这样的对象创建函数:

var Test = function(a) {
    function Test(a) {
        this.a = a;
    }
    var numCalls = 0;
    Test.prototype.output = function() {
        alert('I was initialized with ' + this.a);
        numCalls++;
    };
    Test.prototype.called = function() {
        alert('You called the output ' + numCalls + ' times');
    };
    return new Test(a);
};

然后我会创建一个这样的新对象:

var obj = Test('string');

与每个实例使用new的典型方法相比,此方法有一些优势。首先,我不太可能忘记使用new这个词(我知道还有其他方法可以避免new,但是从我看到它们的问题与我在下面描述的问题类似),其次,我可以很容易地看到构造函数在任何现在属于类的函数中看到的“私有”变量。我测试的时候确实遇到过警告。 instanceof不再有效,因为它没有看到内部对象测试。为了解决这个问题,我尝试使用构造函数属性:

var a = Test('one');
var b = Test('two');
a.constructor == b.constructor              // false
a.constructor.name == b.constructor.name    // true

这让我感到困惑。在不使用对象创建函数的情况下创建相同的对象会导致它们的构造函数相等,但在这种情况下它们会有所不同。我的猜测是,每次运行函数时都会生成一个全新的对象类型(对象结构相同,但原型的实例不同)。

如果我对问题的理解是正确的,那么这是否意味着代码为每个对象实例分配额外的内存给我的JavaScript,以便在实例之间共享这些函数,通过欺骗它来为每个实例创建一个相同的对象原型(打败使用原型的整个目的)?如果是这样,是否有一种避免这种情况的好方法,同时仍然保持这种模式的好处(能够在内部函数之间共享私有变量而不必使用new关键字)?

如果我误解了这个问题,有人可以告诉我实际发生的事情吗?

2 个答案:

答案 0 :(得分:3)

  

如果是这样,有一个好方法可以避免这种情况,同时仍然保持这个   这种模式的好处......

尝试使用模块方法:

var Test = (function TestModule() {

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

  Test.prototype = {

  };

  return function(a) {
    return new Test(a);
  };

}());

var a = Test('foo');
var b = Test('baz');

a.constructor == b.constructor; // true
a.constructor.name == b.constructor.name; // true

答案 1 :(得分:0)

现在我努力完成这项工作:完全封装的完美类,实例化它不需要“新”。经过一段时间的搜索,我想出了这个:

function Test(x){

    var innerFunction = function(y){
        var variable = y;

        this.getA = function(){
            return variable;
        }

        this.setA = function(x){
            variable = x;
        }
    }
    return new innerFunction(x);
}

但测试结果证明错了:

var a = Test("foo");
var b = Test("baz");

alert(a.constructor == b.constructor);             //false, not good!
alert(a.constructor.name == b.constructor.name);   //true

所以似乎有错误的范围,所以我使用了公共内部函数

function Test(x){

    function innerFunction(y){
        var variable = y;

        this.getA = function(){
            return variable;
        }

        this.setA = function(x){
            variable = x;
        }
    }
    return new innerFunction(x);
}

经过一些广泛的测试证明这是正确的:

var a = Test("foo");
var b = Test("baz");

alert(a.constructor == b.constructor);             //true, made it!
alert(a.constructor.name == b.constructor.name);   //true

alert(a.getA());                        //"foo" as expected
alert(a.getA() == b.getA());            //false as expected

a.variable = "whatever";
alert(a.getA());                       //"foo" as expected
alert(a.variable);                     //"whatever", doesn't seem preventable

a.setA("somewhere");
alert(a.getA());                       //"somewhere", as expected
alert(a.variable);                     //"whatever", doesn't seem preventable

但是,我们可以用这种方式使用几个函数吗?这是我的第一个方法:

function Test(x){

    function innerFunction(y){
        var variable = y;

        this.getA = function(){
            return variable;
        }

        this.setA = function(x){
            variable = x;
        }
    }
    return new innerFunction(x);
}

function TestToo(x){

    function innerFunction(y){
        var variable = y;

        this.getA = function(){
            return variable;
        }

        this.setA = function(x){
            variable = x;
        }
    }
    return new innerFunction(x);
}

var a = Test("foo");
var b = Test("baz");

var c = TestToo("foo");
var d = TestToo("baz");

alert(a.constructor == b.constructor);             //true, as expected
alert(a.constructor.name == b.constructor.name);   //true, as expected

alert(c.constructor == d.constructor);             //true, as expected
alert(c.constructor.name == d.constructor.name);   //true, as expected

alert(a.constructor == c.constructor);             //false, as expected
alert(a.constructor.name == c.constructor.name);   //true, as NOT expected

这就是它?我们是否真的总是需要知道a.constructor.name与字符串的比较的内部类结构? Nooooo,因为在Javascript中你可以完全做任何事情(你只需要知道如何,而不是为什么),我发现了这个最终解决方案:

function Test(x){

    function Test(y){
        var variable = y;

        this.getA = function(){
            return variable;
        }

        this.setA = function(x){
            variable = x;
        }
    }
    return new Test(x);
}

function TestToo(x){

    function TestToo(y){
        var variable = y;

        this.getA = function(){
            return variable;
        }

        this.setA = function(x){
            variable = x;
        }
    }
    return new TestToo(x);
}

var a = Test("foo");
var b = Test("baz");

var c = TestToo("foo");
var d = TestToo("baz");

alert(a.constructor == b.constructor);             //true, as expected
alert(a.constructor.name == b.constructor.name);   //true, as expected

alert(c.constructor == d.constructor);             //true, as expected
alert(c.constructor.name == d.constructor.name);   //true, as expected

alert(a.constructor == c.constructor);             //false, as expected
alert(a.constructor.name == c.constructor.name);   //false, q.e.d.!

我很认真,我不知道为什么会这样。但它确实100%有效,100%对象封装,与Java类1:1相等。 ; - )