【学习】你不知道的JavaScript + 忍者秘籍 -- 作用域 +闭包 小结

相关知识点

  1. 编译语言,动态语言

  2. 编译原理:分词/词法分析(Tokenizing/Lexing),解析/语法分析(Parsing),代码生成。

  3. LHS 和 RHS:左查找和右查找
    LHS:找到变量的容器本身;RHS:找到变量的值

  4. 引擎:负责整个JavaScript程序的编译及执行过程
    编译器:负责语法分析及代码生成
    作用域:负责收集并维护由所有声明的标识符(变量)所组成的一系列的查询,并实施一套非常严格的规则,确定当前执行的代码对这些标识符的访问权限。

  5. 词法作用域 && 动态作用域:JavaScript都是词法作用域
    词法作用域:定义在词法阶段的作用域,词法作用域是在写代码时将比那辆和块作用域写在哪里来决定的,因此当词法分析器处理代码时会保持作用域不变(大部分情况下,例如with可改变作用域)。

  6. 无论函数在哪里被调用,也无论它如何被调用,它的词法作用域都只由函数被声明时所处的位置决定。

  7. eval()和with()会在运行时修改或创建新的作用域,影响JavaScript引擎在编译阶段对作用域查找进行优化。

  8. 块级作用域:从ES3开始,try/catch结构在catch分局中具有块级作用域;ES6之后引入了if-else for等使用{}包起来的块级作用域

  9. 闭包: 通过闭包可以访问创建闭包时所处环境中的全部变量。闭包为函数创建时所处的作用域中的函数和变量船舰“安全气泡”,通过这种方式,即使创建函数时所处的作用域已经消失,但是函数仍然能够获得执行时所需的全部内容。

  10. 在JavaScript中,我们可以定义全局级别,函数级别,块级别的变量。

  11. 可以使用关键字var,let,const定义变量:

  • var定义距离最近的函数级变量或者全局变量;
  • let和const定义距离最近级别(函数或者块)的变量
  • const定义只能赋值一次的变量。
  1. JavaScript代码的执行分成两个阶段进行:一旦创建了新的词法环境,就会执行第一阶段。在第一阶段,没有执行代码,但是JavaScript引擎会访问并注册在当前词法环境中所声明的变量和函数。JavaScript在第一阶段完成之后开始执行第二阶段,具体如何执行取决于变量的类型(let,var,const和函数声明)以及环境类型(全局环境,函数环境,块级作用域)
    具体过程如下:
  • 如果时传经一个函数环境,那么创建形参及函数参数的默认值。如果是非函数环境,将跳过此步骤。
  • 如果是创建全局或函数环境,就扫描当前代码进行函数声明(不会扫描其他函数的函数体),但是不会扫描函数表达式和箭头函数。对于找到的函数声明,将创建函数,并绑定到当前环境与函数名相同的标识符上。若该标识符已经存在,那么该标识符的值将被重写。如果是块级作用域,将跳过此步骤。
  • 扫描当前代码进行变量声明,在函数或者全局环境中,找到所有当前函数以及其他函数之外通过var声明的变量,并找到所有在其他函数或者代码块之外通过let或const定义的变量。在块级作用域中,仅查找当前块中通过let和const定义的变量。对于所查找的变量,若该标识符不存在,进行注册并将其初始化为undefined。若该标识符已经存在,将保留其值。
//举例说明
console.log(typeof fun === 'function') //true: 函数声明提前第二步,第三步变量声明提前的时候因为发现标识符已经存在,则保留原来的值,所以依旧为function
var fun = 3;
console.log(typeof fun === 'number');//true: fun被重新赋值为3
function fun(){};
cosole.log(typeof fun === 'number') //true 在程序实际执行过程中,跳过函数声明部分。所以依旧为number

进入正题 - 认识闭包

闭包允许函数方位并操作函数外部的变量。只要变量或函数存在于声明函数时的作用域内,闭包即可使函数能够访问这些变量或函数。

//闭包例子
var outerValue = "sss";
var later;
function outerFunc(){
  var innerValue = "eee";
  function innerFunc(){
    console.log(outerValue === "sss") 
    console.log(innerValue === "eee") 
  }
  later = innerFunc
}
outerFunc(); 
later();  // true true

说明: 当在外部函数中声明内部函数时,不仅定义了函数的声明,而且还创建了一个闭包,该闭包中不仅包含了函数的声明,还包含了在函数声明时该作用域中的左右变量。当最终执行内部函数时,尽管声明时的作用域已经消失了,但是通过闭包,仍然能够访问到原始作用域。

注意:虽然闭包时非常有用的,但是不能过度使用。使用闭包时,所有的信息都会存储在内存中,知道JavaScript引擎确保这些信息不再使用(可以安全的进行垃圾回收),或页面卸载时,才会清理这些信息

使用闭包
  1. 封装私有变量
function A(){
  var value = 55;
  this.getValue = function(){
    return value
  };
  this.add = function(){
    value = value + 10;
  }
}

var a1 = new A();
a1.add();
//a1.value = undefined;
//a1.getValue() = 65

var a2 = new A();
//a2.getValue() = 55;

//注意:
var obj = {};
obj.getValue = a1.getValue ;
//obj.getValue() = 65

注意: 将a1的getValue方法赋给新的obj对象,我们发现可以通过obj.getValue()获得a1的value值。表明了在JavaScript中没有真正的私有对象属性

  1. 回调函数
function move(){
  var step = 10;
  var sum = 0;
  var timer = setInterval(function(){
    sum = sum + step;
  },1000)
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值