(这个github回购中的完整代码)
在你不了解JS系列书(特别是“这个&对象原型”标题)以及许多这样的答案(例如这一个)中,人们常常指出,没有“构造函数”这样的东西,而是用“构造函数调用”调用的普通函数。我试图通过创建一些普通的函数来探索这一点,这些函数不打算在new中调用来创建对象。
第一次尝试有效:
var assert = function(condition, message) {
if (!condition)
throw new Error(message||'assertion error');
};
var Counter1 = function() {
var count = 0;
return {get: function() {return count;},
inc: function() {count++;}};
};
var c2a = Counter1();
c2a.inc();
assert(c2a.get()===1);
var c2b = Counter1();
assert(c2b.get()===0);
assert(c2a.get()===1); // previous counter is a separate object现在,我试图改进上面的代码,不要每次都重新创建getter/setter函数,而只是将它们分配给一个原型(以下是我失败的例子):
var Counter2 = function Counter2_() {
var count = 0;
Counter2_.prototype.get = function() {return count;};
Counter2_.prototype.inc = function() {count++;};
assert(Counter2_.prototype.constructor === Counter2_);
var rv = {};
rv.__proto__ = Counter2_.prototype;
return rv;
};
var c = Counter2();
c.inc();
assert(c.get()===1);
assert(Object.getPrototypeOf(c)===Counter2.prototype);
var cb = Counter2();
assert(Object.getPrototypeOf(cb)===Counter2.prototype);
assert(cb.get()===0);
assert(c .get()===1, 'expecting c to be 1 but was:'+c.get());以上代码在最后一行失败。我的理解是,上面的代码没有成功地维护单独的计数器,因为每次调用Counter2函数时,以前对象的原型get都被设置为新创建的函数,该函数在词汇上绑定到一个新的count (再次初始化为0)。+代码是愚蠢的,因为每次在原型上一次又一次调用和重新分配Counter2函数时,都会再次创建函数(结果是无法维护单独的计数器)。
然而,试图将分配给Counter2函数之外的原型的尝试也失败了,因为count变量不再是作用域了:
var Counter3 = function Counter3_() {
var count = 0;
var rv = {};
rv.__proto__ = Counter3_.prototype;
return rv;
};
Counter3.prototype.get = function() {return count;}; // this fails - I no longer have access to count's lexical scope
Counter3.prototype.get = function() {return this.count;}; // this fails too我的问题是:
1)我对Counter2为什么不能维护单独计数器的理解是正确的吗?
( 2)是否有任何方法可以使用这个成语(即使用"vanilla“函数而不是用new调用),而避免每次调用函数时重新创建getter/setter?
发布于 2015-11-05 23:45:05
1)每一次都会重新定义原型的get和inc。原型不是“封闭”的,原型继承的上链行为使得这成为可能。
function Counter2(name) {
var count = 0;
Counter2.prototype.get = function() {return count;};
Counter2.prototype.inc = function() {count++;};
var rv = {};
if(name) {
rv.get = function() {console.log(name); return count;};
}
console.log(count)
rv.__proto__ = Counter2.prototype;
return rv;
}
var a = Counter2('a');
var b = Counter2('b');
var c = Counter2();在下面的示例中,a和b不继承get函数,因为它们的get键不是未定义的,并且指向不同的函数实例。记住,如果传入名称,计数变量仍将得到分配和唯一绑定,并且知道每次您可以猜出下面的输出是什么时,原型都会被重新定义。
a.inc();a.inc();
[a.get(), b.get(), c.get()]是:
0,0,2
2)是和否。您可以轻松地返回具有函数的对象,这些函数不是每次都分配的,但是如果绑定了一个变量,则这些对象将在它们之间共享。奇怪的是,通过使用原型继承和new操作符,可以很容易地做到这一点。
例如,下面的代码并不是每次都分配一个新函数,但是如果被调用,a.inc()将增加b和其他函数的值。
var count = 0;
function inc() {++count;}
function get() {return count;}
function Count() {
return {inc: inc, get: get};
};
var a = Count();
var b = Count();通过使用new运算符,可以实现一个唯一绑定的“变量”,而无需每次分配一个新函数。
function Count(){}
Count.prototype.count = 0;
Count.prototype.get = function() {return this.count;};
Count.prototype.inc = function() {this.count++;};
var a = new Count();
var b = new Count();
a.inc();
a.get();
>>1
b.get();
>>0
a.inc === b.inc
>>truehttps://stackoverflow.com/questions/33518341
复制相似问题