JavaScript系列教程(三)
一、作用域(scope)、作用域链
作用域(scope):一个变量的可用范围
作用域链:当前作用域没有定义的变量,这成为 自由变量 。自由变量的值如何得到 —— 向父级作用域寻找,
如果父级也没呢?再一层一层向上寻找,直到找到全局作用域还是没找到,就宣布放弃。这种一层一层的关系,就是 作用域链 。
ES6 之前 JavaScript 没有块级作用域,只有全局作用域和函数作用域。ES6 的到来,为我们提供了‘块级作用域’,可通过新增命令 let 和 const 来体现。
全局作用域
- 最外层函数和在最外层函数外面定义的变量拥有全局作用域
- 所有末定义直接赋值的变量自动声明为拥有全局作用域
- 所有 window 对象的属性拥有全局作用域
全局作用域有个弊端:如果我们写了很多行 JS 代码,变量定义都没有用函数包括,那么它们就全部都在全局作用域中。这样就会 污染全局命名空间, 容易引起命名冲突。
函数作用域
函数作用域(局部作用域)是指声明在函数内部的变量,和全局作用域相反,局部作用域一般只在固定的代码片段内可访问到,最常见的例如函数内部。
作用域是分层的,内层作用域可以访问外层作用域的变量,反之则不行。
function foo(a) { var b = a * 2; function bar(c) { console.log(b,a,c) } bar(b * 3) } foo(a); // 2, 4, 12
值得注意的是:块语句(大括号“{}”中间的语句),如 if 和 switch 条件语句或 for 和 while 循环语句,不像函数,它们不会创建一个新的作用域。在块语句中定义的变量将保留在它们已经存在的作用域中。
if (true) { // 'if' 条件语句块不会创建一个新的作用域 var name = 'Hammad'; // name 依然在全局作用域中 } console.log(name); // logs 'Hammad'
块级作用域
块级作用域所声明的变量在指定块的作用域外无法被访问
声明变量不会提升到代码块顶部
禁止重复声明
二、JS预编译,执行过程详解
关于预编译的一些知识点
1、函数声明整体提升
2、变量仅声明提升
3、如果变量未经声明就赋值,此变量就为全局对象所有
4、一切声明的全局变量,全是window的属性
局部预编译
1、创建AO对象(执行期上下文)
2、找形参和变量声明
3、将实参值和形参统一(全局预编译无这一块)
4、在函数体内找函数声明,值赋予函数体
全局预编译
1、创建AO对象(执行期上下文)
2、找变量声明
3、找函数声明,值赋予函数体
实例1-局部预编译
function check(a) { console.log(a); var a = 123; // 变量声明和定义 console.log(a); function a() {}; // 函数声明 console.log(a); var b = function() {} //变量声明和定义 console.log(b); function d() {} //函数声明 } check(1);
// 预编译结果 { a: function a() {}, b: undefined d:function d() {} }

实例2-全局和局部的预编译和解释执行过程
console.log(test); function test(test) { console.log(test); var test = 234; console.log(test); function test() { } } test(1); var test = 123; console.log(test);
// 全局预编译 { test: function test(test) {} // test: undefined被替换 } // 局部预编译 { test: function test() {} }

练习题1
var z = 1; function tim() { console.log("第一:",z) var z = 4 console.log("第二:",z); } tim();
练习题2
var z = 1; function tim() { function cope() { y = 3; //没有y属性,就会沿着作用域链往上找,一直没有就会挂载在GO上(作用域链)
} var y = 4; cope(); console.log(y); } tim();

浙公网安备 33010602011771号