大话javascript 1期:做用域和做用域链

1、什么是做用域?

做用域是你的代码在运行时,各个变量、函数和对象的可访问性。(可产生做用的区域)

2、JavaScript中的做用域

在 JavaScript 中有两种做用域前端

  • 全局做用域
  • 局部做用域

当变量定义在一个函数中时,变量就在局部做用域中,而定义在函数以外的变量则从属于全局做用域。每一个函数在调用的时候会建立一个新的做用域。函数

1.全局做用域

当你在文档中(document)编写 JavaScript 时,你就已经在全局做用域中了。JavaScript
文档中(document)只有一个全局做用域。 定义在函数以外的变量会被保存在全局做用域中
// 做用域默认为全局做用域
var name = 'andy';

全局做用域里的变量可以在其余做用域中被访问和修改code

var name = 'andy';
console.log(name); // 输出 'andy'
function logName() {
    console.log(name); // 'name' 变量能够在这里和其余地方访问
}
logName(); // 输出 'andy'

2.局部做用域

定义在函数中的变量就在局部做用域中。而且函数在每次调用时都有一个不一样的做用域。这意味着同名变量能够用在不一样的函数中。由于这些变量绑定在不一样的函数中,拥有不一样做用域,彼此之间不能访问。
// 全局做用域
function someFunction() {
    // 局部做用域 ##1
    function someOtherFunction() {
        // 局部做用域 ##2
    }
}
 
// 全局做用域
function anotherFunction() {
    //局部做用域 ##3
}

3.块语句(JS没有块级做用域)

块级声明包括if和switch,以及for和while循环,和函数不一样,它们不会建立新的做用域。在块级声明中定义的变量从属于该块所在的做用域。也就是说在for、if、while等语句内部的声明的变量与在外部声明是同样的,在这些语句外部也能够访问和修改这些变量的值。
if (true) {
    //这里的if条件不会建立一个新的做用域
    var name = 'Hammad'; // name 这个变量仍在全局做用域
}

console.log(name); // logs 'Hammad'

ECMAScript 6 引入了let和const关键字。这些关键字能够代替var对象

var name = 'Hammad';

let likes = 'Coding';
const skills = 'Javascript and PHP';

和var关键字不一样,let和const关键字支持在块级声明中建立使用局部做用域(块级做用域)ip

if (true) 
    // 这个 'if' 块语句没有建立一个块级做用域

    // name 变量处于全局做用域,由于由var关键字声明
    var name = 'Hammad';
    // likes 变量处于块级做用域由于由let关键字声明
    let likes = 'Coding';
    // skills 变量处于块级做用域由于由const关键字声明
    const skills = 'JavaScript and PHP';
}

console.log(name); // 输出 'Hammad'
console.log(likes); // Uncaught ReferenceError: likes is not defined
console.log(skills); // Uncaught ReferenceError: skills is not defined

一个应用中全局做用域的生存周期与该应用相同。局部做用域只在该函数调用执行期间存在作用域

4.词法做用域

所谓的 词法( 代码 )做用域, 就是代码在编写过程当中体现出来的做用范围. 代码一旦写好, 不用执行, 做用范围就已经肯定好了.
这个就是所谓词法做用域.这意味着 函数运行在定义它的做用域中,而不是在调用它的做用域中

在 js 中词法做用域规则:文档

  • 函数容许访问函数外的数据.
  • 整个代码结构中只有函数能够限定做用域.
  • 做用规则首先使用提高规则分析
  • 若是当前做用规则中有名字了, 就不考虑外面的名字

词法做用域

var用来将变量定义在词法做用域中(也就是function中)it

function someFunc(){
    var a;
}

a就被函数someFunc框在了词法做用域中io

块级做用域

letconst用来将变量定义在块级做用域中(也就是花括号中)console

if(true){
    let b;
}

b就被if的花括号框在了块级做用域中

5.做用域链

能够发现只有函数能够制造做用域结构. 那么只要是代码, 至少有一个做用域, 即全局做用域. 凡是代码中有函数,那么这个函数就构成另外一个做用域. 若是函数中还有函数, 那么再这个做用域中就 又能够诞生一个做用域. 那么将这样的全部的做用域列出来,能够有一个结构: 函数内指向函数外的链式结构.

做用域嵌套

做用域是能够嵌套的,任务一中提到的词法做用域和块级做用域均可以嵌套其余做用域
(块级做用域仅对ES6而言)

function someFunc(){
    function inner(){
    }
}

inner就是嵌套在someFunc(词法做用域)中的词法做用域

if(true){
    while(false){
    }
}

while就是嵌套在if(块级做用域)中的块级做用域

function someFunc(){
    if(true){
    }
}

if就是嵌套在someFunc(词法做用域)中的块级做用域

做用域中的变量访问

全部的嵌套做用域都遵循如下规则:
内部做用域有权访问外部做用域,反之不成立。

栗子:

function someFunc(){

var outerVar = 1;
function inner(){
    var innerVar = 2;
}

}
inner有权访问innerVarouterVar,可是someFunc只能访问到outerVar

多重嵌套做用域

做用域是能够任意嵌套的,可是都要遵循上面的规则。
再附加一个规则:
兄弟做用域不可相互访问

栗子:

function someFunc(){
    function inner(){
    }
    function inner2(){
    }
}

innerinner2都是someFunc中的做用域,正如someFunc不能访问inner们的做用域同样,inner们之间也不能相互访问。

做用域树

从上向下看这个嵌套做用域,就是棵树!
看代码:

function someFunc() {
  function inner() {
  }
  function inner2() {
    function foo() {
    }
  }
}

看树:

someFunc()
       |
      / \
     /   \
    /     \
   ↓       ↓
inner()  inner2()
           |
           ↓
         foo()

要记住的是:inner做用域能够访问外部做用域,可是反之不成立; foo()能够访问inner2()中的变量,inner2()能够访问someFunc()中的变量,这棵树倒过来彷佛更有意义,就成了链!!

做用域链

从最里面看到最外面就构成了做用域链

someFunc()
       ↑
        \
         \
          \
         inner2()
           ↑
           |
         foo()

若是你以为这篇文章对你有所帮助,那就顺便点个赞吧,点点关注不迷路~

黑芝麻哇,白芝麻发,黑芝麻白芝麻哇发哈!

前端哇发哈

相关文章
相关标签/搜索