Javascript 对象创建函数
前几段描述了我试图实现的目标,实际问题在最后。谢谢 以前,我只是简单地使用Javascript 对象创建函数,javascript,memory-management,Javascript,Memory Management,前几段描述了我试图实现的目标,实际问题在最后。谢谢 以前,我只是简单地使用new关键字来创建对象,并使用原型来分配方法和处理继承。然而,最近,(部分灵感来自CoffeeScript生成的JS)我决定使用一个对象创建函数,该函数如下所示: var Test = function(a) { function Test(a) { this.a = a; } var numCalls = 0; Test.prototype.output = functio
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');
然后我将创建一个新对象,如下所示:
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
关键字)
如果我误解了这个问题,有人能告诉我到底发生了什么吗
如果是这样的话,有没有一个好方法可以避免这种情况,同时保持
这种模式的好处
尝试改用模块方法:
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
现在我努力搜索来完成这项工作:完美的类,具有完整的封装,不需要“新”来实例化它。在搜索了一段时间后,我得出了以下结论:
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
因此,似乎存在错误的范围,因此我使用了一个公共内部函数:
通过大量的测试证明了它的正确性:
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
与字符串比较的内部类结构吗?不,因为在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 你为什么忘了关键字new?我的意思是,每次你创建一个新对象,你都会使用“new”,这很简单。这个解决方案在许多OO语言中已经存在了几十年,这是一件好事,因为每个人都可以阅读和理解您的代码。虽然没有人理解var obj=Test('string'),但代码的可读性会降低。但我知道,这是一些JS程序员的最终目标@Marcus,如前所述,
new
关键字并不是此模式的唯一优势。而且,我不是团队中唯一的程序员。假设每个人都会记住使用new
关键字,同时也用Python编写后端(对于类不使用new
)是不现实的。在类声明的末尾发现缺少的new
要比在每个实例创建时容易得多。啊,我现在明白了:没有编译器告诉程序员他忘记了“new”,所以这就是为什么你不想使用它。据我所知,这在IE中是个问题?!这第一个(
在var Test=(function TestModule(){
)这一行中是什么意思?我真的不理解那种代码…@Marcus:这是一种生活。看看这里,这就像使用“Goto”:Goto“Test”,然后创建一个名为“Test”的类并实例化该类。这证明Javascript函数本身不是类,只有在调用“new”时它变成了一个类!问题:我在IE中没有得到相同的结果!结果是:a.constructor==b.constructor//false
和a.constructor.name==b.constructor.name//true
在IE中。但函数本身仍然工作正常。%D