js闭包和作用域

闭包就是有权访问另一个函数作用域中的变量的函数,这个函数就叫做闭包。
在了解什么是js的闭包时,我们需要引入另外几个概念:作用域链,垃圾(内存)回收机制,函数嵌套,等等.。

作用域链:就是函数在定义的时候创建的,而不是在执行的时候确定。用于寻找使用到的变量的值的一个索引,而他内部的规则是,把函数自身的本地变量放在最前面,把自身的父级函数中的变量放在其次,把再高一级函数中的变量放在更后面,以此类推直至全局对象为止.当函数中需要查询一个变量的值的时候,js解释器会去作用域链去查找,从最前面的本地变量中先找,如果没有找到对应的变量,则到下一级的链上找,一旦找到了变量,则不再继续.如果找到最后也没找到需要的变量,则解释器返回undefined.

Javascript的垃圾回收机制
在Javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收。如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。
function a() {
var i = 0;
function b() { alert(++i); }
return b;
}
var c = a();
c();
因为函数a被b引用,b又被a外的c引用,这就是为什么函数a执行后不会被回收的原因。
所以js解释器在遇到函数定义的时候,会自动把函数和他可能使用的变量(包括本地变量和父级和祖先级函数的变量(自由变量))一起保存起来.也就是构建一个闭包,这些变量将不会被内存回收器所回收,只有当内部的函数不可能被调用以后(例如被删除了,或者没有了指针),才会销毁这个闭包,而没有任何一个闭包引用的变量才会被下一次内存回收启动时所回收.

Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。

Js代码

var world=”Hello World”;
function f1(){
   alert(world); 
  }
f1();//Hello World
但是在函数外部自然无法读取函数内的局部变量。
Js代码
function f1(){
    var world=”Hello World”;
  }
  alert(world); // error
这里有一个地方需要注意,函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!

在上面函数f1中的局部变量在外部是访问不到的。这是因为函数在定义的时候创建的作用域仅仅存在于f1的内部。我们想在函数的外部还能访问到函数内部的局部变量,这时候就需要在函数的内部再定义一个函数。

 function f1(){
    var word = “Hello World”;
    function f2(){
      alert(word);  //Hello World   
  }
  }
 在上面的代码中,函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可以访问得到的。
子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。

既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,我们不就可以在f1外部读取它的内部变量了吗!
var world = “nihao”;
 function f1(){
    var word = “Hello World”;
    function f2(){
      alert(word);     
  }
  return f2;
  }
  var result = f1();
  result();//Hello World
 我们可以理解为闭包其实就是定义在一个函数内部的函数,即可以访问其他函数内部变量的函数。闭包就是将函数内部和函数外部连接起来的一座桥梁。如上个例子中的f2函数就是一个闭包。
 我们知道,js的每个函数都是一个个小黑屋,它可以获取外界信息,但是外界却无法直接看到里面的内容。将变量 word 放进小黑屋里,除了 f2 函数之外,没有其他办法能接触到变量 word,而且在函数 f1 外定义同名的变量 word 也是互不影响的,这就是所谓的增强“封装性”。
而之所以要用 return 返回函数标识f2,是因为在 f1 函数外部无法直接调用 f2 函数,所以 return f2 与外部联系起来。

所谓“闭包”,就是在构造函数体内定义另外的函数作为目标对象的方法函数,而这个对象的方法函数反过来引用外层函数体中的临时变量。这使得只要目标 对象在生存期内始终能保持其方法,就能间接保持原构造函数体当时用到的临时变量值。

使用闭包的注意点
1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

闭包的应用场景
1、保护函数内的变量安全。以最开始的例子为例,函数a中i只有函数b才能访问,而无法通过其他途径访问到,因此保护了i的安全性。
2、在内存中维持一个变量。(因为产生闭包,内存不会轻易被收回)
3、通过保护变量的安全实现JS私有属性和私有方法(不能被外部访问)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值