美文网首页
作用域链

作用域链

作者: fly_198e | 来源:发表于2019-08-14 02:43 被阅读0次

函数的作用域:

  • 作用域指的是变量存在的范围。在 ES5 的规范中,Javascript 只有两种作用域:一种是全局作用域,变量在整个程序中一直存在,所有地方都可以读取;另一种是函数作用域,变量只在函数内部存在。ES6 又新增了块级作用域。
  • 函数外部声明的变量就是全局变量,它可以在函数内部读取。
  • 在函数内部定义的变量,外部无法读取,称为“局部变量”。函数内部定义的变量,会在该作用域内覆盖同名全局变量。
  • 对于var命令来说,局部变量只能在函数内部声明,在其他区块中声明,一律都是全局变量。
function fn() {
var a = 1 ;
if (a > 2){
var b = 3;
}
console.log(b);
}
fn();

console.log(a);
输出:undefined
      ReferenceError: a is not defined 
  • JavaScript在ES6之前{}并没有带来块作用域,JavaScript的作用域是靠函数形成的,也就是说一个函数内定义的变量函数函数外不可以访问.
function f1() {
  var n = 999;
  function f2() {
  console.log(n); // 999
  }
}

上面代码中,函数f2就在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1就是不可见的。这就是 JavaScript 语言特有的”链式作用域”结构,子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。

  • 函数本身也是一个值,也有自己的作用域。它的作用域与变量一样,就是其声明时所在的作用域,与其运行时所在的作用域无关。

var:

在声明变量的时候需要var,这样声明变量作用域才符合我们上面提到的规则,那么不写var会怎样呢

function fn() {
a = 1;
}
fn();

console.log(a);
输出:1
  • 可以看到不写var会声明一个全局的变量,这是我们在编程中应该要避免的,即使真的需要全局变量也应该在最外层作用域使用var声明。
    1. 每当执行一个新的函数,就会来到一个新的作用域下;
    2. 当使用一个变量或者给一个变量赋值的时候,会在当前作用域去寻找,如若找不到再往自己的上层作用域去寻找直至全局作用域,复杂的情况还需要看函数的声明前置。
    3. 上层作用域是指该函数声明的那一层作用域。

什么是闭包:

  • 在调用一个函数然后再返回一个函数就会生成闭包,因为一般情况下一个函数在执行完成之后,函数内的一些临时变量都会被内存释放,可是有些情况得不到释放,例如函数内部有些数据是有用的,仍需被使用则不会被释放。
  • 根据JavaScript的垃圾清理机制,不需要被使用的内容会被内存自动释放,而仍然被使用的内容不会被释放,全局作用域下的内容不会被释放。所以上述函数会存在延时的变量, 可以被保存,这就生成了闭包。
  • 而闭包就是为了保存一些临时的状态和变量。原理就是通过一些方法让函数内的临时变量保存下来。闭包的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量始终保持在内存中,即闭包可以使得它诞生环境一直存在。
function createIncrementor(start) {
  return function () {
    return start++;
  };
}

var inc = createIncrementor(5);

inc() // 5
inc() // 6
inc() // 7
  • 上面代码中,start是函数createIncrementor的内部变量。通过闭包,start的状态被保留了,每一次调用都是在上一次调用的基础上进行计算。从中可以看到,闭包inc使得函数createIncrementor的内部环境,一直存在。所以,闭包可以看作是函数内部作用域的一个接口。

  • 为什么会这样呢?原因就在于inc始终在内存中,而inc的存在依赖于createIncrementor,因此也始终在内存中,不会在调用结束后,被垃圾回收机制回收。

  • 闭包的另一个用处,是封装对象的私有属性和私有方法。

function Person(name) {
  var _age;
  function setAge(n) {
    _age = n;
  }
  function getAge() {
    return _age;
  }

  return {
    name: name,
    getAge: getAge,
    setAge: setAge
  };
}

var p1 = Person('张三');
p1.setAge(25);
p1.getAge() // 25
  • 上面代码中,函数Person的内部变量_age,通过闭包getAge和setAge,变成了返回对象p1的私有变量。

  • 注意,外层函数每次运行,都会生成一个新的闭包,而这个闭包又会保留外层函数的内部变量,所以内存消耗很大。因此不能滥用闭包,否则会造成网页的性能问题。

相关文章

  • 作用域链和闭包

    在谈作用域链之前先说一下与作用域链关系紧密的执行环境和作用域。 作用域:作用域指的是变量的适用范围。 作用域链:作...

  • 作用域链

    作用域链 把多个作用域串起来便形成了作用域链;每个函数在初始化完成之后就拥有了各自的作用域链,但此时的作用域链中并...

  • web性能实践

    一. 作用域 前面我们了解作用域概念的以及作用域链是如何运作的。 随着作用域链中的作用域数量的增加,访问当前作用域...

  • JS_0: 执行环境和作用域链

    JavaScript,目前对于执行环境和作用域链的理解 什么是作用域链? 要讲作用域链就得先讲执行环境。 每个函数...

  • js 总结七07-19

    作用域 全局 局部 作用域链 闭包

  • 作用域和闭包

    作用域链 (据我所知)所有的编程语言都存在作用域链。整个代码存在全局作用域、函数作用以及块级作用域。 上述代码将会...

  • 2023-01-12

    变量提升调用栈块级作用域作用域链和闭包 闭包 => 作用域链(词法作用域) => 调用栈(栈溢出) => 上下文...

  • JavaScript 作用域链与闭包

    作用域链与闭包 了解作用域链之前需要先了解下作用域是什么。 作用域 几乎所有的语言都有作用域的概念。这是因为它们都...

  • 作用域/作用域链 闭包及其使用

    一、作用域、作用域链 作用域(scope) 浅显的理解: 作用域就是变量的可用范围(scope) 为什么要有作用域...

  • 作用域链

    作用域链(scope chain) 理解: 作用域链决定了哪些数据能被函数访问。当一个函数创建后,它的作用域链会被...

网友评论

      本文标题:作用域链

      本文链接:https://www.haomeiwen.com/subject/pxhwjctx.html