你不知道的JavaScript(上)作用域与闭包
第一部分 作用域与闭包
第一章 作用域是什么
1、作用域
变量赋值操作会执行两个动作:首先编译器会在当前作用域中声明一个变量(如果之前没有声明过),
然后会在运行时引擎会在作用域中查找该变量,找到就会对他赋值。
2、理解LHS和RHS操作赋值
简单来说 LHS:查找的目的是进行变量赋值,使用LHS查询【存】
RHS:目的是获取变量的值,就会用RHS【取】
3、JavaScript编译原理 例如var a=2会被拆分为 var a在其作用域中声名新变量;a = 2会查询变量a并且对它赋值
4、不成功的RHS会抛出ReferenceError异常。不成功的LHS引用会导致自动隐式地创建一个全局变量(非严格模式下),该变量使用LHS引用的目标未标识符,或者抛出ReferenceError异常(在严格模式下)
第二章 词法作用域
词法作用域意味着作用域由书写代码时函数声明的位置来决定的,JavaScript有两个机制可以“欺骗词法作用域”:eval(...)和with.
1、eval()可以对一段包含一个或多个声明的“代码”字符串进行演算,借此修改已经存在的词法作用域(在运行时)
2、with本质上是通过将一个对象的引用当作作用域来处理,将对象的属性当作左通谕德标识符来处理,
从而创建一个新的词法作用域(同样在运行时)
不推荐使用,因为由副作用:
都会使引擎无法在编译时对作用于查找进行优化,,都会导致代码运行变慢【不要使用它们】
第三章 函数作用域与块作用域
函数作用域的含义时指,属于这个函数的全部变量都可以在整个函数的范围内使用及复用(事实上在嵌套的作用域中也可以使用)
隐藏内部实现
“隐藏”变量和函数是一个有用的技术。原因:
1、最小授权或最小暴露原则,这个原则是指在软件设计中,应该最小限度地暴露必要内容,而将其他内容都“隐藏”起来
2、可以规避同名标识符之间的冲突
如何解决?
方法一:全局命名空间
在全局作用域中声明一个足够独特的变量,通常是一个对象。这个对象被用作库的命名空间,所有需要暴露在外界的功能都会
成为这个对象的属性,而不是将自己的标志符暴露在顶级的词法作用域中
例如
var MyAnimals = {
style:"comfortable",
eatingSomething:function(){
},
doSomething:function(){
}
};
方法二 模块化的管理
3、函数作用域
var a = 2;
(function foo(){
var a = 3;
console.log(a);//3
})(); console.log(a);//2
区分函数声明和函数表达式最简单的方法是看function关键字出现在声明中的位置(不仅仅是一行代码,而是整个声明中的位置),如果function是声明中的第一个词,那么就是函数声明,否则就是函数表达式。
4、匿名与具名 :函数表达式可以使匿名的,但是函数声明不可以省略函数名
5、立即执行函数表达式
var a = 2;
(function foo() {
var a = 3;
console.log( a ); //
})();
console.log( a ); //
6、块作用域
(1)with 用 with 从对象中创建出的作用域仅在 with 声明中而非外部作用域中有效
(2) try/catch try / catch 的 catch 分句会创建一个块作用域,其中声明的变量仅在 catch 内部有效
例子
try {
undefined(); // 执行一个非法操作来强制制造一个异常
}
catch (err) {
console.log( err ); // 能够正常执行!
}
console.log( err ); // ReferenceError: err not found
(3)ES6引入的新关键字let。let关键字可以将变量绑定到所在的任意作用域中(通常是 { .. } 内部)。也就是说,let为其声明的变量隐式地在所在的块作用域。
隐式的块
var foo = true;
if (foo) {
let bar = foo * 2;
bar = something( bar );
console.log( bar );
}
console.log( bar ); // ReferenceError
显式的快 只要声明是有效的,在声明中的任意位置都可以使用 { .. } 括号来为 let 创建一个用于绑定的块
var foo = true;
if (foo) {
{ // <-- 显式的快
let bar = foo * 2;
bar = something( bar );
console.log( bar );
}
}
console.log( bar ); // ReferenceError
注意:使用 let 进行的声明不会在块作用域中进行提升。声明的代码被运行之前,声明并不“存在”的
第四章 提升
(1)正确的思考思路是,包括变量和函数在内的所有声明都会在任何代码被执行前首先被处理。
(2)只有声明本身会被提升,而赋值或其他运行逻辑会留在原地
(3)函数优先 函数声明和变量声明都会被提升。但是一个值得注意的细节(这个细节可以出现在有多个“重复”声明的代码中)是函数会首先被提升,然后才是变量。
第五章 作用域闭包
闭包也就是函数嵌套函数
作用:1、作为返回值【定时器与闭包】
2、作为参数传递
模块模式两个必备条件:
1、必须有外部的封闭函数,该函数必须至少被调用一次(每次调用都会创建一个新的模块实例)
2、封闭函数必须返回至少一个内部函数,这样内部函数才能在私有作用域中形成闭包,并且可以访问或者修改私有的状态。
ES6中引入模块
1、import可以将一个模块中的一个或多个API导入到当前作用域中,并分别绑定在一个变量上
2、module会将整个模块的API导入并绑定到一个变量上
3、export会将当前模块的一个标识符(变量、函数)导出为公共 API
例子:
bar.js
function hello(who) {
return "Let me introduce: " + who;
}
export hello; foo.js
// 仅从 "bar" 模块导入 hello()
import hello from "bar";
var hungry = "hippo";
function awesome() {
console.log(
hello( hungry ).toUpperCase()
);
}
export awesome; baz.js
// 导入完整的 "foo" 和 "bar" 模块
module foo from "foo";
module bar from "bar";
console.log(
bar.hello( "rhino" )
); // Let me introduce: rhino
foo.awesome(); // LET ME INTRODUCE: HIPPO
你不知道的JavaScript(上)作用域与闭包的更多相关文章
- 你不知道的JavaScript(作用域和闭包)
作用域和闭包 ・作用域 引擎:从头到尾负责整个JavaScript的编译及执行过程. 编译器:负责语法分析及代码生成等. 作用域:负责收集并维护由所有声明的标识符(变量)组成的一系列查询,并实施一套非 ...
- 我认知的javascript之作用域和闭包
说到javascript,就不得不说javascript的作用域和闭包:当然,还是那句老话,javascript在网上都说得很透彻了,我也就不过多的强调了: 作用域:javascript并没有像其他的 ...
- 读书笔记-你不知道的JavaScript(上)
本文首发在我的个人博客:http://muyunyun.cn/ <你不知道的JavaScript>系列丛书给出了很多颠覆以往对JavaScript认知的点, 读完上卷,受益匪浅,于是对其精 ...
- 你不知道的JS之作用域和闭包 附录
原文:你不知道的js系列 A 动态作用域 动态作用域 是和 JavaScript中的词法作用域 对立的概念. 动态作用域和 JavaScript 中的另外一个机制 (this)很相似. 词法作用域是 ...
- 你不知道的JS之作用域和闭包(五)作用域闭包
原文:你不知道的js系列 一个简单粗暴的定义 闭包就是即使一个函数在它所在的词法作用域外部被执行,这个函数依然可以访问这个作用域. 比如: function foo() { var a = 2; fu ...
- javascript的作用域和闭包(三)闭包与模块
一些很重要的说明:前面三篇博客详细的介绍了,引擎与编译器和作用域的关系,重点需要理解的是编译器中的分词与词法分析,JavaScript的特有的“赋值操作的左右侧”引用操作:编译阶段的词法作用域的工作原 ...
- javascript从作用域到闭包-笔记
读<你不知道的javascript>一书做个笔记;编译原理: js是一门编译型的语言,与传统编译语言类似,传统编译的过程分为三个阶段 ; 1. 分词/词法分析; 2.解析/语 ...
- 剖析JavaScript函数作用域与闭包
在我们写代码写到一定阶段的时候,就会想深究一下js,javascript是一种弱类型的编程语言,而js中一个最为重要的概念就是执行环境,或者说作用域.作用域重要性体现在哪呢?首先,函数在执行时会创建作 ...
- JavaScript之作用域与闭包详解
前言: JavaScript是一种应用非常广泛的语言,其也有一些自身特点和优势,本文重在讲述其作用域机制以及闭包,会从一些实例来探讨其机理. 作用域在JavaScript程序员日常使用中有不同的含义, ...
- JavaScript 函数作用域和闭包
函数作用域和闭包 词法作用域 它们在定义它们的作用域里运行,而不是在执行的作用域运行,但是只有在运行时,作用域链中的属性才被 定义(调用对象),此时,可访问任何当前的绑定. 调用对象 ...
随机推荐
- mysql数据库E-R图
学会绘制E-R图 绘制E-R图首先要了解什么是实体,什么是属性,什么是联系. 1.首先实体是指现实世界中具有区分其他事物的特征或属性与其他实体有联系的实体,针对于数据库中的表而言实体是指表中一行一行特 ...
- C++学习第二天(打卡)
C++ new 可以很方便的 分配一段内存. 比如 int *test= new int ; int n; cin>>n; int * test =new int [n]; 可以实现动态分 ...
- python3 之 字符串编码小结(Unicode、utf-8、gbk、gb2312等)
python3 解释器默认编码为Unicode,由str类型进行表示.二进制数据使用byte类型表示. 字符串通过编码转换成字节串,字节码通过解码成为字符串. encode:str-->byte ...
- (四十二)golang--管道
假设我们现在有这么一个需求: 计算1-200之间各个数的阶乘,并将每个结果保存在mao中,最终显示出来,要求使用goroutime. 分析: (1)使用goroutime完成,效率高,但是会出现并发/ ...
- htm&css 颜色的浮动
目标样式 目标分析: 由图可知,整个色板可以分为三块 可以理解为一个大的盒子包含了三个小的盒子,定义如下 LEFT的定义方式 TOP的定义方式 class为bottom的块最为复杂,但分析方法也是异曲 ...
- 请求头里显示Provisional headers are shown的问题
1.问题描述: 在工作中遇到了一个坑.登录一个系统的时候,退出登录不好使了,前端确实调用了logout的接口(退出接口),但是这个接口的请求头显示Provisional headers are sho ...
- Zookeeper 应用实现-配置中心
一.目标 一个乞丐版自更新配置中心,更新配置后,能在各个服务器实现更新 二.架构 三.角色 config-web: 配置后台,主要用于管理配置,增改配置 config-agent: 监听配置,遇到变动 ...
- android java socket断线重连
android java socket断线重连 thread = new Thread(new Runnable() { @Override public void run() { while (tr ...
- 腾讯iphone面试题(转)
1Objective-C内部的实现 2CALayer和View的关系 3 http协议,tcp/ip 4 UITableView的那些元素是可以自定义的? 5 c语言的,定义变量,比如int,在什么情 ...
- 网站出现bug,我深夜被叫醒处理,用一个触发器解决了问题
凌晨两点,我正在睡梦之中,此时电话忽然想起,在漆黑的深夜中显得格外刺耳. 这个时间点电话响了肯定没好事,因为我的手机在夜间模式下,除非被同一个电话号码打三次,否则是静音,因此电话那边的人肯定有急事找我 ...