简单谈谈javascript中的变量、作用域和内存问题

【变量】

[1]定义:可变的量,相当于给一个不定的数据起了一个外号。变量是存储信息的容器。
[2]特性:js中的变量是松散类型的,可以保存任何类型的数据。它只是在特定时间用于保存特定值的一个名字而已。由于不存在定义某个变量必须要保存何种数据类型值的规则,变量的值及其数据类型可以在脚本的生命周期内改变。
[3]变量声明:变量可以在声明时赋值,但不能有其他操作,如+=、-=等

var a = 2;//是正确的
var a += 2;//是错误的
var a = 2++;//是错误的,++只能用于变量,不能用于常量

[4]注意:用var操作符定义的变量将成为定义该变量的作用域中的局部变量。若省略var操作符,可以创建一个全局变量,但在严格模式下会抛出 ReferenceError错误

[5]var:使用var声明的变量会自动被添加到最接近的环境中。如果初始化变量时没有使用var声明,该变量会自动被添加到全局环境。在严格模式下,初始化未经声明的变量会导致错误。
[6]局部变量:如果局部环境中存在同名标识符,就不会使用位于父环境中的标识符。任何位于局部变量color的声明之后的代码,如果不使用window.color都无法访问全局color变量

【标识符】

[1]定义:变量、函数、属性的名字,或者函数的参数。
[2]注意:
  [2.1]第一个字符必须是一个字母、下划线或一个美元符号。其他字符可以是字母、下划线、美元符号或数字[不能出现中划线]
  [2.2]标识符中的字母也可以包括拓展的ASCII或Unicode字母字符,可以使用中文
  [2.3]标识符应采用小驼峰格式,第一位应该是数据的类型,常见的标识如下:

    数组     a   Array aItems
    布尔值    b   Boolean bIsComplete
    浮点数    f    FLoat fPrice
    函数     fn   Function fnHandler
    整数     i    Integer iItemCount
    对象     o   Object oDIv1
    正则表达式  re   RegExp reEmailCheck
    字符串     s    String sUserName
    变量     v   Variant vAnything

  [2.4]不能把关键字、保留字、true、false和null用作标识符
  [2.5]对于不符合标识符命名规则的属性如background-color应写为大括号方式[backgroundColor]
[3]标识符解析:标识符解析是沿着作用域链一级一级地搜索标识符的过程。搜索过程始终从作用域链的前端开始,然后逐级地向后回溯,直到找到标识符为止(如果找不到标识符,表示标识符尚未声明,通常会导致错误发生)。
  [3.1]如果局部环境中存在着同名标识符,就不会使用父环境中的标识符
    e.g. 全局和局部有同名标识符color,任何位于局部变量color的声明之后的代码,如果不使用window.color都无法访问全局color变量
  [3.2]JavaScript引擎在优化标识符查询方面做得不错,访问全局变量和局部变量的时间差别可以忽略不计

【作用域】(也称为执行环境)

  [注意]javascript中没有块级作用域 
[1]执行环境:执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。每个执行环境都有一个与之相关联的变量对象。环境中定义的所有变量和函数都保存在这个对象中。

[2]全局执行环境:
  [2.1]全局执行环境是最外围的一个执行环境,在web浏览器中,全局执行环境被认为是window对象。因此所有全局变量和函数都是作为window对象的属性和方法创建的。全局执行环境直到应用程序退出例如关闭网页或浏览器时才会被销毁
  [2.2]一个页面就相当于一个全局作用域。不论是页面中的js代码,还是引用的外部js文件,最终都会按照在页面中的先后依次解析。

[3]函数执行环境:每个函数都有自己的执行环境,当执行流进入一个函数时,函数的环境就会被推入一个环境栈中,而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境。

[4]作用域链:当代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域链的作用是保证对执行环境有权访问的所有变量和函数的有序访问。作用域的前端始终都是当前执行的代码所在环境的变量对象。如果这个环境是函数,则将其活动对象作为变量对象。活动对象在最开始时只包含一个变量,即arguments对象(这个对象在全局环境中是不存在的)。作用域链中的下一个变量对象来自包含环境,而再下一个变量对象则来自下一个包含环境。这样,一直延续到全局执行环境;全局执行环境的变量对象始终都是作用域链中的最后一个对象。

  [4.1]作用域链的特点:内部环境可以通过作用域链访问所有的外部环境,但外部环境不能访问内部环境中的任何变量和函数。这些环境之间的联系是线性、有次序的。每个环境都可以向上搜索作用域链,以查询变量和函数名;但任何环境都不能通过向下搜索作用域链而进入另一个执行环境。

[5]延长作用域链:

  [5.1]try-catch语句:catch块会创建一个新的变量对象,其中包含的是被抛出的错误对象的声明
  [5.2]with语句:会将指定的对象添加到作用域链中

