这个 getter-setter 闭包是否有充分的理由以这种方式在其内部对象中声明它是私有的

Does this getter-setter Closure have a good reason to declare it's privates in it's inner object this way?

本文关键字:内部对象 声明 方式 是否 闭包 getter-setter 这个 理由      更新时间:2023-09-26

我遵循这个:

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;
    }
}

编辑:但是尝试和尝试新事物当然是非常好的,最好尝试一些东西,亲眼看看它是如何以及为什么是好是坏,而不是盲目地听从像我这样的建议。我希望我没有对博客的作者过度或不公平地批评。