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

can*_*nge 2 javascript closures encapsulation

我正在关注这个:

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
}
Run Code Online (Sandbox Code Playgroud)

添加上面部分的旁注是为了暴露我的想法。

//Use it like this:

var mark = Person('Mark', 'Twain'); // note: no `new` keyword!

mark.firstName('Samuel');
mark.lastName('Clemens');

mark.fullName(); // Samuel Clemens
Run Code Online (Sandbox Code Playgroud)

var my = {};在 chrome 控制台中测试时似乎有效。该代码旨在支持封装。此更改后的测试并未发现任何进入私有空间或损坏功能的新方法。但我担心我缺少一些需要这样做的魔法。

请检查我的想法。当 my.firstName 中的 _firstName 被重新定义为 getter/setter 函数时,它不是被踩了吗?我切换到会暴露或破坏某些东西吗var my = {};

这是如何工作的?部分说:

“通常,当函数完成执行时,该函数内声明的变量会超出范围并被销毁。但有一个例外:如果函数外部的任何代码在函数完成执行后保存对这些变量的引用,则它们不会被清理。相反,将形成一个闭包,并且这些变量将保留在内存中。”

“在上面的示例中,由于 Person 构造函数返回内部对象 my,并且由于 my 引用局部变量 _firstName 和 _lastName(在 getter/setter 和 fullName 方法中),因此这些变量不会被销毁。 getter/setter 被调用,它们对相同的局部变量进行操作。”

Win*_*tro 5

有点讽刺的是,我在博客上看到的大多数“教授”闭包的人实际上并不理解闭包本身。你是对的,但是该代码中还有很多多余的东西,而不仅仅是那个对象。

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?
Run Code Online (Sandbox Code Playgroud)

它是如何工作的?好吧,范围仍然存在。名字和姓氏也是如此。您也不需要返回内部对象,绝对没有理由不只构造一个 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:但是尝试和尝试新事物当然是很好的,最好尝试一些东西并亲眼看看它是好是坏,而不是盲目地听从我的建议。我希望我没有对博客作者过度或不公平地批评。