这个getter-setter Closure是否有充分的理由以这种方式声明它的内部对象的私有性?

时间:2015-01-30 05:06:45

标签: javascript closures encapsulation

我跟着这个:

Javascript constructor patterns - 滚动到“使用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

var my = {};似乎在Chrome控制台中测试时有效。此代码旨在支持封装。在此更改之后进行测试并未发现任何进入私有或破坏功能的新方法。但是我担心我会缺少一些需要它的魔法。

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

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

  

“通常,当函数完成执行时,声明变量   在该函数内超出范围并被销毁。但是有   例外:如果函数外的任何代码都包含引用   函数完成执行后的这些变量,它们不会   清理干净了。相反,将形成一个闭包,以及那些变量   将留在记忆中。“

     

“在上面的例子中,因为Person构造函数返回   内部对象我,因为我指的是局部变量   _firstName和_lastName(在getter / setter和fullName方法中),变量不会被销毁。当。。。的时候   调用getter / setter,它们在同一个本地操作   变量“。

1 个答案:

答案 0 :(得分:3)

有点讽刺的是,我在博客上看到“教学”封闭的大多数人实际上并不了解封闭本身。你是对的,但是代码中的冗余东西比那个对象要多得多。

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?

它是如何工作的?范围仍然存在。 firstName和lastName也是如此。您也不需要返回内部对象,绝对没有理由不构造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;
    }
}

编辑:但实际上很好地尝试和尝试新事物,并且更好地尝试一些事情并亲自了解它是如何以及为什么它的好坏,而不是盲目地倾听像我这样的建议。我希望我对博客的作者不过分或不公平批评。