什么是作用域?
作用域是负责管理如何获取和在哪里获取变量的一组规则,JavaScript属于作用域中的词法作用域。
下面问内容将详细的讲解JavaScript目前涉及到的作用域类型:
全局作用域
全局作用域定义的变量可以被任意地方所访问。
(1)最外层的函数和在最外层函数外面定义的变量 拥有全局作用域;
(2)在非严格模式下,所有未被声明直接赋值的变量 拥有全局作用域;(原因请见LFS引用原理)
(3)所有window对象的属性拥有全局作用域。
局部作用域
局部作用域正好跟全局作用域不同的是他拥有的变量只能在某个局部被使用,根据局部作用域具体类型的不同,我将其又细分为了函数作用域和块级作用域。
函数作用域
JavaScript中最常见的就是函数作用域了,从上一章的作用域气泡就可以很清楚的看到函数作用域的范围。
这里有两个很有意思的代码值得看一下:
//比较下面两段代码,试述两段代码的不同之处
// A--------------------------
var scope = "global scope";
function checkscope(){
var scope = "local scope";
function f(){
return scope;
}
return f();
}
checkscope();
// B---------------------------
var scope = "global scope";
function checkscope(){
var scope = "local scope";
function f(){
return scope;
}
return f;
}
checkscope()();
谜题就是 —— 两道题都为local scope
,由于词法作用域的特性,函数的作用域是在代码编写时就确认的,所以在checkscope
函数内执行的变量,输出的值就是变量内既定的变量值(和this的机制完全不同,后面文章会详细说明)。
块级作用域
这里大致介绍一下在JavaScript有哪些属于块级作用域,大家可以试着跑跑下面的代码:
catch
一开始只以为块级作用域是从ES6才被引入的,其实在ES3中我们就已经见过他了 —— try-catch的catch。
try {
undefined(); //用非法的操作强制产生一个异常!
}
catch (err) {
console.log( err ); // 好用!
}
console.log( err ); // ReferenceError: `err` not found
with
上一篇文章提到过的with,with会根据传入的对象,将其范围变成一个全新的作用域块儿。
function foo(obj) {
with (obj) {
a = 2;
}
}
var o2 = {
b: 3
};
foo( o2 );
console.log( o2.a ); // undefined
console.log( a ); // 2 -- 哦,全局作用域被泄漏了!
let 和 const
let是在ES6中新引入的概念,他可以将所属的{}
变成一个块级作用域,例如:
var foo = true;
if (foo) {
let bar = !foo
console.log( bar );
}
console.log( bar ); // ReferenceError
注意:if的两个大括号并属于作用域的范围,而是let让这个大括号变成了一个块级作用域。不信的话可以试试下面这段代码:
var foo = true;
if (foo) {
{
let bar = !foo;
console.log( bar );
}
console.log( 1, bar ); // ReferenceError
}
console.log( 2, bar ); // ReferenceError
我们将一对儿大括号抱在了let语句,if语句下面的第一条console会抛出一个引用错误。
const 和 let类似,唯一的区别就是 const的值定义之后是不能再被修改的。
网友评论