Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/365.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 试图完成这个闭包示例。。。?_Javascript_Function_Closures - Fatal编程技术网

Javascript 试图完成这个闭包示例。。。?

Javascript 试图完成这个闭包示例。。。?,javascript,function,closures,Javascript,Function,Closures,我对此有些问题。我真的不明白我们如何得到字符串“foobar”。我将写下我目前对这段代码的错误理解,希望有人能解释我错在哪里 o是具有属性foo的对象 foo对应于具有一个属性的对象,get。(这似乎是错的,但我看不出是怎么回事。) get对应于自调用匿名函数,该函数返回由一行组成的函数returnclosured+'bar' 也就是说,我希望o.foo返回一个对象,o.foo.get返回一个函数,o.foo.get()返回“foobar” 但事实并非如此,我也不知道为什么 另外,你为什么要这样

我对此有些问题。我真的不明白我们如何得到字符串
“foobar”
。我将写下我目前对这段代码的错误理解,希望有人能解释我错在哪里

  • o
    是具有属性
    foo
    的对象
  • foo
    对应于具有一个属性的对象,
    get
    。(这似乎是错的,但我看不出是怎么回事。)
  • get
    对应于自调用匿名函数,该函数返回由一行组成的函数
    returnclosured+'bar'
  • 也就是说,我希望
    o.foo
    返回一个对象,
    o.foo.get
    返回一个函数,
    o.foo.get()
    返回
    “foobar”

    但事实并非如此,我也不知道为什么

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

    var o = Object.create({inherited: 1}, {
    foo: {
      get: (function () { // a closure
          var closured = 'foo';
          return function () {
            return closured+'bar';
          };
        })()
      }
    });
    
    o.foo; // "foobar"
    
    而不是简单地:

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

    额外功能层有什么好处?

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

    考虑到这一点,请查看中的代码:

    get: (function () { // a closure
          var closured = 'foo';
            return closured+'bar';
        })()
    
    正如您所说,为get分配了一个自调用匿名函数。此函数返回一个关闭closured变量并返回closured+bar值的函数。这并不等同于以下内容:

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

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

    使用
    get
    可以为名为
    foo
    的属性定义
    getter
    方法。因此,每次您拥有对
    foo
    的读取权限时,它都将执行getter方法。这就是为什么立即执行的函数本身返回一个函数(它是结果getter)


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

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

    至于

    get: (function () { // a closure
      var closured = 'foo';
        return closured+'bar';
    })()
    
    它返回一个函数,而

    get: (function () { // a closure
          var closured = 'foo';
          return function () {
            return closured+'bar';
          };
    })()
    
    返回字符串
    'foobar'
    ,因此它们不等效,但第一个代码块等效于

    get: (function () { // a closure
          var closured = 'foo';
            return closured+'bar';
    })()
    
    它也返回一个函数。在本例中,该闭包是无用的,但您可以这样做

    get: function () { // a closure
          var closured = 'foo';
            return closured+'bar';
    }
    
    这样,getter和setter都可以访问
    closured
    ,但其他函数不能:

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

    关于代码,有几件事你没有正确理解

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

    Object.create的第二个参数描述对象的属性。在本例中,
    get
    部分实际上是一个getter,因此它描述了读取对象
    o
    foo
    属性时发生的情况


    这个结构被称为IIFE。它是一个立即被调用的函数。IIFE的优点是它创建了一个局部范围,因此
    closure
    变量在外部范围中不可见。这避免了冲突


    在第一种情况下,closured变量位于getter函数外部,而在第二种情况下,closured变量位于内部。处于外部意味着它的状态不会在每次调用函数(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';
    }
    

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

    现在我们来谈谈为什么要这样做

    var namespace = Object.create(null, {
      uniqueId : {
        get : (function(){
          var counter = 0;
          return function() {
            return counter++;
          };
        })()
      }
    });
    
    console.log(namespace.uniqueId); // 0
    console.log(namespace.uniqueId); // 1
    

    你们看,当你们这样做的时候,你们不仅可以得到“closured”变量,你们还可以修改它!(虽然您修改了它)现在“关闭”也不会被回收。因此,它将驻留在内存中,而不是在函数返回时清除。

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

    get: (function () { // a closure
      var closured = 'foo';
      return function () {
        return closured+'bar';
      };
    })()
    
    var o = Object.create({inherited: 1}, {
       foo: { /* ... property descriptor object ... */ },
       bar: { /* ... property descriptor object ... */ }
    });
    
    在上面的示例中,我们向新对象的原型添加了两个属性:
    foo
    bar
    。可以使用描述符对象以各种方式配置这些属性中的每一个

    描述符对象接受几个配置属性,即:
    可配置
    可枚举
    可写
    获取
    设置

    在最初的示例中,您有效地为属性
    foo
    配置了一个getter函数。如果希望简单地设置属性
    foo
    的值,则必须在描述符内创建
    value
    属性,并在其中添加所需的值(如果选择,它实际上是一个具有名为
    get
    的属性的对象)。例如:

    get: (function () { // a closure
      var closured = 'foo';
      return function () {
        return closured+'bar';
      };
    })()
    
    var o = Object.create({inherited: 1}, {
       foo: { /* ... property descriptor object ... */ },
       bar: { /* ... property descriptor object ... */ }
    });
    
    有关属性描述符对象的详细信息,请参阅:

    var o = Object.create({inherited: 1}, {
       foo: {
         value: {get: (function () { /* ... code ... */ })() }
       }
    });