你不知道的JavaScript(上)作用域与闭包

时间:2023-02-23 12:36:46

第一部分 作用域与闭包

第一章 作用域是什么

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

你不知道的JavaScript(上)作用域与闭包例子:

     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(上)作用域与闭包的更多相关文章

  1. 你不知道的JavaScript(作用域和闭包)

    作用域和闭包 ・作用域 引擎:从头到尾负责整个JavaScript的编译及执行过程. 编译器:负责语法分析及代码生成等. 作用域:负责收集并维护由所有声明的标识符(变量)组成的一系列查询,并实施一套非 ...

  2. 我认知的javascript之作用域和闭包

    说到javascript,就不得不说javascript的作用域和闭包:当然,还是那句老话,javascript在网上都说得很透彻了,我也就不过多的强调了: 作用域:javascript并没有像其他的 ...

  3. 读书笔记-你不知道的JavaScript&lpar;上&rpar;

    本文首发在我的个人博客:http://muyunyun.cn/ <你不知道的JavaScript>系列丛书给出了很多颠覆以往对JavaScript认知的点, 读完上卷,受益匪浅,于是对其精 ...

  4. 你不知道的JS之作用域和闭包 附录

     原文:你不知道的js系列 A 动态作用域 动态作用域 是和 JavaScript中的词法作用域 对立的概念. 动态作用域和 JavaScript 中的另外一个机制 (this)很相似. 词法作用域是 ...

  5. 你不知道的JS之作用域和闭包(五)作用域闭包

    原文:你不知道的js系列 一个简单粗暴的定义 闭包就是即使一个函数在它所在的词法作用域外部被执行,这个函数依然可以访问这个作用域. 比如: function foo() { var a = 2; fu ...

  6. javascript的作用域和闭包(三)闭包与模块

    一些很重要的说明:前面三篇博客详细的介绍了,引擎与编译器和作用域的关系,重点需要理解的是编译器中的分词与词法分析,JavaScript的特有的“赋值操作的左右侧”引用操作:编译阶段的词法作用域的工作原 ...

  7. javascript从作用域到闭包-笔记

    读<你不知道的javascript>一书做个笔记;编译原理:    js是一门编译型的语言,与传统编译语言类似,传统编译的过程分为三个阶段 ;     1. 分词/词法分析; 2.解析/语 ...

  8. 剖析JavaScript函数作用域与闭包

    在我们写代码写到一定阶段的时候,就会想深究一下js,javascript是一种弱类型的编程语言,而js中一个最为重要的概念就是执行环境,或者说作用域.作用域重要性体现在哪呢?首先,函数在执行时会创建作 ...

  9. JavaScript之作用域与闭包详解

    前言: JavaScript是一种应用非常广泛的语言,其也有一些自身特点和优势,本文重在讲述其作用域机制以及闭包,会从一些实例来探讨其机理. 作用域在JavaScript程序员日常使用中有不同的含义, ...

  10. JavaScript 函数作用域和闭包

    函数作用域和闭包  词法作用域   它们在定义它们的作用域里运行,而不是在执行的作用域运行,但是只有在运行时,作用域链中的属性才被 定义(调用对象),此时,可访问任何当前的绑定.   调用对象     ...

随机推荐

  1. php 实现设计模式之 建造者模式

    <?php /** * 建造者模式 * ------------- * 定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. * 类型:创建类模式 * 四个要素: * ...

  2. Debian

    一.简介 https://zh.wikipedia.org/wiki/Debian 二.下载 https://www.debian.org/ 三.配置 1)挂载iso镜像 mount /dev/cdr ...

  3. 【Todo】【读书笔记】大数据Spark企业级实战版 &amp&semi; Scala学习

    下了这本<大数据Spark企业级实战版>, 另外还有一本<Spark大数据处理:技术.应用与性能优化(全)> 先看前一篇. 根据书里的前言里面,对于阅读顺序的建议.先看最后的S ...

  4. Python串行运算、并行运算、多线程、多进程对比实验

    转自:http://www.redicecn.com/html/Python/20111223/355.html Python发挥不了多核处理器的性能(据说是受限于GIL,被锁住只能用一个CPU核心, ...

  5. VS2010调试小技巧

    在VS下做开发的时候我们进行调试的时候路径是这个样子的:http://localhost:端口号/项目名称/index.aspx 但是发布到服务器上面的时候却是这个样子的:http://www.xxx ...

  6. easyui datagrid 行数

    $('#gridList').datagrid('getData').rows.length

  7. 基于Debian系统配置Nginx环境的Node&period;js应用教程

    Node.js,是当前比较流行的能够动态的快速响应内容的JavaScript框架,在有些环境下比我们使用的PHP应用都能够提高效率.目 前,Node.js可以与我们常用的Nginx.Apache等服务 ...

  8. 如何使用mybatis对mysql数据库进行操作,batis的增删改查

    1.先下载Mybatis和mysql connecrt的jar包 下载地址: 链接: https://pan.baidu.com/s/1kVFfF8N 密码: ypkb 导入jar包,maven的话可 ...

  9. 纯干货!华为软件开发云编译构建之Maven

    一.Maven介绍 Maven是一个项目管理和整合的工具.Maven为开发者提供了一套完整的构建生命周期框架.开发团队基本不用花多少时间就能自动完成工程的基础构建配置,因为Maven使用了一个标准的目 ...

  10. zookeeper的使用demo(c&num;&sol;java)

    Zookeeper 作为一个分布式的服务框架,主要用来解决分布式集群中应用系统的一致性问题,它能提供基于类似于文件系统的目录节点树方式的数据存储,但是 Zookeeper 并不是用来专门存储数据的,它 ...