我遵循这个:
Javascript 构造函数模式 - 滚动到 "Closures with getter-setters (D3.js, jQuery))"
我对my
的声明方式感到困惑:
function Person(firstName, lastName) {
var _firstName = firstName, // private
_lastName = lastName; // private
var my = {
firstName: _firstName, // <- why?
lastName: _lastName // <- why?
}; // var my = {};?
my.fullName = function() {
return _firstName + ' ' + _lastName; // a toString() wannabe
};
// Getter/setters
my.firstName = function(value) {
if (!arguments.length) return _firstName; // getter
_firstName = value; // setter
return my; // enable "method chaining" ...
};
my.lastName = function(value) {
if (!arguments.length) return _lastName; // getter
_lastName = value; // setter
return my; // ... so mark.firstName('Samuel').lastName('Clemens'); works
};
return my; // expose inner object but not the private instance variables
}
上面部分中的侧面评论是为了暴露我的想法而添加的。
//Use it like this:
var mark = Person('Mark', 'Twain'); // note: no `new` keyword!
mark.firstName('Samuel');
mark.lastName('Clemens');
mark.fullName(); // Samuel Clemens
在Chrome的控制台中对此进行测试时,var my = {};
似乎可以正常工作。 此代码旨在支持封装。此更改后的测试并未揭示任何进入私有或损坏功能的新方法。 但我担心我错过了一些需要这个的魔法。
请检查我的想法。 my.firstName 中的_firstName不是在被重新定义为 getter/setter 函数时被踩到的吗? 我是否通过切换到var my = {};
来暴露或破坏某些内容?
"这是如何工作的?"部分说:
"通常,当函数完成执行时,声明的变量 在该功能中,超出范围并被销毁。但是有 例外:如果函数外部的任何代码包含对 这些变量在函数完成执行后,它们不会 清理。相反,将形成一个闭包,并且这些变量 将留在记忆中。
"在上面的例子中,由于 Person 构造函数返回 内部对象 my,并且由于 my 引用局部变量 _firstName和_lastName(在getter/setters和fullName方法中),变量不会被销毁。当 getter/setter 被调用,它们在同一个本地运行 变量。
有点讽刺的是,我在博客上看到的大多数人"教授"闭包本身实际上并不理解闭包。你是对的,但是该代码中还有更多冗余的东西,而不仅仅是那个对象。
function Person(firstName, lastName) { // [arguments] also "private"
this.fullName = function() {
return firstName + ' ' + lastName;
};
this.firstName = function(value) { // difficult to inspect
if (!arguments.length) return firstName; // soon: How's this working?
firstName = value; // yes those are still there
// ...still there...
return this; // ......always there....
}; // ........forever........
// ...haunting your memories
this.lastName = function(value) { // .......never forget...
if (!arguments.length) return lastName; // ....closure remembers...
lastName = value; // ...dream within a dream..
// ....within a closure....
return this; // ...no one returns......
}; // ...daddy..............
} // where do dead memories go?
它是如何工作的?嗯,范围仍然存在。名字和姓氏也是如此。你也不需要返回一个内部对象,绝对没有理由不只构造一个 Person 的实例。
但这种模式也只有在你打算用它做一些真正花哨的东西时才有用。对于存储字符串或整数或沿该行的任何内容,效率低得可笑。没有人将少量数据存储在 3 个函数加上一个闭包加上对象每个实例的数据中 - 该对象的 1000 个实例是 1000 个闭包和 3000 个函数加上实际数据(在这个不公平的例子中,它当然只有 2 个字符串,这使得它更加荒谬)。
因此,除非你觉得值得,否则只需使用一个普通的老式无聊原型。我知道这很无聊,但如果你实际上同时运行这个无聊的版本,不仅占用的内存减少了 99%(你有 1 个对象只保存每个实例所需的数据,其余的都是共享的),它也更容易使用,因为一切都按照你的期望一直运行。
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
Person.prototype = {
get fullName () {
return this.firstName + ' ' + this.lastName;
}
}
编辑:但是尝试和尝试新事物当然是非常好的,最好尝试一些东西,亲眼看看它是如何以及为什么是好是坏,而不是盲目地听从像我这样的建议。我希望我没有对博客的作者过度或不公平地批评。