首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >不用于构造函数调用的“构造函数”函数

不用于构造函数调用的“构造函数”函数
EN

Stack Overflow用户
提问于 2015-11-04 09:39:45
回答 1查看 80关注 0票数 4

(这个github回购中的完整代码)

你不了解JS系列书(特别是“这个&对象原型”标题)以及许多这样的答案(例如这一个)中,人们常常指出,没有“构造函数”这样的东西,而是用“构造函数调用”调用的普通函数。我试图通过创建一些普通的函数来探索这一点,这些函数不打算在new中调用来创建对象。

第一次尝试有效:

代码语言:javascript
复制
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函数,而只是将它们分配给一个原型(以下是我失败的例子):

代码语言:javascript
复制
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变量不再是作用域了:

代码语言:javascript
复制
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?

EN

回答 1

Stack Overflow用户

发布于 2015-11-05 23:45:05

1)每一次都会重新定义原型的get和inc。原型不是“封闭”的,原型继承的上链行为使得这成为可能。

代码语言:javascript
复制
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键不是未定义的,并且指向不同的函数实例。记住,如果传入名称,计数变量仍将得到分配和唯一绑定,并且知道每次您可以猜出下面的输出是什么时,原型都会被重新定义。

代码语言:javascript
复制
a.inc();a.inc();
[a.get(), b.get(), c.get()]

是:

0,0,2

2)是和否。您可以轻松地返回具有函数的对象,这些函数不是每次都分配的,但是如果绑定了一个变量,则这些对象将在它们之间共享。奇怪的是,通过使用原型继承和new操作符,可以很容易地做到这一点。

例如,下面的代码并不是每次都分配一个新函数,但是如果被调用,a.inc()将增加b和其他函数的值。

代码语言:javascript
复制
var count = 0;

function inc() {++count;}
function get() {return count;}

function Count() {
    return {inc: inc, get: get};
};

var a = Count();
var b = Count();

通过使用new运算符,可以实现一个唯一绑定的“变量”,而无需每次分配一个新函数。

代码语言:javascript
复制
    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
>>true
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33518341

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档