function buildUrl(){
  var qs = '?debug=true';
  with(location){
    var url = href + qs;
  }
  return url;
}

【垃圾回收】:javascript具有自动垃圾收集机制,执行环境会负责管理代码执行过程中使用的内存。

[1]垃圾回收机制:找出那些不再继续使用的变量,然后释放其占用的内存,垃圾收集器会按照固定的时间间隔,或代码执行中预定的收集时间,周期性地执行这一操作

[2]垃圾收集标记无用变量的两种策略

  [2.1]标记清除,标记“进入环境”和“离开环境”。离开作用域的值将被自动标记为可以回收,因此将在垃圾收集期间被删除
  [2.2]引用计数,跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数就是1,如果同一个值又被赋给另一个变量,则该值的引用次数加1,相反,如果包含对这个值的引用的变量又取得了另外一个值,则这个值的引用次数减1,当这个值的引用次数为0时,则说明没有办法再访问这个值了,因此就可以将其占用的内存空间回收回来。
    [2.2.1]引用计数的问题:循环引用:对象A中包含一个指向对象B的指针,对象B中也包含一个指向对象A的指针
    [2.2.2]IE:IE中有一部分对象并不是原生js对象,例如,其BOM和DOM中的对象就是使用c++以COM对象的形式实现,而COM对象的垃圾回收机制采用的就是引用计数策略

var element = document.getElementById('some_element');
var myObject = new Object();
myObject.element = element;
element.someObject = myObject;

    解决办法:为了避免类似这样的循环引用,最好是在不使用它们的时候手工断开

myObject.element = null;
element.someObject = null;   
    为了解决此问题,IE9把BOM和DOM对象都转换成了真正的js对象

【内存管理】

[1]主要问题:分配给web浏览器的可用内存数量通常要比分配给桌面应用程序的少,目的是防止运行js的网页耗尽全部系统内存而导致系统崩溃。内在限制问题不仅会影响给变量分配内存,同时还会影响调用栈以及在一个线程中能够同时执行的语句数量

[2]优化方式:为执行中的代码只保存必要的数据。一旦数据不再有用,最好通过将其值设置为null来释放其引用,这种做法叫解除引用。这一做法适用于大多数全局变量和全局对象的属性以及循环引用变量,局部变量会在它们离开执行环境时自动被解除引用。

解除变量的引用并不意味着自动回收该值所占用的内存。解除引用的真正作用是让值脱离执行环境,以便垃圾收集器下次运行时将其回收。

(0)

