从函数做用域和块级做用域看javascript的做用域链

在ES6以前,javascript只有全局做用域和函数做用域。所谓做用域就是一个变量定义并可以被访问到的范围。也就是说若是一个变量定义在全局(window)上,那么在任何地方都能访问到这个变量,若是这个变量定义在函数内部,那么就只能在函数内部访问到这个变量。javascript

全局做用域只要页面没关闭就会一直存在,而函数做用域只有在函数执行的时候才存在,执行完就销毁。且每次执行函数都会建立一个新的做用域java

那么什么是做用域链呢?

在了解做用域链以前,咱们先了解一个执行期上下文的概念。闭包

执行期上下文:当函数执行时,会建立一个称为执行期上下文的内部对象(即AO或GO),一个执行期上下文定义了一个函数的执行环境,函数每次执行时对应的执行期上下文都是独一无二的,因此每次调用一个函数都会建立一个新的执行期上下文,当函数执行完毕,所产生的执行期上下文被销毁。函数

做用域链就是函数中[[scope]]属性所存储的执行期上下文对象的集合,这个集合呈链式连接,咱们把这种链式连接叫作做用域链。this

做用域链更像是一种包含的关系。好比说函数A内部定义了一个函数B,因此B的定义是依赖于A的,也就是说B在A的内部,那么B中就能够访问A的中的变量和方法。这种一层一层向上依赖的关系就构成了做用域链。spa

为了更好理解,咱们直接看例子。code

var name = 'xiaoyu';
function fn1() {};
function fn2() {
    var num = 10;
    function fn3() {
        var num1 = 10;
        console.log(num);
    };
    return fn3;
}
var fn4 = fn2();

在上个例子咱们知道,fn2执行的时候返回fn3,产生了闭包。可是一个函数执行而后返回另外一个函数都会产生闭包嘛?咱们来看一下。对象

var name = 'xiaoyu';
function fn1() {};
function fn2() {
    var num = 10;
    function fn3() {//fn3函数没有依赖fn2函数内的变量
        var num1 = 10;
        console.log(num1);
    };
    return fn3;
}
var fn4 = fn2();

了解了做用域链以后,咱们来看一个小例子,巩固一下。blog

var age = 10;
var obj = {
    age: 12,
    test: function() {
        console.log(age);
        console.log(obj.age);
        console.log(this.age);
    }
}
obj.test();

console.log(this.age)打印出12不难理解,可是为何console.log(age)不也应该打印出12嘛。ip

咱们说test执行时首先会在本身的做用域内查看有没有age变量,而后再沿着做用域链往上到全局做用域查找age变量,全局做用域下有age变量和data变量。因此console.log(age)打印出的10,若是要打印出12则须要访问obj.age。

 ES6的块级做用域

在ES6以后,经过let和const引入了块级做用域。即经过let和const声明的变量只在声明所在的块级做用域内有效,而且let声明的变量虽然属于全局变量,但再也不属于全局对象window。

咱们经过一段代码来看一下引入块级做用域后,函数的做用域链的变化。

var age = 10;
let obj = {
    age: 12,
    test: function() {
            console.log(age);
            console.log(obj.age);
            console.log(this.age);
    }
}
obj.test();

 

相关文章
相关标签/搜索