【JS学习笔记】第四章变量、作用域和内存问题

JS 变量松散类型的本质,决定了变量只是在特定时间保存特定值的一个名字而已,而不存在定义某个变量的数据类型的规则,因此变量的值及其数据类型可以在脚本的生命周期内发生改变。

  • 基本类型的值是指简单的数据段,引用类型的值指由可能有多个值构成的对象。

  • 基本数据类型有5种:string, number,boolean,null,undefined. 它们按值访问,因此可以操作保存在变量中实际的值。

  • 在赋值给变量时,解析器必须确定这个值是基本类型的值还是引用类型的值。

  • 引用类型的值是保存在内存中的对象。js 不允许直接访问内存中的位置,也就是不能直接操作对象的内存空间。因此,在操作对象时,是在操作对象的引用,而不是实际的对象。

动态属性

对基本类型和引用类型的变量值进行操作的方法不同。
对于引用类型的值,可以为其添加、删除、更改属性和方法:

var person = new Object();
person.name = "Nicholas";
alert(person.name); //"Nicholas"

alert ()是一个函数。通过函数访问属性
如果对象不被销毁或者这个属性不被删除,则这个属性将一直存在。

基本类型的值却不能添加属性。

复制变量值

从一个变量向另一个变量复制基本类型值和引用类型值时,也存在不同。

复制基本类型的值时,会在变量对象上创建一个新值然后把该值复制到为新变量分配的位置上

var num1 =5;
var num2 = num1;
IMG_8065.JPG

复制引用类型的值时,也会将存储在变量对象中的值复制一份放到为新变量分配的空间中。不同在于,这个值的副本是一个指针,这个指针指向存储在堆中的一个对象。复制操作结束后,两个变量引用同一个对象。改变其中一个变量,会影响另一个。

IMG_8066.JPG

传递参数

ECMAScript 中所有函数的参数都是按值传递的。
在向参数传递基本类型的值时,被传递的值会被复制给一个局部变量(即命名参数,arguments对象中的一个元素)。
在向参数传递引用类型的值时,会把值在内存中的地址复制给一个局部变量,因此这个局部变量的变化会反映在函数的外部。

https://www.zhihu.com/question/27114726

检测类型

检测基本数据类型用 typeof s
如果变量的值是一个对象或null,则会返回object

检测引用类型的值,则用instanceof constructor
示例: alert(person instanceof Object/Array/RegExp) //true or false
所有引用类型的值都是Obeject的实例。因此在检测一个引用类型的值和Object构造函数时,instanceof 操作符始终返回true。如果使用instanceof 操作符检测基本类型的值,则返回false,因为基本类型不是对象。

执行环境及作用域

执行环境,execution context,简称环境,定义了变量或函数有权访问的其他数据,决定了各自的行为。每个执行环境都有一个与之关联的变量对象(variable object),环境中定义的所有变量和函数都保存在这个对象中。编写代码无法访问这个对象,但解析器在处理数据时会在后台使用它。

全局执行环境是最外围的一个执行环境。在web浏览器中,全局执行环境是Window对象,所有全局变量和函数都是作为 Window的属性和方法创建的。某个执行环境中所有代码执行完毕后,该执行环境被销毁,保存在其中的所有变量和函数定义也随之销毁。

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

当代码在一个环境中执行时,会创建变量对象的一个作用域链(scope chain)。用途是保证对执行环境有权访问的所有变量和函数的有序访问。作用域链前端,是当前执行代码所在环境的变量对象。如果这个环境是函数,则将其活动对象(activation object)作为变量对象。活动对象最开始只包含一个变量,即arguments对象。作用域链中下一个变量对象来自包含(外部)环境,再下一个变量对象在来自下一个包含环境,最后是全局执行环境。

标识符解析是沿着作用域链一级一级地搜索标识符的过程。

延长作用域链

可以在作用域链的前端临时增加一个变量对象,该变量对象会在代码执行后被移除。

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

with 语句接收的是location对象,因此其变量对象中就包含了 location对象的所有属性和方法,
href实际上是location.href

没有块级作用域

在其中c语言中,由花括号封闭的代码都有自己的作用域,因而支持根据条件来定义变量。比如以下例子中,color会在if语句执行完毕后被销毁

if(true) {
   var color = "blue";
  }
  alert(color); //"blue"

但在js中,if语句中的变量声明会将变量添加到当前的执行环境,这里是全局环境。

for (var i=0;i<10;i++){
      doSomething(i);
}

alert(i);//10

对于块级作用域的语言来说,for语句初始化变量的表达式所定义的变量,只会存在于循环的局部环境。而对于JS来说,变量i即使在for循环结束后,也依旧会存在于循环外部的执行环境中。

  1. 变量声明
    使用var声明的变量会自动被添加到被接近的环境中,在函数内部,最接近的环境就是函数的局部环境。下面例子中,sum被var声明,添加到add()函数的局部环境中,因此在全局环境中访问时,是导致错误。这里如果省略var,则sum会被添加到全局环境中。
function add(num1,num2) {
    var sum =num1 + num2 ;
    return sum;
}
var result = add(10,20);//30
alert(sum); //导致错误

访问局部变量要比访问全局变量更快,因为不用向上搜索作用域链。

垃圾收集

js具有自动垃圾收集机制,不用手动跟踪内存的使用情况。

函数中的局部变量只在函数执行的过程中存在,因此在函数执行完毕后,对其打上标记,将来回收其内存。

标记清除

mark-and-sweep
当变量进入环境时(例如在函数中声明一个变量),将这个变量标记为进入环境,而当变量离开环境时,则将其标记为离开环境。

垃圾收集器在允许的时候回给存储在内存中的所有变量都加上标记,然后去掉环境中的变量以及被环境中变量引用的变量的标记,在此之后,再被加上标记的变量将被视为准备删除的变量。最后,垃圾收集器完成内存清楚工作,销毁那些带标记的值回收其占用的内存空间。

另一种是引用计数

性能问题

当环境中存在256个变量,4096个对象,64K的字符串,任意一种都会触发垃圾回收机制,但如果环境中一直都有这么多变量存在,那么垃圾回收器会一直工作。

因此,如果垃圾回收器回收的内存分配量低于程序占用内存的15%,说明大部分内存不可被回收,那么把临界条件翻倍,如果回收的内存高于85%,说明大部分内存该清理了,把临界值重置为默认值。

管理内存

JS中,分配给web浏览器的可用内存数量通常比分配给桌面应用程序的少,处于安全考虑。内存限制问题不仅会影响给变量分配内存问题,还会影响调用栈以及在一个线程中能够同时执行的语句数量。

因此,为了让页面获得更好的性能,我们需要占用最少的内存,优化内存占用,只为执行中的代码保存必要的数据。一旦数据不再有用,可将其值设置为null释放其引用,这个做法叫做解除引用(dereferencing)。一般用于释放全局变量的内存,因为局部变量在离开执行环境时自动被解决引用。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,287评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,346评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,277评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,132评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,147评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,106评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,019评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,862评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,301评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,521评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,682评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,405评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,996评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,651评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,803评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,674评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,563评论 2 352

推荐阅读更多精彩内容