【JavaScript】关于闭包

为什么80%的码农都做不了架构师?>>>   hot3.png

1、闭包是函数的代码在运行过程中的一个动态环境,是一个运行期的、动态的概念。
       闭包(又称“词法闭包”或“函数闭包”)是一个包含了非本地变量引用环境的函数。
2、变量在语法分析阶段被初始化为undefined。
//   标识符   ( 变量   ) 在定义后值为 undefined
function myFunc() {
      alert(i);
      var i = 100;
}
// 输出值总是undefined
myFunc();
myFunc();
//name在函数闭包内被声明, 不会访问到全局变量  name
var name = 'test';
function myFunc() {
      // 输出undefined
      alert(name);
      var name = 100;
      // 输出100 
      alert(name);
}
3、以下函数返回( return 子句)并不导致引用:
function myFunc() {
      function foo() {
      //...
      }
      return foo;
}
// 函数  foo() 在返回后立即被执行了,然后就会释放
foo()();
4、引用:
对象属性的引用:
      1)对象在构造时,使用   this   引用进入构造器函数
      2)对象在调用方法时,使用   this   引用进入函数
      3)某个函数使用   call/apply   方法调用,并传入某个对象作为   this   引用
      4)调用一个函数时,对象从参数入口传入
被变量引用:
     var  func = myFunc(); // <-- 在这里产生一个引用
5、函数闭包间的关联性:
var checker;
function myFunc() 
{
     if (checker) {
            checker();
      }
      alert('do myFunc: ' + str);
      var str = 'test.';
      if (!checker) {
           checker = function() {
           alert('do Check:' + str);
           }
      }
      return arguments.callee;
}
  myFunc()();
// do myFunc:  undefined  第一次调用
//do Check:test.  第二次调用
// do myFunc:  undefined 第二次调用
6、
范例1:
var obj = new Object();
var events = { m1: "clicked", m2: "changed" };
for (e in events) {
      obj[e] = function(){
      alert(events[e]);
      };
}
// 显示false, 表明是不同的函数实例
alert( obj.m1 === obj.m2 );
// 方法m1()与m2()都输出相同值
// 其原因,在于两个方法都访问全局闭包中的同一个upvalue 值e
obj.m1();
obj.m2();
范例2:
// 范例 2.1  在函数内保存数据
var obj = new Object();
var events = { m1: "clicked", m2: "changed" };
for (e in events) {
      obj[e] = function( aValue) { // 闭包 lv1
           return function() { // 闭包lv2
                alert(events[ aValue]);
           }
      }(e);
}
// 下面将输出不同的值
obj.m1();

obj.m2();

// 范例 2.2  在闭包内通过局部变量保存数据
for (e in events) {
      function() { // 闭包lv1
           var aValue = e;
           obj[e] = function() { // 闭包lv2
                alert(events[ aValue]);
           }
      }();

}

// 范例 2.3  将值 e   交给函数实例保存
for (e in events) {
      (obj[e] = function() {
           // arguments.callee 指向匿名函数自身
           alert(events[arguments.callee .aValue]);
      }
      ) .aValue = e;

}

// 范例 2.4  Function构造器
var obj = new Object();
var events = {m1: "clicked", m2: "changed"};
for (e in events) {
           obj[e] = new Function('alert( events["' + e + '"])');// 变量e被转换为字符串值来使
}

7、优先级:argsName(形式参数名) > arguments > funcName(函数名),其中arguments 是语言内定的标识符,无需声明即可使用。  
// 示例1:输出值'hi', 而非函数foo.toString()
function foo(foo) {
      alert(foo);
}
foo('hi');
// 示例2:输出数值100 的类型'number', 而非参数对象arguments 的类型'object'
function foo2(arguments) {
      alert(typeof arguments);
}
foo2(100);
// 示例3:输出参数对象arguments 的类型'object'
// (注:在JScript 中, arguments 作为函数名可以被声明, 但调用该函数导致脚本引擎崩溃)
function arguments () {
      alert(typeof arguments);
}
arguments ();
8、局部变量 (varDecls)与函数形式参数:
     A. 当形式参数名与未赋值的局部变量名重复时   ,   取形式参数值;
     B. 当形式参数与有值的局部变量名重复时,取局部变量值。
第一种情况:
function myFunc(str){
     var str;
     alert(str);
}
myFunc("not undefined");   //not undefined
第二种情况:
function myFun(str){
     var str = "hello world";
     alert(str);
}
myFun("not undefined");  //hello world
9、使用Function()构造器创建的函数与函数直接量声明、匿名函数不同,它在任意位置创建的实例,都处于全局闭包中。亦即是说, Function()的实例的upvalue 总是指向全局闭包。
var value = "hello world";
function myFunc(arg){
     var value = "welcome to here";
     var foo = new Function('alert(value)');
     foo();
}
myFunc();  //   "hello world"
 10、对象闭包:
var aObj = { value: 'hello' };
function foo() {
     with (aObj) {  // < --对象闭包
           var value = 1000;
            alert(aObj.value); // 显示值: 1000
       }
       alert(value);
}
foo();    // 显示'undefined'
11、函数闭包与对象闭包既有相关性,也有各自的独立性。对象闭包总是动态地添加在闭包链的顶端,而函数闭包则依赖于函数声明时的、静态的语法作用域限制。 
/**
* 两种闭包的交叉作用  
*/
var obj = { value: 200 };
var value = 1000;
with (obj) { // <-- 对象闭包
      function foo() { // <-- 具名函数foo()的闭包
      value *= 2; // <-- 依赖于函数静态位置所决定的闭包链
      }
      foo();     // with  的限定只对这一行有效
}
alert(obj.value);// 显示 200
alert(value);   // 显示 2000
12、匿名函数的闭包如同对象闭包一样,动态地添加到当前闭包链的顶端。
var obj = { value: 200 };
var value = 1000;
with (obj) { // <-- 对象闭包
    obj. foo =   function ()  {   // <-- 匿名函数的闭包
      value *= 2;   //   <-- 依赖于函数闭包所在的当前闭包链:with所打开的obj对象闭包
      }
    obj. foo();  
}
/**
* 即使该匿名函数没 有添加为对象  obj  的方法
*而仅是即用即声明,那么它所操作的仍然是对象 闭包中的  value 
*/
with (obj) { // <-- 对象闭包
      void  function ()  {   // <-- 匿名函数的闭包
      value *= 2;   //  <-- 依赖于函数闭包所在的当前闭包链:with所打开的obj对象闭包
      }();
}
// 显示 400
alert(obj.value);
// 显示 1000
alert(value);
13、eval:
     解决eval作用域的方法:with ( objContext )eval (strScript) 。
     如:with ( window )eval (strScript) ; //eval在 全局作用域中执行

转载于:https://my.oschina.net/aram/blog/114285

你可能感兴趣的:(【JavaScript】关于闭包)