3. 变量、内存、作用域

3.1 基本类型和引用类型的值

ECMAScript 变量可能包含两种不同数据类型的值:基本类型值【Undefined、Null、Boolean、Number 和 String。 这 5 种基本数据类型是按值访问的,因为可以操作保存在变量中的实际的值】和引用类型值【在操作对象时,实际上是在操作对象的引用而不是实际的对象。为此,引用类型的值是按引用访问的】。基本类型值指的是简单的数据段,而引用类型值指那些可能由多个值构成的对象。

  • 动态的属性:

    • 对于引用类型的值,可以添加、更改、删除属性和方法;但是基本类型不可以这么做。

  • 复制变量值:

    • 当复制一个基本类型的值时,会创建一个新的变量副本。两个变量完全独立。

    • 当复制一个引用类型的值时,复制的是一个引用。两个变量都引用一个对象。当改变原变量的值时,新复制的也会改变。

    • var a=[1,2,3]; var b=a; a[0]=0; alert(b); //0,2,3

  • 传递参数:

    • 当传递一个基本类型的值时,是按值传递,不能更改外部的值。

    • 当传递一个引用类型的值时,是引用传递,可以更改外部的值。

  • 检测类型:

    • typeof xxx

    • 变量 instanceof 类型 /pattern/i instanceof RegExp => true

