js 变量的作用域详解、生存周期,以及一些小细节。

简介: 写在前面:是想写一个闭包的,因为写的比较细,基于篇幅,所以闭包前面关于变量的部分就单独发出来,到时候放个链接引进来,js闭包虽然是一个被讲烂的东西,但其实很多人刚接触这个概念也不太懂,所以希望写一篇接地气,能够让一个从前不知道这个内容的小伙伴能够清楚的理解闭包这个东西。so,本文是基于闭包的变量部分。首先需要理解变量的作用域(变量的有效范围):变量的作用域有两种:全局变量和局部变量。全局变量很好理解:就是我们平时没有再函数内部声明的那些变量,在全局中任何地方(函数,对象等)都可以被引用。

写在前面:

是想写一个闭包的,因为写的比较细,基于篇幅,所以闭包前面关于变量的部分就单独发出来,到时候放个链接引进来,js闭包虽然是一个被讲烂的东西,但其实很多人刚接触这个概念也不太懂,所以希望写一篇接地气,能够让一个从前不知道这个内容的小伙伴能够清楚的理解闭包这个东西。so,本文是基于闭包的变量部分。


首先需要理解变量的作用域(变量的有效范围):

变量的作用域有两种:全局变量和局部变量。

全局变量很好理解:就是我们平时没有再函数内部声明的那些变量,在全局中任何地方(函数,对象等)都可以被引用。

栗子:

var n=999;
  function f1(){
    alert(n);
  }
  f1(); // 输出999,说明全局变量n在函数内部被读取

局部变量:在函数内部声明的变量。函数内部的变量,外部无法读取。

栗子:

function f1(){
    var n=999;
  }
  alert(n); // 没有定义,说明函数内部的变量,外部无法读取。

在函数内部声明变量没有使用var,实际上是声明了一个全局变量,前提是需要先调用函数(闭包函数中,也是全局变量。)!

栗子:

var func1=function(){
         a1=1;
        console.log(a1); //输出:1
        function func2() {//func2()是一个闭包
            a2=2;
            console.log(a2);
        }
        func2();//闭包函数中的变量在调用函数之后,变量也是全局变量
        console.log(a2);//输出2
    };
    func1();//调用函数,才会使变量生效
    console.log(a1);//输出1
     console.log(a2);//输出2,说明闭包中没有用var声明的变量也是全局变量。

上面栗子中在函数里面声明变量没有用var,在调用函数之后,a1,a2都能有效输出,看完栗子之后,相信你们对变量的作用域也有一些了解了,我们总结一下:


变量作用域,js高级程序设计(红宝书)中的解释:

内部环境可以通过作用域链访问所有的外部环境,但外部环境不能访问内部环境中的任何变量和函数。这些环境是线性、有次序的。每个环境都可以向上搜索作用域链,以查询变量和函数名;

意思就是:比如函数的局部环境可以访问到外界所有的变量的函数,而且环境的搜索是先从自己本身的环境开始,一级一级往上搜索,这样由多个执行上下文的变量对象构成的链表就叫做作用域链。

关于查找变量,红宝书中有一句话是这样的:

标识符解析是沿着作用域链一级一级地搜索标识符的过程。搜索过程始终从作用域链的前端开始,然后逐级的向后查找,直至找到标识符位置(如果找不到标识符,通常会导致错误的发生、)

ps:标识符指的是变量的名字,作用域链的前端指的是当前执行代码所在环境的变量对象。

作用域链的用途:

保证对执行环境有权访问的所有变量和函数的有序访问

红宝书中的作用域链栗子:

var color = 'blue';
function text1(){
    var anotherColor = 'red';
    function text2(){
        var tempCplor = anotherColor;
        anotherColor = color;
        //这里可以访问到color、anotherColor和tempColor
    }
    //这里可以访问color和anotherColor,但不能访问到tempColor
    text2();
}
//这里只能访问到color
text1();

解析(画重点,这里关于作用域讲的比较详细,看完这个作用域就了解差不多):

以上代码一共涉及三个执行环境:全局环境,text1()的局部环境和text2()的局部环境。

1.全局环境中有一个变量color和一个函数text1()。

2.text1()的局部环境中有一个anotherColor变量和一个text2()的函数,但它可以访问到全局环境中的变量color。

3.text2()的局部环境有一个变量tempColor,该变量只能在text2()自身的环境中被访问到。这是一个闭包,无论是全局环境还是text1()的局部环境都无权访问tempColor。但是在text2()的内部环境中,可以访问到全局环境和text1()中的所有变量,因为这两个环境是text2()的父执行环境。

