一、作用域定义
作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期。在JavaScript中,变量的作用域有全局作用域和局部作用域两种。ES6中新增块级作用域。
相应作用域的变量分别称为全局变量、局部变量和块级变量。
二、全局作用域
一般来说以下几种情形拥有全局作用域:
(1)最外层函数和在最外层函数外面定义的变量拥有全局作用域,直接写在script标签中的JS代码或单独一个JS文件中的;
<script>
var a = 1;
</script>
(2)所有末定义直接赋值的变量自动声明为拥有全局作用域(情况较少);
(3)所有window对象的属性拥有全局作用域。一般情况下,window对象的内置属性都拥有全局作用域,例window.name、window.location、window.top等等。
var a = 1;
function b(){
console.log(a); // 1 a为全局变量可以在函数内访问到
}
console.log(a); // 1 可以全局访问
console.log(window.a); // 1 可以全局访问
三、局部作用域
1、 也称为函数作用域,其含义是指,属于这个函数的全部变量都可以在整个函数的范围内使用及复用(包括嵌套的作用域中也可以使用)在固定的代码片段才能被访问;
function b(){
var a = 1; // 变量a定义在函数内部
}
console.log(a) // error,引用错误,a没有定义
2、调用函数时创建函数作用域,函数执行完成后,函数作用域就销毁,每调用一次函数就会创建一个新的函数作用域,他们之间是互相独立的;
function b(){
if(true){
var a = 1; // a的作用域不是if的范围,而是在函数中
}
console.log(a); // 1 在函数内部能访问到
}
console.log(a); // error引用错误
**3、和全局作用域的关系:**在函数作用域中可以访问到全局作用域的变量,但是在全局作用域中是访问不到函数作用域的变量;当函数作用域操作一个变量时,它会先在自身中寻找,如果有就直接使用,如果没有就向上一级作用域中寻找,直到找到全局作用域。
var a = 1;
function b(){
var a = 10;
console.log(a); // 10 局部变量和全局变量同名,在函数作用域中,局部变量覆盖全局变量
}
console.log(a); // 1 输出全局变量的值
四、块级作用域
ES6 中引入了 let 与 const,与 var 不同的是在大括号(包括纯粹的大括号、if、while、for)间用var 定义的变量处在全局作用域。如果我们用 let 与 const 在大括号中定义,变量将处于块作用域。
{
var a = 1; // var声明a=1 全局变量
let b = 2; // let声明b=2 局部变量
const c = 3; // const声明c=3 局部变量
console.log(a) // 1
console.log(b) // 2
console.log(c) // 3
}
console.log(a) // 1
console.log(b) // error引用错误,b未定义
console.log(c) // error引用错误,c未定义
对块级变量来说,其作用域是块级变量声明语句开始到块结束之间的区域。
let 与 const 的不同点在于,const 定义的是一个常量,无法修改定义后的值。
{
const a; // 语法错误,const声明必须初始化赋值
const b = 1; // const声明c为常量,赋值后不会改变,在块级作用域内
}
console.log(b); // error引用错误b未定义
五、作用域中的特殊情况
1、函数参数------属于函数(局部)作用域
function printAge(age) {
console.log('我今年' + age + '岁了');
}
printAge(20); // 我今年20岁了
console.log(age); // 报错
2、for循环
使用var---全局作用域,外面也可以访问
for(var i = 0; i < 10; i++) {
console.log(i); // 0 1 2 3 4 5 6 7 8 9
}
console.log(i); // 10
使用let---块级作用域,只能在{}范围内被访问,外面访问不到
for(let i = 0; i < 10; i++) {
console.log(i); // 0 1 2 3 4 5 6 7 8 9
}
console.log(i); // error
3、try...catch中的err---不属于任何作用域,只能被catch访问
try {
throw new Error();
} catch (err) {
var test = 'hello';
const test2 = 'Hi';
console.log(err); // 正常打印
}
console.log(test); // hello
console.log(test2); // 报错
console.log(err); // 报错
六、作用域实例
function Person() {
getAge = function () {
console.log(1);
}
return this;
}
Person.getAge = function () {
console.log(2);
}
Person.prototype.getAge = function () {
console.log(3);
}
var getAge = function () {
console.log(4);
}
function getAge() {
console.log(5);
}
Person.getAge();
getAge();
Person().getAge();
getAge();
new Person.getAge();
new Person().getAge();
输出结果:2 4 1 1 2 3