3.2 执行环境和作用域

  • 执行环境(execution context) 是JavaScript中最为重要的一个概念。执行环境定义了变量或函数有权访问的其他数据,决定了他们各自的行为。

  • 每个执行环境都有一个与之关联的变量对象(variable object),环境中定义的所有变量和函数都保存在这个对象中。虽然无法通过代码访问这个对象,但是解析器在处理数据时会在后台使用它。

  • 全局执行环境是最外围的一个执行环境。根据 ECMAScript 实现所在的宿主环境不同(浏览器、Node.js),表示执行环境的对象也不一样。在 Web 浏览器中,全局执行环境被认为是 window 对象,因此所有全局变量和函数都是作为 window 对象的属性和方法创建的。某个执行环境中的所有代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁。

  • 每个函数都有自己的执行环境。当执行流进入一个函数时,函数的环境就会被推入一个环境栈中。而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境。ECMAScript 程序中的执行流正是由这个方便的机制控制着。

  • 当代码在一个环境中执行时,会创建变量对象的一个作用域链(sope chain)作用域链的用途是保证对有权访问的执行环境里的变量和函数的有序访问。作用域链的前端,是当前所执行的代码所在环境的变量对象。如果这个环境是函数,则将其活动对象(activation object)作为变量对象。活动对象最开始只包含一个变量,即arguments对象(不再全局环境中存在)。作用域中的下级各变量对象来自包含(外层)环境,再下一个变量来自下一个包含环境。这样一直延伸到全局执行环境,全局执行换金过得变量对象始终都是作用域链的最后一个对象。

  • 标识符的解析是沿着作用域链一级一级地搜索标识符的过程,搜索过程从作用域链的前端开始,然后逐级地向后回溯,知道找到标识符为止(找不到则发生错误)。

  • 例如:

     /// 下面这段代码中,changeColor()的作用域链中包含两个对象:他自己变量对象(其中定义着arguments对象) 和全局环境的变量对象。在函数内部可以访问变量color就是因为可以再这个作用域链中找到它。
    var color = "blue";
    function changeColor(){
    if (color === "blue"){
    color = "red";
    } else {
    color = "blue";
    }
    }
    changeColor();
    alert("Color is now " + color); //red




    ///以下代码共涉及 3 个执行环境:全局环境、changeColor()的局部环境和 swapColors()的局部环境。
    // 2. 全局环境中有一个变量 color 和一个函数 changeColor()。
    // 1. changeColor()的局部环境中有一个名为 anotherColor 的变量和一个名为 swapColors()的函数,但它也可以访问全局环境中的变量 color。
    // 0. swapColors()的局部环境中有一个变量 tempColor,该变量只能在这个环境中访问到。无论全局环境还是 changeColor()的局部环境都无权访问 tempColor。然而,在 swapColors()内部则可以访问其他两个环境中的所有变量,因为那两个环境是它的父执行环境。
    var color = "blue";
    function changeColor(){
    var anotherColor = "red";
    function swapColors(){
    var tempColor = anotherColor;
    anotherColor = color;
    color = tempColor;
    // 这里可以访问 color、anotherColor 和 tempColor
    }
    // 这里可以访问 color 和 anotherColor,但不能访问 tempColor
    swapColors();
    }
    // 这里只能访问 color
    changeColor();
  • 内部环境可以通过作用域链访问所有的外部环境,但外部环境不能访问内部环境中的任何变量和函数。这些环境之间的联系是线性、有次序的。每个环境都可以向上搜索作用域链,以查询变量和函数名;但任何环境都不能通过向下搜索作用域链而进入另一个执行环境。

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

    • 延长作用域链:

       //虽然执行环境的类型总共只有两种——全局和局部(函数),但还是有其他办法来延长作用域链。就是当执行流进入下列任何一个语句时,作用域链就会得到加长:
      // try-catch 语句的 catch 块;
      // with 语句。
      //这两个语句都会在作用域链的前端添加一个变量对象。对 with 语句来说,会将指定的对象添加到作用域链中。
          对 catch 语句来说,会创建一个新的变量对象,其中包含的是被抛出的错误对象的声明。下面看一个例子。
      function buildUrl() {
      var qs = "?debug=true";
      with(location){
      var url = href + qs;
      }
      return url;
      }

      //with 语句接收的是 location 对象,因此其变量对象中就包含了 location 对象的所有属性和方法,而这个变量对象被添加到了作用域链的前端。
        //buildUrl()函数中定义了一个变量 qs。当在with 语句中引用变量 href 时(实际引用的是 location.href),可以在当前执行环境的变量对象中找到。
        当引用变量 qs 时,引用的则是在 buildUrl()中定义的那个变量,而该变量位于函数环境的变量对象中。至于 with 语句内部,则定义了一个名为 url 的变量,
        因而 url 就成了函数执行环境的一部分,所以可以作为函数的值被返回。
  • 没有块级作用域:

     // 在if语句中定义了变量color,如果在C/C++、Java中,color会在if语句执行完毕后被销毁。但在JavaScript中,if语句中的变量声明会将变量加到当前执行环境中(这里是全局环境)。
    if (true) {
    var color = "blue";
    }
    alert(color); // "blue"


    // 对于有块级作用域的语言来说,for 语句初始化变量的表达式所定义的变量,只会存在于循环的环境之中。而对于 JavaScript 来说,由 for 语句创建的变量 i 即使在 for 循环执行结束后,也依旧会存在于循环外部的执行环境中。
    for(var i = 0; i < 10; i++){
    doSomething();
    }
    alert(i); //


    // 【变量声明】
    // 如果使用 var 声明变量,则会被自动添加到最近的环境中。在函数内部,最接近的环境就是函数的局部环境。如果初始化变量时,没有使用var声明,则该变量会被自添加到全局环境中。


    // 【查询标识符】
    //当在某个环境中引用一个标识符时,必须通过搜索来确定该标识符实际代表什么。搜索过程从作用域链的前端开始,向上逐级查询与给定名字匹配的标识符。如果在局部环境中找到了该标识符,搜索过程停止,变量就绪。如果在局部环境中没有找到该变量名,则继续沿作用域链向上搜索。搜索过程将一直追溯到全局环境的变量对象。如果在全局环境中也没有找到这个标识符,则意味着该变量尚未声明

3.3 垃圾收集