相关推荐

  • javascript 的变量、作用域和内存问题

    javascript 的变量.作用域和内存问题 (一)JavaScript变量可以用来保存两种类型的值:基本类型值和引用类型值.基本类型的值源自以下5种基本数据类型:Undefined.Null.Boolean.Number和 String.基本类型值和引用类型值具有以下特点: 1.基本类型值在内存中占据固定大小的空间,因此被保存在栈内存中: 2.从一个变量向另一个变量复制基本类型的值,会创建这个值的一个副本: 3.引用类型的值是对象,保存在堆内存中: 4.包含引用类型值的变量实际上包含的并不是

  • js变量、作用域及内存详解

    基本类型值有:undefined,NUll,Boolean,Number和String,这些类型分别在内存中占有固定的大小空间,他们的值保存在栈空间,我们通过按值来访问的. (1)值类型:数值.布尔值.null.undefined. (2)引用类型:对象.数组.函数. 如果赋值的是引用类型的值,则必须在堆内存中为这个值分配空间.由于这种值的大小不固定(对象有很多属性和方法),因此不能把他们保存到栈内存中.但内存地址大小是固定的,因此可以将内存地址保存在栈内存中. <script type="

  • JavaScript 变量、作用域及内存

    JS变量是松散型的(不强制类型)本质,决定了它只是在特定时间用于保存特定值的一个名字而已; 由于不存在定义某个变量必须要保存何种数据类型值的规则,变量的值及其数据类型可以在脚本的生命周期内改变; 一 变量及作用域 1.基本类型和引用类型 // JS变量包含两种不同的数据类型的值:基本类型值和引用类型值; // 1.基本类型值:保存在栈内存中的简单数据段;即这种值完全保存在内存中的一个位置; // 基本类型值包含:Undefined|Null|Boolean|Number|String; // 这

  • 简单谈谈javascript中的变量、作用域和内存问题

    [变量] [1]定义:可变的量,相当于给一个不定的数据起了一个外号.变量是存储信息的容器. [2]特性:js中的变量是松散类型的,可以保存任何类型的数据.它只是在特定时间用于保存特定值的一个名字而已.由于不存在定义某个变量必须要保存何种数据类型值的规则,变量的值及其数据类型可以在脚本的生命周期内改变. [3]变量声明:变量可以在声明时赋值,但不能有其他操作,如+=.-=等 var a = 2;//是正确的 var a += 2;//是错误的 var a = 2++;//是错误的,++只能用于变量

  • 深入解析JavaScript中的变量作用域

    在学习JavaScript的变量作用域之前,我们应当明确几点: •JavaScript的变量作用域是基于其特有的作用域链的. •JavaScript没有块级作用域. •函数中声明的变量在整个函数中都有定义. 1.JavaScript的作用域链首先看下下面这段代码: 复制代码 代码如下: <script type="text/javascript"> var rain = 1; function rainman(){ var man = 2; function inner()

  • JavaScript中的变量作用域介绍

    对于变量的作用域(scope),C.Java等语言采取的是"block scope"的方式.与之不同,JavaScript所采取的是"function scope"的方式 - 变量的作用域仅由所处的function决定,与if.for等逻辑块无关.比如,以下这个例子展示了JavaScript中与C.Java等语言不一样的行为: 复制代码 代码如下: function(){   var s = 42;//s is visible throughout function

  • 简单谈谈Javascript中类型的判断

    数据类型的判断有这么几种方式 1.一元运算符 typeOf 2.关系运算符 instanceof 3.constructor 属性 4.prototype属性 一.typeof typeof的返回值有以下几种 类型 结构 Undefined "undefined" Null "object" (见下方) 布尔值 "boolean" 数值 "number" 字符串 "string" Symbol (ECMAS

  • javascript中的变量作用域以及变量提升详细介绍

    变量作用域"一个变量的作用域表示这个变量存在的上下文.它指定了你可以访问哪些变量以及你是否有权限访问某个变量." 变量作用域分为局部作用域和全局作用域. 局部变量(处于函数级别的作用域)不像其他对面对象的编程语言(比方说C++,Java等等),javascript没有块级作用域(被花括号包围的):当是,javascript有拥有函数级别的作用域,也就是说,在一个函数内定义的变量只能在函数内部访问或者这个函数内部的函数访问(闭包除外,这个我们过几天再写个专题). 函数级别作用域的一个例子

  • 简单谈谈javascript中this的隐式绑定

    我们先来看一个例子 function foo() { console.log( this.a ); } var obj = { a: 2, foo: foo }; obj.foo(); // 2 this指向了obj,因为foo执行时的call-site(可以理解为调用时所在作用域)在obj上面.注意是运行的时候,和在哪里声明的没有关系. call-site and call-stack call-site姑且理解为调用域,call-stack为调用栈.如下代码可以辅助我们理解 function

  • 简单谈谈JavaScript变量提升

    目录 前言 1. 什么变量提升? 2. 为什么会有变量提升? (1)提高性能 (2)容错性更好 3. 变量提升导致的问题 (1)变量被覆盖 (2)变量没有被销毁 4. 禁用变量提升 5. JS如何支持块级作用域 (1)创建执行上下文 (2)执行代码 6. 暂时性死区 总结 前言 在 ECMAScript6 中,新增了 let 和 const 关键字用来声明变量.在前端面试中也常被问到 let.const和 var 的区别,这就涉及到了变量提升.暂时性死区等知识点.下面就来看看什么是变量提升和暂时

  • 简单谈谈python中的语句和语法

    python程序结构 python"一切皆对象",这是接触python听到最多的总结了.在python中最基层的单位应该就是对象了,对象需要靠表达式建立处理,而表达式往往存在于语句中,多条语句组成代码块,多个代码块再组成一整个程序.python的核心其实是由语句和表达式组成.所以在这里简单探讨一下python中的语句和表达式. 因为以后可能会接触到两个版本的python,所以这里讲一讲python2与python3的语句差异: 1.python2中没有nolocal语句. 2.prin

  • JavaScript变量作用域及内存问题实例分析

    本文实例讲述了JavaScript变量作用域及内存问题.分享给大家供大家参考,具体如下: 学习要点: 1.变量及作用域 2.内存问题 JavaScript的变量与其他语言的变量有很大区别.JavaScript变量是松散型的(不强制类型)本质,决定了它只是在特定时间用于保存特定值的一个名字而已.由于不存在定义某个变量必须要保存何种数据类型值的规则,变量的值及其数据类型可以在脚本的生命周期内改变. 一.变量及作用域 1.基本类型和引用类型的值 ECMAScript变量可能包含两种不同的数据类型的值:

  • 谈谈JavaScript中的函数

    JS中的函数简介 JS中的函数是一种通过调用来完成具体业务的一段代码块.最核心的目的是将可重复执行的操作进行封装,然后供调用方无限制的调用. JS中的函数的定义 JS中函数定义,有如下两种形式: 方式1 function f1(){} //函数声明,f1为函数名,可以将其理解为变量f1指向一个函数 function f2(){return 100;}//函数允许有返回值 function f3(a,b){}//函数中可以定义多个参数,无需指定变量类型 方式2 var f4=function(){

随机推荐