Javascript Closures

    Javascript 闭包
Every function is an object
在JavaScript中每个函数都是对象。
(说了等于没说)怎么理解这句话?
敲在编辑器中的代码只是代码,被js引擎导入以后的代码中
的每个函数定义就成为了对象。
或者说就被js engine表示成了对象,更进一步说是
Function的实例。
这些函数对象和其他对象一样也包含了你能访问的属性,比
如name, length, prototype。也包括了你不能通过代码访
问的内部属性。其中一个属性就是[[Scope]],在ECMA-262,
Third Edition中定义。
创建函数对象时生成作用域链
function add(num1, num2) {
  var sum = num1 + num2;
  return sum;
}
When the function is created, its scope chain is populated
with global object     这个集合就被称为函
                                           这个集合由变量对象
   [[Scope]]属性指向一                         variable object组
                       数的作用域链
   个集合                                    成。




                    作用域链就决定了函数可以
  js engine读到函数定义,创
                    访问到的数据。
  建函数对象,生成作用域
                                         这个全局变量对象由一些键值
  链。
                                         对组成key-value pairs
执行函数时

var total = add(5, 10);
执行add函数时,js engine就会为该函数创建一个内部对
象--执行上下文execution context。同一个函数每次执行
时都会创建一个EC,这个EC定义了函数在这次执行时的环
境,所以称它为执行上下文。当函数执行完以后,该EC就会
被销毁,它所占内存就被释放。
激活对象Activation object

执行上下文execution context 简称EC
EC有自己的scope chain,该SC的作用是什么呢?
用来identifier resolution,也就是找到变量名,函数名所指的
对象。那EC的SC怎么创建,初始化些什么内容呢?
函数创建时生成的SC就派上用场了。函数SC中的变量对象中
的键值对就被拷贝进EC的SC中的变量对象中。
这个激活对象为这次函数执行准备了所有的局部变量,命名
参数,arguments对象和this对象。这个激活对象被放置在
SC的第一个位置,因此最先被找到。当EC销毁时,这个激活
对象也被销毁。(这句话不够准确,应该是当这个激活对象
没有引用时,才会被销毁。这在讲到闭包时会再次提到。)
理解闭包:内嵌函数nested function

var scope = "global";               // 全局变量scope
function checkscope() {
  var scope = "local";               // 局部变量scope
  function f() { return scope; }    // 返回变量scope的值
  return f;                        // 返回内嵌函数
}
var f = checkscope();              // 变量 f 指向内嵌函数实
例
f();
var f = checkscope();
函数checkscope执行,返回内嵌函数,该内嵌函数也是一个
对象(记得吗?everything is object),更具体的说是一
个函数实例对象。这个对象也有Scope属性,指向scope
chain,而且这个SC的variable object就是checkscope函数
的变量对象,js的设计很神奇!这样做很有趣,但带来了副
作用。
执行内嵌函数
f = checkscope(); f();
当执行这个内嵌函数时,同样EC会被创建,激活对象会被创建,并被置于SC的最
前位置。内嵌函数访问scope,根据ID解析规则,第2个变量对象中的scope变量
被找到,所以返回"local"。因为scope chain的缘故,函数外部的代码不能访问
函数内部的局部变量,这些变量就好像被函数“关闭”了。但内嵌函数可以访问
它的外部函数的局部变量,称这种内嵌函数为“闭包” closures。
var uniqueInteger = (function() {        // Define and invoke
                var counter = 0; // Private state of function below
                return function() { return counter++; };
             }());
uniqueInteger(); // ==> 0
uniqueInteger(); // ==> 1
function counter() {
   var n = 0;
   return {
      count: function() { return n++; },
      reset: function() { n = 0; }
   };
}
var c = counter(), d = counter(); // Create two counters
c.count()                    // => 0
d.count()                    // => 0: they count independently
c.reset()                   // reset() and count() methods share state
c.count()                    // => 0: because we reset c
d.count()                    // => 1: d was not reset
function addPrivateProperty(o, name, predicate) {
  var value; // This is the property value
  // The getter method simply returns the value.
  o["get" + name] = function() { return value; };
  // The setter method stores the value or throws an exception if
  // the predicate rejects the value.
  o["set" + name] = function(v) {
      if (predicate && !predicate(v))
          throw Error("set" + name + ": invalid value " + v);
      else
          value = v;
  };
}
var o = {}; // Here is an empty object
addPrivateProperty(o, "Name", function(x) { return typeof x == "string"; });
o.setName("Frank");          // Set the property value
console.log(o.getName()); // Get the property value
o.setName(0);               // Try to set a value of the wrong type
function constfunc(v) { return function() { return v; }; }
var funcs = [];
for(var i = 0; i < 10; i++) funcs[i] = constfunc(i);
funcs[5]()   // => 5
function constfuncs() {
  var funcs = [];
  for(var i = 0; i < 10; i++)
     funcs[i] = function() { return i; };
  return funcs;
}
var funcs =
constfuncs();
funcs[5]();
Another thing to remember when writing closures is that this is a JavaScript
keyword,not a variable. As discussed earlier, every function invocation has a
this value, and a closure cannot access the this value of its outer function
unless the outer function has saved that value into a variable:
var self = this; // Save this value in a variable for use by nested funcs.
The arguments binding is similar. This is not a language keyword, but it is
automatically declared for every function invocation. Since a closure has
its own binding for arguments, it cannot access the outer function’s
arguments array unless the outer func-tion has saved that array into a variable
by a different name:
var outerArguments = arguments; // Save for use by nested functions

