JavaScript 系列之做用域(三)

这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战git

4、函数做用域和块级做用域

ES6 以前 JS 没有块级做用域。github

if (true) {
  var name = 'zhangsan'
}
console.log(name) // zhangsan
复制代码

从上面的例子能够体会到做用域的概念,做用域就是一个独立的地盘,让变量不会外泄、暴露出去。上面的 name 就被暴露出去了,所以,ES6 以前 JS 没有块级做用域,只有全局做用域函数做用域markdown

var a = 100
function fn() {
  var a = 200
  console.log('fn', a) // fn 200
}
console.log('global', a) // global 100

fn()
复制代码

ES6 出来以后,let 和 const 都可以声明块级做用域app

4.1 var

使用 var 声明的变量,不管是在代码的哪一个地方声明的,都会提高到当前做用域的最顶部,这种行为叫作变量提高(Hoisting)ide

  • 若是是在函数内部声明的变量,都会被提高到函数开头。
  • 若是是在全局声明的变量,就会提高到全局做用域顶部。
function test() {
  console.log("1: ", a); //undefined
  if (false) {
    var a = 1;
  }
  console.log("3: ", a); //undefined
}

test();
复制代码

实际执行时,上面的代码中的变量 a 会提高到函数顶部声明,即便 if 语句的条件是 false,也同样不影响 a 变量提高。函数

function test() {
  var a;
  //a 声明没有赋值
  console.log("1: ", a); //undefined
  if (false) {
    a = 1;
  }
  //a声明没有赋值
  console.log("3: ", a); //undefined
}

test();
复制代码

在函数嵌套函数的场景下,变量只会提高到最近的一个函数顶部,而不会提高到外部函数。oop

// b 提高到函数a顶部,但不会提高到函数 test
function test() {
  function a() {
    if (false) {
      var b = 2;
    }
  }
  console.log("b: ", b);
}
test(); // b is not defined
复制代码

4.2 let

let 和 const 都可以声明块级做用域,用法和 var 是相似的,let 的特色是不会变量提高,而是被锁在当前块中。惟一正确的使用方法:先声明,再访问post

function test() {
  if (true) {
    console.log(a); //TDZ,俗称临时死区,用来描述变量不提高的现象
    let a = 1;
  }
}
test(); // a is not defined

function test() {
  if (true) {
    let a = 1;
  }
  console.log(a);
}
test(); // a is not defined
复制代码

4.3 const

声明常量,一旦声明,不可更改,并且常量必须初始化赋值。ui

const 虽然是常量,不容许修改默认赋值,但若是定义的是对象 Object,那么能够修改对象内部的属性值包括新增删除键值对也是能够的。lua

5、做用域链

函数有一个内部属性 [[scope]]

自由变量一层一层向上寻找,直到找到全局做用域仍是没找到,就宣布放弃。这种一层一层的关系,就是做用域链

let a = 100;
function F1() {
  let b = 200;
  function F2() {
    let c = 300;
    console.log(a); // 自由变量,顺做用域链向父做用域找
    console.log(b); // 自由变量,顺做用域链向父做用域找
    console.log(c); // 本做用域的变量
  }
  F2();
}
F1();
复制代码

image.png

image.png

文章连接

相关文章
相关标签/搜索