作用域与闭包第一二三章

来源:互联网 发布:pdb数据库 编辑:程序博客网 时间:2024/06/11 10:56

作用域与闭包

 

第一章:什么是作用域


-在变量中存储值和取出值的能力,给程序赋予了状态

-变量存活在哪里

-程序如何找到它们

-定义规则:作用域

 

编译器理论


-传统编译型:“编译”

       1.分词/词法分析

              -token(记号):将一连串字符打断成有意义的片段

       2.解析

              -将一个token的流(数组)转换为一个嵌套元素的树

              -综合表示了程序的语法结构

              -抽象语法树(AST—Abstract Syntax Tree)

       3.代码生成

              -将抽象语法树转换为可执行的代码

-JavaScript

       1.JS引擎没有大把时间去优化

       2.JS代码段刚好在它之前被编译

 

理解作用域


-过程处理想象成一场对话

-演员

       1.引擎:负责从始至终编译和执行JS程序

       2.编译器:解析和代码生成

       3.作用域:收集维护被声明变量的列表,制定访问规则

-反复

       1.编译期间:声明一个变量(先前没有在当前作用域中声明过)

       2.执行期间:在作用域中查询变量并赋值(如果找到的话)

-编译器术语

       1.”LHS”查询(Left-hand Side)

              -变量出现在赋值操作的左手边 a = 2;

              -赋值的目标

       2.”RHS”查询(Right-hand Side)

              -简单查询变量的值console.log(a);

              -赋值的源

 

嵌套的作用域


-遍历嵌套作用域简单规则

-从当前执行的作用域一直往上级查找,到最外层的全局作用域停止

-错误

       1.RHS查询找不到会导致引擎抛出ReferenceError

       2.非Strict模式LHS查询没有会在全局作用域中创建同名新变量

       3.ReferenceError:作用域解析失败

       4.TypeError:作用域解析成功,试图对结果进行非法/不可能动作

 

第二章:词法作用域

-作用域的工作方式模型

       1.词法作用域:常见,绝大多数编程语言使用

       2.动态作用域:Bash脚本,Perl中的一些模式

-词法分析时

       -词法作用域是在词法分析时被定义的作用域

       -将词法作用域看作是仅仅依靠词法的

-查询

       1.一旦找到第一个匹配,作用域查询就停止

       2.“遮蔽”(shadowing):内部的标识符遮蔽了外部的标识符

       3.全局变量 window.a访问

       4.词法作用域由这个函数被声明的位置唯一定义

-欺骗词法作用域

       1.会导致更低下的性能

       2.eval(…):在运行时修改一个编写时的词法作用域

              -Strict模式不会实际修改

              -setTimeout(),setInterval()可以为它们各自第一个参数值接收一个字符串,其内容会被eval为一个动态生成函数的代码(老旧废弃别做)

       3.with:从你传递给它的对象中凭空创造了一个全新的词法作用域

       4.性能:存在eval和with将不会做优化,代码运行慢(假定自己知道的所有标识符位置无效)

 

第三章:函数与块作用域

-函数中的作用域

       1.JavaScript拥有基于函数的作用域

       2.函数作用域:所有变量属于函数,贯穿整个函数使用/重用/嵌套访问

-隐藏于普通作用域

       1.将变量和函数围在一个函数的作用域中来”隐藏”它们

       2.最低权限原则(note-least privilege/最低授权/最少曝光):私有细节保持为私有

       3.避免冲突:避免同名用处不同的标识符之间发生无意的冲突

       4.全局“名称空间”:多个库加载到全局作用域中(为库创建单独的变量声明)

       5.模块管理:通过依赖管理器(库导入指定作用域)回避冲突

-函数作为作用域

       1.区分函数声明和函数表达式

              -名称作为一个标识符被绑定在何处

              -外部为声明function foo(){}内部表达式(function foo(){…})()

       2.匿名和命名

              -函数声明不能省略名称

              -匿名缺点:栈轨迹无名称使调试困难/自引用困难/描述性名称帮助自解释

              -内联函数表达式:强大有用(最佳方法命名函数表达式)

       3.立即调用函数表达式

              -IIFE(ImmediatelyInvoked Function Expression):立即被调用的函数表达式

              -利用只是函数调用的事实,来传入参数值

var a =2;

(functionIIFE(global ){

       var a =3;

       console.log( a );// 3

       console.log(global.a );// 2

})(window );

console.log( a );// 2

              -变种先定义后传值:用于UMD(Universal Module Definition统一模块定义)项目,繁杂

var a =2;
(functionIIFE( def ){
        def( window );
})(functiondef( global ){
        var a =3;
        console.log( a ); // 3
        console.log( global.a ); // 2
});

-块儿作为作用域

       1.尽量靠近的局部的在变量将被使用的位置声明它

       2.bar仅在声明作用域使用 var总属于外围作用域

       3.是一种扩展了早先的”最低暴露原则”

       4.with块、try/catch的catch块

       5.let声明的变量依附所在块(之下),不暴露给外作用域

{
   console.log( bar ); // ReferenceError!
   let bar =2;
}

      6.垃圾回收:关于闭包和释放内存的垃圾回收

       -声明可以将变量绑定在本地的明确的块(块作用域)

      7.let循环

for (let i=0; i<10; i++) {
        console.log( i );
}
console.log( i ); // ReferenceError

       8.const创建一个块儿作用域变量,值固定

-总结

       应当同时使用函数作用域和块儿作用域技术—在它们各自可以产生更好,更易读/易维护代码的地方。

 

 

 

 

 

 

 

 

 

 

 

原创粉丝点击