3. Javascript学习笔记——变量、内存、作用域的更多相关文章

  1. javascript学习笔记 - 变量、作用域和内存问题

    一 垃圾收集 javascript具有自动垃圾收集机制.由垃圾收集机制标找出不再使用的变量.按照固定间隔的时间进行销毁,释放内存.  1.找出不再使用的变量的方法,如下: 1-1.标记清除 垃圾回收器 ...

  2. php学习笔记-变量的作用域

    这个东西很难理解,但很重要,我觉得非常容易出错. PHP中的变量按照作用域分为有两种,一种是global,一种是local. 函数内部声明的变量就叫local型变量,只能在函数内部被访问到.一句话,l ...

  3. JavaScript高级程序设计学习笔记--变量、作用域和内存问题

    传递参数 function setName(obj){ obj.name="Nicholas"; obj=new object(); obj.name="Greg&quo ...

  4. JavaScript学习笔记——变量和数据类型

    一.javascript命名规范 1. 严格区分大小写 2. 变量的命名必须以字母或 _或 $开头,余下的部分可以是任意的字母,数字,或者是 _或者是$ 3.不能用关键字或者是保留字命名. 4.jav ...

  5. R语言学习笔记-变量的作用域

    R语言是如何将变量值和变量绑定的 在r语言中,当前的 workspace就是global enviroment,当输入变量名时,首先会在global enviroment中搜索该变量,如有,则将它显示 ...

  6. js学习之变量、作用域和内存问题

    js学习之变量.作用域和内存问题 标签(空格分隔): javascript 变量 1.基本类型和引用类型: 基本类型值:Undefined, Null, Boolean, Number, String ...

  7. JavaScript:学习笔记(7)——VAR、LET、CONST三种变量声明的区别

    JavaScript:学习笔记(7)——VAR.LET.CONST三种变量声明的区别 ES2015(ES6)带来了许多闪亮的新功能,自2017年以来,许多JavaScript开发人员已经熟悉并开始使用 ...

  8. JavaScript学习笔记(十一)——闭包

    在学习廖雪峰前辈的JavaScript教程中,遇到了一些需要注意的点,因此作为学习笔记列出来,提醒自己注意! 如果大家有需要,欢迎访问前辈的博客https://www.liaoxuefeng.com/ ...

  9. Java程序猿JavaScript学习笔记(4——关闭/getter/setter)

    计划和完成这个例子中,音符的顺序如下: Java程序猿的JavaScript学习笔记(1--理念) Java程序猿的JavaScript学习笔记(2--属性复制和继承) Java程序猿的JavaScr ...

随机推荐

  1. [BAT] 通过批处理删除7天前的报告,并删除当前目录下的空文件夹

    set reportPath=D:\AutomationReport cd /d %reportPath% forfiles /p %reportPath% /s /m *.xml /d -7 /c ...

  2. 1056 IMMEDIATE DECODABILITY

    题目链接: http://poj.org/problem?id=1056 题意: 给定编码集, 判断它是否为可解码(没有任何一个编码是其他编码的前缀). 分析: 简单题目, 遍历一遍即可, 只需判断两 ...

  3. 关于SoftReference的使用

    SoftReference一般可以用来创建缓存的,缓存我们经常使用,例如:我们在浏览器中浏览了一个网页后,点击跳转到新的网页,我们想回去看之前的网页,一般是点击回退按钮,那么这个时候之前的网页一般就是 ...

  4. Python相关基础

    1>变量: 2>条件判断与缩进: sex = raw_input("Please input your gender:") if sex == "girl&q ...

  5. python3操作Excel openpyxl模块的使用

    python 与excel 安装模块 本例子中使用的模块为: openpyxl 版本为2.4.8 安装方法请参看以前发表的文章(Python 的pip模块安装方法) Python处理Excel表格 使 ...

  6. memcached整理の内存管理及删除机制

    内存的碎片化 如果用C语言直接malloc,free来向操作系统申请和释放内存时,在不断申请和释放的过程中,形成了一些很小的内存片段,无法再利用.这种空闲但无法利用内存的现象称为内存的碎片化. sla ...

  7. TunnelBroker for EdgeRouter 后记

    最近入手了UBNT EdgeRouter X, 想着用 IPv6在路由上FQ,经过两天折腾,终于正常使用,留下点标记 供后来同学借鉴. TUNNEL的注册和配置,可以完全按这篇文章来: TunnelB ...

  8. Linq实战 之 DataSet操作详解

    Linq实战 之 DataSet操作详解  一:linq to Ado.Net 1. linq为什么要扩展ado.net,原因在于给既有代码增加福利.FCL中在ado.net上扩展了一些方法. 简单一 ...

  9. 安装MySQL提示:应用程序无法正常启动(0xc000007b)

    转:https://blog.csdn.net/zztingfeng/article/details/80155624 解决:在百度上下载DirectX修复工具(增强版),修复即可. 链接:http: ...

  10. MSSQL Server中partition by与group by的区别

    在使用over等开窗函数时,over里头的分组及排序的执行晚于“where,group by,order by(但此排序顺序优先级是最高的)”的执行. ①group by 列名 合并(列值相同的并作一 ...