变量、作用域链和内存问题

基本类型和引用类型

如果从一个变量向另一个变量复制基本类型的值,会在变量对象上创建一个新值,然后把该值复制到为新变量分配的位置上。
当从一个变量向另一个变量复制引用类型的值时,同样也会将存储在变量对象中的值复制一份放到为新变量分配的空间中。不同的是,这个值的副本实际上是一个指针,而这个指针指向存储在堆中的一个对象。复制操作结束后,两个变量实际上将引用同一个对象。

传递参数(只能按值传递)

ECMAScript中所有函数的参数都是按值传递的,也就是说,把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样。基本类型值的传递如同基本类型变量的复制一样,而引用类型值的传递,则如同引用类型变量的复制一样。
<script type="text/javascript">
function setName(obj){
	obj.name = "lisi";
	obj = new Object();
	obj.name = "wangwu";
}
var person = new Object();
setName(person);//对象是按值传递的
console.log(person.name);//lisi
/*
在把person传递给setName()后,其name属性就被设置为"lisi"
当在函数内部重写obj时,这个变量引用的就是一个局部对象。这个局部对象会在函数执行完毕后立即销毁
 */
</script>

执行环境及作用域

执行环境定义了变量或者函数有权访问的其他数据,决定了它们各自的行为。每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。
在Web浏览器中,全局执行环境被认为是window对象,因此所有全局变量和函数都是作为window对象的属性和方法创建的。
作用域链的作用是:保证对执行环境有权访问的所有变量和函数的有序访问
作用域链的变量只能向上访问,变量访问到window对象即被终止,作用域链向下访问变量是不被允许的。
函数声明最先进内存,其他代码依次执行
alert(abc);//输出函数声明
        function abc(){
        console.log("I am student.");
    }


 
var name="liujie";//全局变量
console.log('全局-name:'+name);//当前环境 liujie
 function f1()//内部环境 
{ 
console.log('f1-name:'+name); 
function f2()//内部深层环境 f2是f1的局部变量 
{ 
console.log('f2-name:'+name); 
function f3()//内部深层环境 
{ console.log('f3-name:'+name);
 } 
f3();//liujie
 }
 f2();//liujie }
 f1();//liujie

内部环境可以通过作用域链访问所有的外部环境,但是外部环境不能访问内部环境中的任何变量和函数。

var week='sunday';
   function abc(){
    var month='1yuefen';
    console.log(week);//sunday
   }
   console.log(month);//ReferenceError: month is not defined
   abc();

//自己有就访问自己的,自己没有就访问全局的
    var week='sunday';
    function f1(){
        console.log('f1星期:'+week);//Friday
    }
    function f2(){
        var week='monday';
        console.log('f2星期:'+week);//monday
        f1();
    }
    week="Friday";
    f2();
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
    </head>
    <body>
    <script type="text/javascript">
        (function(){//这里是块级作用域,通常称为私有作用域
            a=5;
            //这里是undefined,是因为下面的var a的变量声明提升造成的,将a的声明提升到作用域的最前方
            console.log(window.a);// undefined
            var a=1;
            console.log(a);//1
        })();
    </script>
    </body>
</html>

垃圾收集

JavaScript具有自动垃圾收集机制,也就是说,执行环境会负责管理代码执行过程中使用的内存。在编写程序时,开发人员不用再关心内存使用问题,所需内存的分配以及无用内存的会受完全实现了自动管理。
原理:找出那些不再继续使用的变量,然后释放其占用的内存。为此,垃圾收集器会按照固定的时间间隔周期性地执行这一操作。

最常用的垃圾收集机制:标记清除

垃圾收集器在运行的时候回给存储在内存中的所有变量都加上标记。然后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记。而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。最后,垃圾收集器完成内存清除工作,消除那些带标记的值并回收它们所占用的内存空间。

<span style="font-weight: normal;"><script type="text/javascript">
	/*
	循环引用:指的是对象A中包含一个指向对象B的指针,而对象B中也包含一个指向对象A的引用
	这个例子中,objectA和objectB通过各自的属性相互引用;这两个对象的引用次数都是2.
	在采用标记清除策略的实现中,由于函数执行之后,这两个对象都离开了作用域,因此这种相互引用不是问题
	但在引用计数策略的实现中,当函数执行完毕后,objectA和objectB还会继续存在,因为他们的引用次数永远不会是0。假如这个函数被重复多次调用,就会导致大量的内存得不到回收。
	*/
function fn(){
	var objectA = new Object();
	var objectB = new Object();
}
objectA.data = objectB;
objectB.data = objectA;
	</script></span>
<span style="font-weight: normal;"><script type="text/javascript">
	var ele = document.getElementById("some_ele");
	var myObject = new Object();
	myObject.element = ele;
	ele.someObject = myObject;
	/*
	这里DOM元素与原生js对象之间创建了循环引用
	由于存在这个循环引用,即使将例子中的DOM从页面中移除,它也永远不会被回收
	为了避免类似这样的循环引用问题,最好是不在使用它们的时候手工断开原生JavaScript对象与DOM元素之间的连接。
	myObject.element = null;
	ele.someObject = null;
	将变量设置为null意味着切断变量与它以前引用的值之间的连接。当垃圾收集器下次运行时,就会删除这些值并回收它们占用的内存。
	 */
</script></span>

管理内存

确保占用最少的内存可以让页面获得更好的性能。而优化内存占用的最佳方式,就是为执行中的代码只保留必要的数据。一旦数据不再有用,最好通过将其值设置为null来释放其引用。
我们一般只需要将大多数全局变量和全局对象的属性进行解除引用(在我们不需要的时候),局部变量会在它们离开执行环境时自动被解除引用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值