gpt4 book ai didi

javascript - "constructor"不打算与构造函数调用一起使用的函数

转载 作者:搜寻专家 更新时间:2023-10-31 23:26:56 25 4
gpt4 key购买 nike

(完整代码在 this github repo 中)

You don't know JS系列丛书(特别是“this&Object Prototypes”标题)以及许多 SO 答案(例如 this one)中经常指出没有“构造函数”这样的东西,而是用“构造函数”调用的普通函数称呼”。我试图通过创建普通函数来理解这一点,这些函数不打算用 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 函数来改进上面的代码,而是简单地将它们分配给原型(prototype)(这是我失败的地方):

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 函数时,先前对象的原型(prototype) get 都设置为新创建的函数在词法上绑定(bind)到一个新的 count(再次初始化为 0)。 Plus 代码是愚蠢的,因为每次调用 Counter2 函数时都会再次创建函数并一遍又一遍地在原型(prototype)上重新分配(使用无法维护单独柜台的灾难性结果)。

然而,尝试将赋值给 Counter2 函数之外的原型(prototype)也失败了,因为 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) 有没有什么方法可以使用这个习惯用法(即使用不打算用 new 调用的“vanilla”函数)并且避免每次函数都重新创建 getters/setters叫什么?

最佳答案

1) 是的,原型(prototype)的 get 和 inc 每次都被重新定义。原型(prototype)没有被“关闭”,原型(prototype)继承的上链行为使这成为可能。

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 键不是未定义的,而是指向不同的函数实例。请记住,如果传入一个名称并且每次您可以猜测以下输出是什么时都会重新定义原型(prototype),那么计数变量仍然会被分配和唯一绑定(bind)。

a.inc();a.inc();
[a.get(), b.get(), c.get()]

是:

[0, 0, 2]

2) 是和否。您可以轻松地返回具有并非每次都分配的函数的对象,但如果绑定(bind)了一个变量,它将在它们之间共享。奇怪的是,通过使用原型(prototype)继承和 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 运算符,可以实现唯一绑定(bind)的“变量”,而无需每次都分配新函数。

    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

关于javascript - "constructor"不打算与构造函数调用一起使用的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33518341/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com