我们说我有以下内容:
var foo = (function(){
var bar = 0;
return {
getBar: function(){
return bar;
},
addOne: function(){
bar++;
},
addRandom: function(rand){
bar += rand;
}
}
})();
我有以下内容:
var foo2 = function(){
var bar = 0;
this.getBar = function(){
return bar;
};
this.addOne = function(){
bar++;
};
this.addRandom = function(rand){
bar += rand;
}
};
执行new
函数的唯一区别是什么?
alert(foo.getBar()); //0
foo.addOne();
foo.addRandom(32);
alert(foo.getBar()); //33
var foo2_obj = new foo2;
alert(foo2_obj.getBar());//0
foo2_obj.addOne();
foo2_obj.addRandom(32);
alert(foo2_obj.getBar());//33
他们两个都完全相同。
那么从长远来看有什么不同?
另一个人不能做什么呢?
以上的小提琴演示:http://jsfiddle.net/maniator/YtBpe/
答案 0 :(得分:14)
在第一个中你只能创建一次对象,而第二个你可以创建任意数量的对象。 I.E.第一个实际上是一个单身人士。
请注意,第二个闭包不适用。每次实例化它都会重新创建函数并浪费大量内存。原型对象旨在解决这个问题,您可以在函数范围之外创建函数,并且不会创建意外的闭包。
function foo2(){
this._bar = 0;
}
foo2.prototype = {
constructor: foo2,
getBar: function(){
return this._bar;
},
addOne: function(){
this._bar++;
},
addRandom:function(rand){
this._bar += rand;
}
};
然后:
var a = new foo2, b = new foo2, c = new foo2;
创建三个具有自己的_bar
但共享相同功能的实例。
你可以将所有这些与“PHP”进行“比较”,有些代码甚至不会运行,但原则上它是“等效的”:
var foo = (function(){
var bar = 0;
return {
getBar: function(){
return bar;
},
addOne: function(){
bar++;
},
addRandom: function(rand){
bar += rand;
}
}
})();
与PHP大致“等同”:
$foo = new stdClass;
$foo->bar = 0;
$foo->getBar = function(){
return $this->bar;
};
$foo->addOne = function(){
$this->bar++;
}
$foo->addRandom = function($rand){
$this->bar += $rand;
}
var foo2 = function(){
var bar = 0;
this.getBar = function(){
return bar;
};
this.addOne = function(){
bar++;
};
this.addRandom = function(rand){
bar += rand;
}
};
在PHP中大致“等同于”:
Class foo2 {
public function __construct(){
$bar = 0;
$this->getBar = function(){
return $bar;
};
$this->addOne = function(){
$bar++;
};
$this->addRandom = function($rand){
$bar += rand;
};
}
}
function foo2(){
this._bar = 0;
}
foo2.prototype = {
constructor: foo2,
getBar: function(){
return this._bar;
},
addOne: function(){
this._bar++;
},
addRandom:function(rand){
this._bar += rand;
}
};
在PHP中大致“等同于”:
Class foo2 {
public $_bar;
public function __construct(){
$this->_bar = 0;
}
public function getBar(){
return $this->_bar;
}
public function addOne(){
$this->_bar++
}
public function addRandom($rand){
$this->_bar += $rand;
}
}
...并且是上面三个例子中唯一接近OOP的那个
答案 1 :(得分:4)
唯一的区别是foo
将是通用Object
,而foo2_obj
在检查其类型时会识别为foo2
(即foo2_obj.constructor == foo2
将是true
,而foo
上的等价物是foo.constructor == Object
)。
当然,foo
和foo2
之间存在重要区别 - foo
是一个对象,而foo2
是一个函数(用作构造函数)。因此,制作尽可能多的foo2
(其中foo2_obj
为1)的实例是微不足道的,而创建foo
的“实例”的想法并不真正有意义 - 你能做的最好的就是副本(这比调用构造函数更难)。
由于复制/创建实例的区别,第二种方法允许使用原型链进行真正的OO编程,而第一种方法使得这些事情很多更难(并且是不明智的)。
答案 2 :(得分:1)
[1]首先,但不重要:效率
function Foo1() {
var bar = 0;
return {
getBar: function () {
return bar;
}
}
}
var o = Foo1();
o.getBar();
function Foo2() {
var bar = 0;
this.getBar = function () {
return bar;
}
}
var o = new Foo2();
o.getBar();
哪个更快?,看object-literal-vs-new-operate
[2]程序模式:前者没有程序模式,但后者将受益于prototypal inheritance形式。如果现在我们要添加一个名为“logBar”的方法,
前者:
1:扩展每个 Foo1实例:
o.logBar = function () {
console.log(this.getBar());
}
o.logBar();
糟糕的方式!
2:找到Foo1定义的位置并添加:
function Foo1() {
var bar = 0;
return {
getBar: function () {
return bar;
},
logBar:function () {
console.log(this.getBar());
}
}
}
var o = Foo1();
o.logBar = o.logBar();
如果你想增加更多的方法时间,你想回去做吗?
后者:
Foo2.prototype.logBar = function () {
console.log(this.getBar());
}
var o = Foo2();
o.logBar = o.logBar();
这样可以正常工作。
[3]回到效率:
在Foo1的方式中,它产生logBar
函数实例在创建Foo1实例时的时间。object-literal-vs-new-operate
答案 3 :(得分:0)
foo
和foo2_obj
他们是一样的。在这两种情况下,您都有一个创建新对象的函数,在闭包范围内引用变量并返回该对象。
你有4件事
如果您不触及new
<Function>.prototype
和从函数返回函数文字之间的确切差异是可以忽略的
您可能想比较
var foo2 = function(){
var bar = 0;
this.getBar = function(){
return bar;
};
this.addOne = function(){
bar++;
};
this.addRandom = function(rand){
bar += rand;
};
};
要
var Foo = {
addOne: function () { this.bar++; },
addRandom: function (x) { this.bar+=x; }
};
var foo3 = function () {
return Object.create(Foo, { bar: { value: 0 } });
}
foo3使用原型OO。这意味着您不必一直重新创建这些功能。
答案 4 :(得分:0)
我认为在我个人看来这两种类型中 1-单身人士 2-对象
让我们说我们有一个页面让他们的javascript使用Object(Second),和 有许多使用单例的工具(第一),并且工作正常。
但是有一天我们需要一个通过AJAX调用第一页的新页面,这个新页面使用Object(Second)使用javascript并使用singleton具有相同的util,但是我们在utils单例中添加了一些新函数。 / p>
事实证明,新页面中的utils单例重写了第一页中加载的utils单例,所以当新页面执行时,其中一些新函数不存在,生成错误......
我认为这是我的观点,当你有这个场景时,单身人士会被覆盖,并且在这样的情况下发现错误很难......很难...,与具有唯一实例的对象不同
干杯。
答案 5 :(得分:0)
简单来说,如果您要创建10个foo
和foo2
的实例,则getBar
的{{1}}函数将在内存中存在10次,而{{1}的函数将存在10次只会一次。
此外,现代浏览器如Chrome和V8编译器,它将js编译为机器代码......在这种情况下,foo
将被转换为本机类对象,它的速度提高了20倍(当你创建时)说一个循环中的1000个实例)
当只需要一个类/模块的实例时,我通常使用简单对象方法。我遵循的结构是,
foo2
这与foo2
方法非常相似,但我觉得这个结构更方便。
我通常遇到的另一个不同之处(实际使用中)是我在课堂上有var myInstance = function(){
var self = {};
self.bar = null;
self.gerBar = function(){
return self.bar
}
return self;
}();
个函数或foo
时,
callback
正如你可以看到当你有很多这些情况时,本地临时变量并不漂亮。
在另一种方法中,您始终是模块范围内的timeouts
引用,
var foo2 = function(){
this.doSomething = function(){
var temp = this;
$.someAsyncCall(function(){
// 'this' in current scope is the inline function itself, not the class instance
// so have to store the instance ref in a local var in outer scope and then use that to get the class instance
temp.callAfterAsyncCall();
});
};
this.callAfterAsyncCall = function(){
};
};
我不确定它对你来说是否重要,但只是值得一提。
答案 6 :(得分:0)
主要区别在于foo
是一个对象,而foo2
是一个函数。
这意味着您将无法创建另一个实际上不是foo
的{{1}}对象,除非您复制/粘贴其代码。 / p>
另一方面,您可以创建另一个foo
对象并在将foo2
用于其他目的时对其进行操作。
简而言之,foo2_obj
是一个实例,而foo
可以被视为一个类(即使它只是一个构建一个函数的函数)对象)。
这取决于你想在程序中做什么,但我肯定建议使用第二种形式,它允许通过创建其他实例来重用你的代码。