函数变量的作用域
就是变量声明的区域,就是变量和函数的可访问范围
全局变量
在全局作用域中声明的变量叫做全局变量,全局作用域的变量可以在js中任何地方调用
,变量没有在函数内声明或者声明的时候没有带var就是全局变量,拥有全局作用域。特殊:var a = b = c = 0; b与c是全局变量。
局部变量
如,在函数内部声明的变量只能在函数内部访问
块级作用域
在javascript中,函数里面定义的变量,可以在函数里面被访问,但在函数外无法访问。而由花括号封闭的代码块都有自己的作用域,因而支持根据条件来定义变量,变量在执行完毕后会被销毁,注意在es6之前的版本,并没有块级作用域,只有函数作用域和全局作用域,for循环的循环体中是函数作用域,for循环内部定义的变量在整个所在的函数内部是可以访问的。
举个栗子
for(var i =0;i<10;i++){
//console.log(i)
}
console.log(i) //这里i打印为10,i的作用域是全局作用域
我们来举个复杂一点的函数来分析下其中变量的作用域
var t = 9;
function f1() {
var t2 = 10;
console.log(t);
console.log(t3)
function f2() {
var t3 = 200;
console.log(t2);
return t2 * t2;
}
return f2()
}
f1();
- 1.变量t的作用域为全局作用域,任何地方都能访问到它
- 2.函数f1的作用域为全局作用域,任何地方都能访问到它
- 3.在函数f1的内部,变量t2的作用域为函数作用域f1,在函数f1中的任何地方都可以访问到它
- 4.函数f2的作用域为函数作用域f1,在函数f1中的任何地方都可以访问到它
- 5.在函数f2中,变量t3的作用域为函数作用域f2,在函数f2中的任何地方都可以访问到它
这样就形成了一个作用域链f2.Scope ===> f1.Scope ===> global.Scope
函数在执行的时候会沿着最末端的作用域依次向上查找变量,因此,子域可以访问父域的变量,而父域不可以访问子域的
上述代码的执行结果为
var t = 9;
function f1() {
var t2 = 10;
console.log(t);//9
console.log(t3)//父级不可以访问子级的变量。报错 not defined
function f2() {
var t3 = 200;
console.log(t2); //10
return t2 * t2;
}
return f2()
}
f1();
变量提升
如果一个声明的变量在函数体内,那么它的作用域就是函数内部。如果是在全局环境下声明的,那么它的作用域就是全局的。通过var声明的变量是无法用delete删除的。
函数内部的声明的变量会被提升到函数的头部。函数在解析执行的时候,先进行变量声明处理,然后再运行函数内部的代码。
变量和赋值语句一起书写,在js引擎解析时,会将其拆成声明和赋值2部分,声明置顶,赋值保留在原来位置
function a(){
var b = 1
}
上述代码就相当于
function a(){
var b
b = 1
}
变量重复声明不会出错,后面的会覆盖前面的。
var a = 1
var a = 2
console.log(a)//被覆盖,a的值为2
当函数名和变量名相同时, 函数 > 变量,也就是先函数提升,后变量提升
var a = 1
function a(){
}
console.log(a)//a打印1
既然是先函数提升后变量提升那为什么会打印变量的值呢,因为,重复声明是会被后面的覆盖的
上述代码相当于
var a = function(){
}
var a = 1
console.log(a)//a打印1
我们来看几个题目在巩固一下作用域和变量提升
1.
if (!("a" in window)) {
var a = 1;
}
console.log(a);
答案
if (!("a" in window)) {
var a = 1;
}
console.log(a);//undefined
分析
1."a" in window是判断在全局作用域中存不存在a,若存在则为true,不存在为fasle
2.在es5中函数是没有块级作用域的,因此在if中定义的变量的作用域为包括此if语句的作用域,即变量a的作用域为全局作用域
3.在js执行过程中会先进行变量提升,因此在全局中先声明一个变量a
4.if()的判断为false,因此不会a不会赋值
5打印a为undefined
var a
if (!("a" in window)) { // true
a = 1;
}
console.log(a);//undefined
2.
var a = 18;
function d() {
console.log(a);
var a = { age: 19};
console.log(a);
}
d(); // 输出?
console.log(a);
答案
var a = 18;
function d() {
console.log(a);//undefiend
var a = { age: 19};
console.log(a); //{ age: 19};
}
d(); // 输出?
console.log(a);//18
分析
在访问变量时会先在访问的作用域进行查找
1.函数d在执行的时候,遇到var a = {age:19}时进行了变量提升,只声明没有赋值,因此第一个打印语句打印undefined
2.全局中的a在全局中查找,打印18
//相当于
var a
a = 18;
function d() {
var a
console.log(a);//undefiend
a = { age: 19};
console.log(a); //{ age: 19};
}
d(); // 输出?
console.log(a);//18
小练习
练习1
console.log(a);
var a = 20;
console.log(a);
function a() {
}
练习2
f();
console.log(a);
console.log(b);
console.log(c);
function f() {
var a = b = c = 9;
console.log(a);
console.log(b);
console.log(c);
}
练习3
f();
function f() {
for(var k = 0; k <10; k++) {
console.log(k);
}
console.log(k);
}
答案
练习1
console.log(a); //打印函数a
var a = 20;
console.log(a); //20
function a() {
}
练习2
f();
console.log(a);//Uncaught ReferenceError: a is not defined
console.log(b);//如果代码可以执行到这里(忽略上述行的报错),打印9
console.log(c);//如果代码可以执行到这里(忽略上述行的报错),打印9
function f() {
var a = b = c = 9;
console.log(a);//9
console.log(b);//9
console.log(c);//9
}