视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
JavaScript中关于变量作用域和内存问题的理解
2020-11-27 19:32:53 责编:小采
文档


1.1复制变量值

引用类型实际上在复制的时候,传递的是函数的指针,复制完成后,实际两个变量引用的都是同一个堆内存中的对象,改变这个对象,两个变量的值也会同步改变。

1.2传递参数

函数的参数都是按值传递的。其实我认为这种说法多少还是有些抽象。总结起来不如这样说。当传递给函数的变量是值类型时,那么传递给函数的这个原始变量的值不会随函数内部的影响而改变。当传递给函数的变量是引用类型(object)时,那么传递给函数的这个原始变量的引用不会随函数内部的影响而改变。其实这里不是太容易理解,比如举个例子来说明

 var obj = {
 name: 'andy'
 }

 function ChangeObj(val) {
 val.age = '25'
 val = {
 name:'zakas',
 age:40
 }
 return val;
 }
 ChangeObj(obj); // {name:'zakas',age:40}
 console.log(obj) // {name:'andy',age:25}

上面这个例子中,函数中val的内存地址变了(引用变了),如果函数是按引用传递的话,那么val的引用就是obj的引用,val的应用变了,obj的引用也会跟随变化,所以obj的结果也应该是{name:'zakas',age:40}。而按值传递的话,obj赋值给val它的引用,但是他俩的引用是不关联在一起的,val引用的改变并不会影响obj的引用地址。

函数的形参就是函数作用域中的局部变量。当函数运行完是会被销毁的。

1.3检测类型

instanceof 可以进行引用类型的更明确的检测。所以值类型在instanceof总全是false,值类型也没必要用其方法进行检测。instanceof只能区分Array Object 和 RegExp

2.执行环境

每个执行环境都有一个变量对象,变量对象的概念很重要。它是作用域中所有定义的变量的一个大的集合;每个执行环境都有一个变量对象,存储着我们定义的所有变量,但是这个变量对象我们访问不到,但解析器处理数据时会在后台使用它。

 function A() {
 var tempA;
 function B() {
 var tempB;
 function C() {
 var tempC
 }
 }
 }

B()的作用域链中包含3个对象,一个是自己的变量对象,还有A的变量对象和全局变量对象。A()中的作用域链包含2个对象,一个A()自己的变量对象,还有就是全局变量对象。因此A访问不了B的变量,只能访问自己的和全局的变量。但是B不但能访问自己的变量,也能访问A和全局作用域下的变量。

2.1延长作用域链

with

With相当于创造了一个新的变量对象在当前作用域的上方。例如:

 var obj = {
 name:'andy',
 sex:'man',
 hobby:'game'
 }
 function fn() {
 with(obj) {
 fnName = name;
 fnSex = sex;
 fnHobby = hobby;
 }
 console.log(fnName,fnSex,fnHobby) // andy,man,game
 }
 fn()

With方法会造成性能的严重损失,所以一般不建议用

2.2无块级作用域

必须要知道这个概念,作用和区别,最老生常谈的一个问题:

for(var i =0 ; i < 10 ; i++ ) {
 setTimeout(function(){
 console.log(i);
 },0)
}

在理解这个问题的前提下,首先要知道定时器是异步的,即使是0,也要先放到缓存区中,当其他程序自上而下执行完毕之后再去调用。所以在其他程序自上而下执行完毕之后,由于没有块级作用域,i是全局的,已经变成10了,所以输出10个10。如果把i改为存在块级作用域的let,那么问题就迎刃而解了。

for(let i =0 ; i < 10 ; i++ ) {
 setTimeout(function(){
 console.log(i);
 },0)
}

2.3垃圾收集

JavaScript具有自动垃圾收集机制

使用值的过程中,其实是相当于对变量分配的内存进行写入和读取的操作。JavaScript在创建变量的过程会分配内存,当变量不用时会自动释放掉,这个过程叫做垃圾回收机制,但是这个自动是混乱的根源,很多开发者因此觉得不用太关心内存问题,这是错误的。

原理:垃圾处理器会在默认情况下周期的进行检测,找出那些不用的变量,然后释放其内存。
回收策略:在局部环境中,函数调用完之后,垃圾收集器会跟踪哪个变量有用,哪个变量没有用,对于没用的变量,打上标记,以备回收其内存,但是标记的方法通常有另两个策略:

  • 标记清除:从2012年起,所有浏览器全部使用标记清除的方法进行垃圾回收,并且所有对js垃圾回收的改进也是基于标记清除的方法进行算法优化。

  • 引用计数:这个由于存在严重的循环引用问题,所以现在已经基本不用了。

  • 因此,当写的程序占用较少的内存是高性能页面的一个很重要的点。所以当我们写程序时候,一旦数据不用了,最好设置成null来解除引用

    相关文章:

    JavaScript变量作用域和内存问题(二)

    李炎恢Javascript视频教程

    下载本文
    显示全文
    专题