JavaScript 一、 ES6 声明变量,作用域理解

// JavaScript
/*
* =========================================================
*
* 编译原理
* 尽管通常将 JavaScript 归类为“动态”或“解释执行”语言,但事实上它是一门编译语言。 这个事实对你来说可能显而易见,也可能你闻所未闻,取决于
* 你接触过多少编程语言,具有多少经验。但与传统的编译语言不同,它不是提前编译的,编译结果也不能在分布式系 统中进行移植。
*
* 分词/词法分析(Tokenizing/Lexing)
* 这个过程会将由字符组成的字符串分解成(对编程语言来说)有意义的代码块,这些代 码块被称为词法单元(token)。
* 例如,考虑程序var a = 2;。这段程序通常会被分解成 为下面这些词法单元:var、a、=、2 、;。空格是否会被当作词法单元,取决于空格在
* 这门语言中是否具有意义。
*
*
* 解析/语法分析(Parsing)
* 这个过程是将词法单元流(数组)转换成一个由元素逐级嵌套所组成的代表了程序语法 结构的树。这个树被称为“抽象语法树”
* (Abstract Syntax Tree,AST)。 var a = 2; 的抽象语法树中可能会有一个叫作 VariableDeclaration 的顶级节点,接下 来是一个叫作
* Identifier(它的值是 a)的子节点,以及一个叫作 AssignmentExpression 的子节点。AssignmentExpression 节点有一个叫作
* NumericLiteral(它的值是 2)的子 节点。
*
* 代码生成
* 将 AST 转换为可执行代码的过程称被称为代码生成。这个过程与语言、目标平台等息 息相关。 抛开具体细节,简单来说就是有某种方法可以
* 将 var a = 2; 的 AST 转化为一组机器指 令,用来创建一个叫作 a 的变量(包括分配内存等),并将一个值储存在 a 中。
*
*
*
* JavaScript 三大实现构成
* 一、ECMAScript:JavaScript的核心
* 二、DOM(document object model):把整个页面映射为一个多节点的结构,借助DOM提供的API,可以轻松的对节点增加,删除,替换。
* 三、BOM(browser object model):可以控制浏览器显示的页面以外的东西,如:窗口和框架等。
*
* WEB浏览器只是ECMAScript的宿主环境之一,其次还有:Node,Adobe Flash等。
*
* JavaScript 中顶层对象
* 1、window对象,它是JavaScript的最顶层对象,其它的BOM对象都是windows对象的属性;
* 2、document对象表示浏览器中加载页面的文档对象;
* 3、location对象包含了浏览器当前的URL信息;
* 4、navigator对象包含了浏览器本身的信息;
* 5、screen对象包含了客户端屏幕及渲染能力的信息;
* 6、history对象包含了浏览器访问网页的历史信息。
*
* 变量:声明的变量是存在与栈内存(先进后出),引用存放在堆内存(先进先出),。
* 1.栈内存:存储变量,包括引用变量,存储在RAM中,是先进后出的,并且像列表一样的由上而下排列,向下则是增加一个变量,向上则是释放一个变量。
* 2.堆内存:存储对象,存储在RAM中,是先进先出,像集合一样的一个内存池。
*
* 作用域:定义存储变量的一套规则,LHS(为变量赋值) 和 RHS(得到某某的值),并在的编译时,编译器和引擎都需要和作用域
* 一次次的沟通并确认作用域中是否存在此变量。
*
* 当一个html文件调用多个js文件时(只有一个窗口),使用var定义变量时:它们都属于同一个作用域,并且window这种顶层对象中时共用的。
*
* 当使用LET定义变量时,不会出现在顶层对象(window)中,ES6引入了块的概念,所以let定义的变量时存储在当前块(暂存死区)中,在此块之外的地方
* 都将不能使用,并且在let之前使用let定义的变量将直接抛出 ReferenceError错误。
*
* var定义的变量将出现在顶层对象(window)中,var定义变量时,会有一个变量提升的功效:即的var定义变量之前可以使用,但值却时undefined,因为
* 在编译的过程中会把变量声明提升到当前作用域的最上方,即:var a = 10; 在编译时,var a; 然后是 a = 10;变量赋值并没有做提升,只是声明被提升了,
* 这是因为:JavaScript 在语言设计时,易与实现。
*
* const定义的值变量,并不能更改其值。当定义引用变量时,其值是可以更换的,但是引用是不能更换,否则都将抛出TypeError
*
* *不使用标示符声明变量*
* 不使用标示符声明变量,类似var声明变量一样,有一个特性不同,在非严格模式下,当在作用域对变量进行RHS(得到某某的值),如果直至全局作用域找不到,
* 将会抛出ReferenceError,如果在作用域对变量进行LHS(为某某变量赋值),直至全局作用域还找不到变量,全局作用域中就会"创建一个"具有该名称的
* 全局变量并将其返还给引擎。
*
* *严格模式*
* 与松散模式相比,其中一个不同的行为是严格模式禁止自动或隐式地创建全局变量,LHS查询失败时,会与RHS一样抛出ReferenceError。
*
* Error
* ReferenceError 同作用域判别失败相关,而 TypeError 则代表作用域判别成功了,但是对 结果的操作是非法或不合理的。
*
* 函数:定义函数分为两种,1.function a(){}, 2.var a = function(){},前者是'函数声明',后者是'函数表达式'
* 1.函数声明会有"提升"的功效,函数表达式则"没有提升"的功效。
* 2.函数声明的"提升"功效,要优先与变量的提升,即:在同一个作用域中,函数声明提升优先级大于变量优先级。
* 推荐使用1声明函数,在ES6的出现,可以使用 async 定义函数,也是推荐使用这种。
*
*
*
* =========================================================
* */

