追求JS小姊姊系列 Day25 -- 工具人、姐妹的存活原理:宣告变数的有效区域

前情提要:

看完记忆体储存差异,现在要来谈谈全域污染这件事。

基本scope概念

所谓的范畴Scope是规范变数有效的区域

在JavaScript内有三个主要的变数有效范畴:

  1. global scope
  2. function scope
  3. block scope

透过下面这段程序码来标示所谓的scope


let x = 2;
let y = 2;
function trys(){
    let x = 3;
    let y = 3;
}

{
    let x = 4;
    let y = 4;
}


Scope 与宣告的关系

不同的宣告有不同的变数有效范畴,以下简单以表格呈现:

宣告方式 var let const
有效区域 global scope / function scope global scope / funciotn scope / block scope global scope / funciotn scope / block scope

有效区域指的是什麽意思,也直接看例子吧?


//区域范畴内有x变数
{
    let x = 3;
    
}
console.log(x);

可以理解成x这个宣告,出了这个区域就会无效(无法取得)。

其实之所以会出现所谓scope的现象,背後是由字汇环境一手包办的,什麽意思?


从字汇环境的视角诠释

字汇环境(lexical environment)的任务就是:追踪纪录范畴内(scope)的识别字

let x = 2;
let y = 2;
function trys(){
    let x = 3;
    let y = 3;
}

{
    let x = 4;
    let y = 4;
}

会透过字汇环境纪录自己区域内的宣告内容,在你需要使用时就会来找寻

当你要找寻的变数,不存在当前的字汇环境中,它会往上层的字汇环境找寻,若到了全域都没有此变数,则会回报reference error

假设我们今天在函式内会取用到z这个变数,但它不存在:

let z = "我在全域";

function doIt(i){
    console.log(z);
}

doIt();


最後由图可知,变数z会在全域找到。

理念大概理解,用实例来试试看吧


重新理解for回圈结构!

来看一个经典的范畴(scope)相关题目

当我们用var宣告时

for(var i =0;i <4;i++){
    setTimeout(function(){
        console.log(i,"我是结果");
    },1000)
}

你想像的执行过程跟的结果

i = 0; console.log(0,"我是结果");
i = 1; console.log(1,"我是结果");
i = 2; console.log(2,"我是结果");   
i = 3; console.log(3,"我是结果");
i = 4; console.log(4,"我是结果");
//0,"我是结果";
//1,"我是结果";
//2,"我是结果";
//3,"我是结果";
//4,"我是结果";

实际上的结果

因为

  1. 非同步的关系,它实际上是跑完回圈後
  2. 字汇环境的原因

varlet的差别

前面有提过两者的范畴上的差异:

var时,因为它不具有block scope,所以并不存在{}的字汇环境,因此不会纪录i的值,所以会往global environment寻找此值,

i = 0;
i = 1;
i = 2;
i = 3;
i = 4;

console.log(4);
console.log(4);
console.log(4);
console.log(4);
console.log(4);

而因为非同步的执行,所以当要印出所有i时,global environment所纪录的值,已经是迭代完成的值,也就是4

那为何let就可以?
前面提过let具有block environment的特性,所以每次迭代时,都会在{}建立字汇环境,并记住当前i的值。

所以你可以想像为:

//开始迭代: for environment
{    
    let i =0;
    console.log(i);
}
//第一圈後: for environment
{
    let i =1;
    console.log(i);
}

...

{
    let i = 4;
    console.log(i);
}

不过上述的论述,只是在学习过程与前辈跟同学讨论的整理,并没有在规范中明确定义。

-- to be continued --


那今天就到这边搂!
每天的休息,是为了後面的追求,明天见。


reference:

忍者2
所有的函式都是闭包:谈 JS 中的作用域与 Closure


<<:  [Day27] - Django-REST-Framework API 期末专案实作 (二)

>>:  DAY25:模型训练DenseNet201

D14 - 如何用 Apps Script 自动化地创造与客制 Google Docs?(一) 以 NDA 为例的大架构与简单复制

今天的目标 现在几乎每天都会打开 Google Doc,但有时就是会有很多类似的文件,其实只要调整一...

Day 13: Monitor and Log with Google Cloud Operations Suite: Challenge Lab

Tasks: Initialize Cloud Monitoring. Navigation men...

课堂小考 - 深度学习 Deep Learning Q&A(2)

请先看 课堂笔记 - 深度学习 Deep Learning (17) Gradient and Di...

[Pytorch] torchvision.transforms()

torchvision.transforms() Transforms are common im...

Day 14 - 寻访其他组件

在开发Vue时,官方建议使用属性及事件对其他元件做处理,不过凡事总有例外的嘛~ 还是会有一些情境中会...