《JavaScript高级程序设计》总结(六)—— 做用域和变量提高

函数变量的做用域

就是变量声明的区域,就是变量和函数的可访问范围javascript

全局变量

在全局做用域中声明的变量叫作全局变量,全局做用域的变量能够在js中任何地方调用 ,变量没有在函数内声明或者声明的时候没有带var就是全局变量,拥有全局做用域。特殊:var a = b = c = 0; b与c是全局变量。java

局部变量

如,在函数内部声明的变量只能在函数内部访问es6

块级做用域

在javascript中,函数里面定义的变量,能够在函数里面被访问,但在函数外没法访问。而由花括号封闭的代码块都有本身的做用域,于是支持根据条件来定义变量,变量在执行完毕后会被销毁,注意在es6以前的版本,并无块级做用域,只有函数做用域和全局做用域,for循环的循环体中是函数做用域,for循环内部定义的变量在整个所在的函数内部是能够访问的。bash

举个栗子函数

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.Scopeui

函数在执行的时候会沿着最末端的做用域依次向上查找变量,所以,子域能够访问父域的变量,而父域不能够访问子域的es5

上述代码的执行结果为spa

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删除的。code

函数内部的声明的变量会被提高到函数的头部。函数在解析执行的时候,先进行变量声明处理,而后再运行函数内部的代码。ip

变量和赋值语句一块儿书写,在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
}
复制代码
相关文章
相关标签/搜索