试图通过这个闭包示例...?

时间:2014-01-16 11:00:37

标签: javascript function closures

var o = Object.create({inherited: 1}, {
foo: {
  get: (function () { // a closure
      var closured = 'foo';
      return function () {
        return closured+'bar';
      };
    })()
  }
});

o.foo; // "foobar"

我遇到了一些问题。我真的不明白我们如何得到字符串"foobar"作为结果。我将写下我目前对此代码的错误理解,希望有人可以解释我错在哪里。

  1. o是具有属性foo
  2. 的对象
  3. foo对应于具有一个属性get的对象。 (这似乎是错的,但我看不出如何。)
  4. get对应于自动调用匿名函数,该函数返回由一行return closured+'bar';
  5. 组成的函数

    话虽这么说,我希望o.foo返回一个对象,o.foo.get返回一个函数,o.foo.get()返回"foobar"

    但这不是正在发生的事情,我不知道为什么。

    另外,另外,为什么你会这样写东西?为什么写:

    get: (function () { // a closure
          var closured = 'foo';
          return function () {
            return closured+'bar';
          };
        })()
    

    而不仅仅是:

    get: (function () { // a closure
          var closured = 'foo';
            return closured+'bar';
        })()
    

    额外功能层有什么好处?

6 个答案:

答案 0 :(得分:2)

Object.create的第二个参数应该是属性描述符对象。这是一个描述要添加到原型的属性的对象 - 而不是字面上的对象本身。例如:

var o = Object.create({inherited: 1}, {
   foo: { /* ... property descriptor object ... */ },
   bar: { /* ... property descriptor object ... */ }
});

在上面的示例中,我们将两个属性添加到新对象的原型中:foobar。可以使用描述符对象以各种方式配置这些属性中的每一个。

描述符对象接受几个配置属性,即:configurableenumerablevaluewritablegetset。< / p>

在原始示例中,您有效地为属性foo配置了一个getter函数。如果您只想设置属性foo的值,那么您必须在描述符中创建一个value属性并在那里添加您想要的值(实际上它是一个名为{{的属性的对象) 1}}如果你选择)。例如:

get

有关属性描述符对象的更多详细信息,请参阅:Object.defineProperty()

答案 1 :(得分:1)

foo对应于具有一个属性的对象,并且该属性是一个函数,如您所说,但Object.create的第二个参数用于定义属性。 o.foo是新对象o的一个此类属性。它定义了一个getter,因此它不是“value属性”而是“accessor属性”。尝试从o.foo读取会导致调用getter。

至于

get: (function () { // a closure
      var closured = 'foo';
      return function () {
        return closured+'bar';
      };
})()

它返回一个函数,而

get: (function () { // a closure
      var closured = 'foo';
        return closured+'bar';
})()

返回字符串'foobar',因此它们不等效,但第一个代码块等同于

get: function () { // a closure
      var closured = 'foo';
        return closured+'bar';
}

也会返回一个函数。在该示例中,该闭包是无用的,但您可以执行

foo: (function() {
    var closured = 'foo';
    return {
        'get': function () {
            return closured+'bar';
        },
        'set': function (value) {
            closured = value;
        }
    };
})()

这样,getter和setter都可以访问closured,但没有其他函数可以:

console.log(o.foo); // "foobar"
o.foo = "a";
console.log(o.foo); // "abar"

答案 2 :(得分:1)

关于代码,有几件事你不理解。

var o = Object.create({inherited: 1}, {
  foo: {
    get: function(){ return 1; }
  }
});

console.log(o.foo); // 1
o.foo = 5;
console.log(o.foo); // 1

Object.create的第二个参数描述了对象的属性。在这种情况下,get部分实际上是一个getter,因此它描述了在读取对象foo的{​​{1}}属性时会发生什么。


o

这种结构称为IIFE。它是一个立即调用的函数。 IIFE的优点是它创建了一个局部范围,因此(function () { var closure = 'foo'; return function () { return 'bar'; }; })() 变量在外部范围内不可见。这可以避免冲突。


closure

在第一种情况下,闭包变量在getter函数之外,而在第二种情况下,它在内部。外部意味着每次调用函数(getter)时都不会重置其状态,并且它也可以在其他函数中使用,它们将共享相同的变量。这是一个潜在的用例:

get: (function () { // a closure
  var closured = 'foo';
  return function () {
    return closured+'bar';
  };
})()
// versus:

get: function () { // changed it a bit to be a getter
  var closured = 'foo';
  return closured+'bar';
}

答案 3 :(得分:0)

您的问题的答案可以在this documentation page找到。如果您阅读有关属性的部分,您可以看到Object.create函数的第二个参数不是简单地合并到原型中,而是实际上是具有getter,setter和各种选项的属性的定义。

考虑到这一点,请查看以下代码:

get: (function () { // a closure
  var closured = 'foo';
  return function () {
    return closured+'bar';
  };
})()

正如你所说的,指定了一个自我调用的匿名函数来获取。此函数返回一个函数,该函数关闭闭包变量并返回闭合的+ bar值。这不等同于以下内容:

get: (function () { // a closure
  var closured = 'foo';
    return closured+'bar';
})()

原因是在这种情况下为get分配了一个实际值而不是一个函数,打破了Object.create期望的属性规范。

答案 4 :(得分:0)

使用get为名称为getter的媒体资源定义foo方法。因此,每次您对foo具有读访问权时,它都将执行getter方法。这就是为什么立即执行的函数本身返回一个函数(它是结果的getter)。

执行o.foo将导致对foo o属性的读访问权限,因此将执行getter。

答案 5 :(得分:-1)

闭包是在函数外部访问变量的能力。我想你已经知道了。

现在关于为什么要这样做的问题

get: (function () { // a closure
  var closured = 'foo';
  return function () {
    return closured+'bar';
  };
})()

你知道,当你这样做时,你不仅可以获得“封闭”变量,你可以修改它!(虽然你做了修改)同时'封闭'现在也不会被回收。所以它会存在于内存中,而不是在函数返回时清理。