【Javascript】从作用域、作用域链角度浅谈let、var、const和闭包

作用域

作用域:变量和代码能够被访问到的区域,即可见性。
分为全局作用域、函数作用域和块级作用域。

全局作用域

不在函数和代码块内声明的变量,都是在全局作用域下。在全局作用域中,var声明的变量会挂在window对象上,let和const不会。

函数作用域

即在函数中声明的变量,只能在函数中访问。

块级作用域

在代码块里用let/const声明的变量,只能在该代码块里访问。

闭包

词法作用域

词法环境:变量在创建时就已经有了作用域,而不是等到被调用的时候才有。Js就是依赖词法环境的。

闭包

闭包是指:内层函数中可以访问外层函数声明的变量。(内层函数访问到外层函数的作用域)
这就是因为当外层函数中的该变量被声明后,它的词法环境就被创建了,内层函数就可以访问到该变量。

闭包原理

函数执行会分成两个阶段(预编译阶段和执行阶段)。

  1. 预编译阶段:如果发现内部函数使用了外部函数的变量,就会在内存中创建一个“闭包”对象并保存对应的变量值,如果已经创建了闭包则只需要增加对应的属性值即可。
  2. 执行阶段:执行完成后,函数的执行上下文会被销毁,函数对“闭包”对象的引用也会被销毁,但是其内部函数还持有该“闭包”的引用,所以内部函数可以继续使用“外部函数”中的变量。

闭包引用了函数作用域链的特性,一个函数内部定义的函数会将包含外部函数的活动对象添加到它的作用域链中,函数执行完毕后,其执行作用域链被销毁,但因内部函数的作用域链仍然在引用这个活动对象,所以其活动对象不会被销毁,直到内部函数被销毁后活动对象才会被销毁。

function outside() {
    var a = 1;
    return function inside1() {
        a++;
        console.log(a);
    }
}
var a = 0;
let increment = outside();
increment(); // 2
console.log(a); // 0

闭包使用场景

  1. 柯里化函数: 大量含有部分相同的参数的函数调用可以简化成只用传入不同参数。
function Area(width) {
    return function(height) {
        return width * height;
    }
}

let boxWidthTen = Area(10);
let box1 = boxWidthTen(20);
let box2 = boxWidthTen(30);
console.log(box1, box2);
  1. 模拟私有变量
var makeCounter = function() {
  var privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment: function() {
      changeBy(1);
    },
    decrement: function() {
      changeBy(-1);
    },
    value: function() {
      return privateCounter;
    }
  }
};

var Counter1 = makeCounter();
var Counter2 = makeCounter();
console.log(Counter1.value()); /* logs 0 */
Counter1.increment();
Counter1.increment();
console.log(Counter1.value()); /* logs 2 */
Counter1.decrement();
console.log(Counter1.value()); /* logs 1 */
console.log(Counter2.value()); /* logs 0 */

Counter1和Counter2各自维护自己的privateCounter,当改变它的值的时候,改变它所处闭包的词法环境,不会影响另外一个变量。

闭包的缺点

  1. 可能会导致内存泄漏。
  2. 降低运行速度。

var,let,const

前面也说了,let和const若是在代码块内声明,则在块外无法访问到。
再来看看其他区别。

变量提升

var声明和函数声明会提到作用域内的最开始。let和const不会

console.log(a); // undefined
var a = 1; 

暂时性死区

是let和const没有变量提升带来的问题:在let/const声明变量之前,该变量不可用。

console.log(a); // Uncaught
let a = 1; 

重复声明

var可以在同一作用域内重复声明,let和const不可以。

const 只读

const声明的对象具有只读性:这个只读性是单对于对象地址来说的,修改该对象的属性是没有问题的,但不能对该对象重新赋值。

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值