// let 定义的值不会在javascript顶层出现,只出现在当前作用域中
let a = 20;
console.log(this.a,'this.a'); // undefined

// var 定义的变量会在顶层出现。
var b = 30;
console.log(this.b,'this.b'); // 30

// 定义的值不会在javascript顶层出现,只出现在当前作用域中
const c = 10;
console.log(this.c,'this.c'); // undefined

// c = 50; // 使用const定义值类型变量时,修改值内容,抛出typeError

const d = {a: 1, b: 2};
const e = {c: 1};
// d = e; // 使用const定义引用类型变量时,修改引用地址,抛出typeError
d.c = 19; // 使用const定义引用类型变量时,可以修改引用对象内容。
console.log(d, 'd object'); // 验证通过 Object {a: 1, b: 2, c: 19} "d object"


/*
* =========================================================
*
* JavaScript 作用域嵌套
* 1.查找变量规则
* 引擎从当前作用域中开始查找变量,如果找不到,就向上一级继续查找,当抵达最外层的全局作用域时,无论找到还是没找到,查找过程都将停止。
*
* 2.作用域链
* 作用域链查找变量的规则和作用域嵌套查找变量的方式是一样的。
*
* =========================================================
* */

// 在foo函数中,找不到f变量时,就会向上级查找变量,在全局作用域中查找到f变量。
// function foo(a) {
// console.log(a + f,'==a + f');
// }
// var f = 2;
// foo(2);

// 对f RHS操作,所以会抛出ReferenceError
// function foo(a) {
// console.log(a + f, '==a + f');
// f = a;
// }
// foo(2);

// 非严格模式下,不使用var let const 等声明变量,对l LHS操作,全局作用域中会对l,创建一个l全局变量变量。
// 使用严格模式可验证这个证明
function foo(a) {
// 'use strict';
l = a;
console.log(a + l,'a+b');
}
foo(2);
console.log(this.l,'this.l');
原文地址:https://www.cnblogs.com/zero-zf/p/6815503.html