Java script closures

  • 1.
    Javascript Closures Javascript 闭包
  • 2.
    Every function isan object 在JavaScript中每个函数都是对象。 (说了等于没说)怎么理解这句话? 敲在编辑器中的代码只是代码,被js引擎导入以后的代码中 的每个函数定义就成为了对象。 或者说就被js engine表示成了对象,更进一步说是 Function的实例。 这些函数对象和其他对象一样也包含了你能访问的属性,比 如name, length, prototype。也包括了你不能通过代码访 问的内部属性。其中一个属性就是[[Scope]],在ECMA-262, Third Edition中定义。
  • 3.
    创建函数对象时生成作用域链 function add(num1, num2){ var sum = num1 + num2; return sum; } When the function is created, its scope chain is populated with global object 这个集合就被称为函 这个集合由变量对象 [[Scope]]属性指向一 variable object组 数的作用域链 个集合 成。 作用域链就决定了函数可以 js engine读到函数定义,创 访问到的数据。 建函数对象,生成作用域 这个全局变量对象由一些键值 链。 对组成key-value pairs
  • 4.
    执行函数时 var total =add(5, 10); 执行add函数时,js engine就会为该函数创建一个内部对 象--执行上下文execution context。同一个函数每次执行 时都会创建一个EC,这个EC定义了函数在这次执行时的环 境,所以称它为执行上下文。当函数执行完以后,该EC就会 被销毁,它所占内存就被释放。
  • 5.
    激活对象Activation object 执行上下文execution context简称EC EC有自己的scope chain,该SC的作用是什么呢? 用来identifier resolution,也就是找到变量名,函数名所指的 对象。那EC的SC怎么创建,初始化些什么内容呢? 函数创建时生成的SC就派上用场了。函数SC中的变量对象中 的键值对就被拷贝进EC的SC中的变量对象中。 这个激活对象为这次函数执行准备了所有的局部变量,命名 参数,arguments对象和this对象。这个激活对象被放置在 SC的第一个位置,因此最先被找到。当EC销毁时,这个激活 对象也被销毁。(这句话不够准确,应该是当这个激活对象 没有引用时,才会被销毁。这在讲到闭包时会再次提到。)
  • 6.
    理解闭包:内嵌函数nested function var scope= "global"; // 全局变量scope function checkscope() { var scope = "local"; // 局部变量scope function f() { return scope; } // 返回变量scope的值 return f; // 返回内嵌函数 } var f = checkscope(); // 变量 f 指向内嵌函数实 例 f();
  • 7.
    var f =checkscope(); 函数checkscope执行,返回内嵌函数,该内嵌函数也是一个 对象(记得吗?everything is object),更具体的说是一 个函数实例对象。这个对象也有Scope属性,指向scope chain,而且这个SC的variable object就是checkscope函数 的变量对象,js的设计很神奇!这样做很有趣,但带来了副 作用。
  • 8.
    执行内嵌函数 f = checkscope();f(); 当执行这个内嵌函数时,同样EC会被创建,激活对象会被创建,并被置于SC的最 前位置。内嵌函数访问scope,根据ID解析规则,第2个变量对象中的scope变量 被找到,所以返回"local"。因为scope chain的缘故,函数外部的代码不能访问 函数内部的局部变量,这些变量就好像被函数“关闭”了。但内嵌函数可以访问 它的外部函数的局部变量,称这种内嵌函数为“闭包” closures。
  • 9.
    var uniqueInteger =(function() { // Define and invoke var counter = 0; // Private state of function below return function() { return counter++; }; }()); uniqueInteger(); // ==> 0 uniqueInteger(); // ==> 1
  • 10.
    function counter() { var n = 0; return { count: function() { return n++; }, reset: function() { n = 0; } }; } var c = counter(), d = counter(); // Create two counters c.count() // => 0 d.count() // => 0: they count independently c.reset() // reset() and count() methods share state c.count() // => 0: because we reset c d.count() // => 1: d was not reset
  • 11.
    function addPrivateProperty(o, name,predicate) { var value; // This is the property value // The getter method simply returns the value. o["get" + name] = function() { return value; }; // The setter method stores the value or throws an exception if // the predicate rejects the value. o["set" + name] = function(v) { if (predicate && !predicate(v)) throw Error("set" + name + ": invalid value " + v); else value = v; }; } var o = {}; // Here is an empty object addPrivateProperty(o, "Name", function(x) { return typeof x == "string"; }); o.setName("Frank"); // Set the property value console.log(o.getName()); // Get the property value o.setName(0); // Try to set a value of the wrong type
  • 12.
    function constfunc(v) {return function() { return v; }; } var funcs = []; for(var i = 0; i < 10; i++) funcs[i] = constfunc(i); funcs[5]() // => 5
  • 13.
    function constfuncs() { var funcs = []; for(var i = 0; i < 10; i++) funcs[i] = function() { return i; }; return funcs; } var funcs = constfuncs(); funcs[5]();
  • 14.
    Another thing toremember when writing closures is that this is a JavaScript keyword,not a variable. As discussed earlier, every function invocation has a this value, and a closure cannot access the this value of its outer function unless the outer function has saved that value into a variable: var self = this; // Save this value in a variable for use by nested funcs. The arguments binding is similar. This is not a language keyword, but it is automatically declared for every function invocation. Since a closure has its own binding for arguments, it cannot access the outer function’s arguments array unless the outer func-tion has saved that array into a variable by a different name: var outerArguments = arguments; // Save for use by nested functions