这个作用域链为:

image.png

只是把函数的名字改了,图方便

ps:函数参数也被当做变量来对待,因此其访问规则与执行函数中的其他变量相同。

以上出自红宝书,自己修改了一丢丢,红宝书还是神器啊,常看常新,每次都会有新发现。


关于变量的生存周期:

1.全局变量的生存周期是永久的,除非我们主动销毁。

ps:变量永久生存,且可以随时调用,但是使用的时候要适度,正是因为它的生命周期长,所以将占据更多的内存,如果声明的变量都是全局变量,当项目比较大的时候,就可能出现性能问题,养成一个好的习惯还是有必要的。

2.而对于在函数内用 var 关键字声明的局部变量来说,当退出函数时,这些局部变量即失去了它们的价值,它们都会随着函数的调用的结束而销毁。

ps:调用函数结束,局部变量确实会销毁。但并不是完全销毁,而是一直函数的内部环境中存活着,当函数再度被调用时,变量就“复活”了,所以局部变量还是非常方便的,不会影响二次使用。

值得注意的是:在局部环境中,出现全局变量与局部变量重名的时候,起作用的是局部变量,全局变量被屏蔽掉。这是因为上文说过作用域链的原因,先由局部开始搜索变量,当局部找到该变量的时候,就不会再我继续往父级找变量了。


目录
相关文章
|
7天前
|
JavaScript 前端开发 开发者
JavaScript的变量提升是一种编译阶段的行为,它将`var`声明的变量和函数声明移至作用域顶部。
【6月更文挑战第27天】JavaScript的变量提升是一种编译阶段的行为,它将`var`声明的变量和函数声明移至作用域顶部。变量默认值为`undefined`,函数则整体提升。`let`和`const`不在提升范围内,存在暂时性死区。现代实践推荐明确声明位置以减少误解。
14 2
|
2天前
|
JavaScript
js export 对外输出常量、变量和函数
js export 对外输出常量、变量和函数
11 5
|
1天前
|
存储 JavaScript 前端开发
|
6天前
|
JavaScript 前端开发
JavaScript中的var变量详解:定义、提升与注意事项
JavaScript中的var变量详解:定义、提升与注意事项
11 2
|
9天前
|
自然语言处理 JavaScript 前端开发
JavaScript闭包是函数访问外部作用域变量的能力体现,它用于封装私有变量、持久化状态、避免全局污染和处理异步操作。
【6月更文挑战第25天】JavaScript闭包是函数访问外部作用域变量的能力体现,它用于封装私有变量、持久化状态、避免全局污染和处理异步操作。闭包基于作用域链和垃圾回收机制,允许函数记住其定义时的环境。例如,`createCounter`函数返回的内部函数能访问并更新`count`,每次调用`counter()`计数器递增,展示了闭包维持状态的特性。
24 5
|
6天前
|
JavaScript 前端开发
JavaScript变量命名规则及关键字详解
JavaScript变量命名规则及关键字详解
12 1
|
7天前
|
JavaScript 前端开发
JavaScript作用域关乎变量和函数的可见范围。
【6月更文挑战第27天】JavaScript作用域关乎变量和函数的可见范围。全局作用域适用于整个脚本,局部作用域限于函数内部,而ES6引入的`let`和`const`实现了块级作用域。全局变量易引发冲突和内存占用,局部作用域在函数执行后消失,块级作用域提高了变量管理的灵活性。作用域关键在于组织代码和管理变量生命周期。
16 1
|
9天前
|
JavaScript 前端开发
JavaScript中的变量提升(Hoisting)将`var`声明和函数声明提前到作用域顶部,允许在声明前使用
【6月更文挑战第25天】JavaScript中的变量提升(Hoisting)将`var`声明和函数声明提前到作用域顶部,允许在声明前使用。`let`和`const`不完全提升,存在暂时性死区(TDZ),尝试在初始化前访问会出错。函数声明会被提升,但函数表达式不会。
16 3
|
10天前
|
设计模式 JavaScript 前端开发
JS 代码变量和函数的正确写法大分享
在开发中,变量名,函数名一般要做到清晰明了,尽量做到看名字就能让人知道你的意图,所以变量和函数命名是挺重要
13 2
|
17小时前
|
JavaScript
JS 【详解】作用域
JS 【详解】作用域
5 0