基础范例和援用范例的值
ECMAScript变量可以包括两种差别数据范例的值:基础范例值和援用范例值。基础范例值指的是简朴的数据段,而援用范例的值指那些可以有多个值组成的对象。
动态的属性
var person = new Object();
person.name = "Nicholas";
alert(person.name); // Nicholas
var name = "Nicholas";
name.age = 27;
alert(name.age); // undefined
这申明只能给援用范例值动态增加属性。
复制变量值
var num1 = 5;
var num2 = num1;
num1中保留的值是5.当运用num1的值来初始化num2时,num2中也保留了值5.但num2中的5与num1中的5是完整自力的,该值只是num1中5的一个副本。
var obj1 = new Object();
var obj2 = obj1;
obj1.name = "Nicholas";
alert(obj2.name); // Nicholas
变量obj1保留了一个对象的新实例。然后,这个值被复制到了obj2中;换句话说,obj1和obj2都指向同一个对象。如许,当为obj1增加name属性后,可以经由过程obj2来接见这个属性。
通报参数
function addTen(num){
num +=10;
return num;
}
var count = 20;
var result = addTen(count);
alert(count); // 20, 没有变化
alert(result); //30
例:
function setName(obj){
obj.name = "Nicholas";
}
var person = new Object();
setName(person);
alert(person.name); // "Nicholas"
例:
function setName(obj){
obj.name = "Nicholas";
obj = new Object();
obj.name = "Greg";
}
var person = new Object();
setName(person);
alert(person.name); // "Nicholas"
假如person是按援用通报的,那末person就会自动被修改成指向其name属性值为”Greg”的新对象。
实行环境及作用域
var color = "blue";
function changeColor(){
if(color == 'blue'){
color = 'red';
}else{
color = 'blue';
}
}
changeColor();
alert('color is now' + color); //red
渣滓网络
渣滓接纳
javascript具有渣滓接纳的机制,也就是说,实行环境会担任治理代码实行过程当中运用的内存。其他的不多说,我们来剖析一下函数中局部变量的平常生命周期。局部变量只在函数实行过程当中存在。而在这个过程当中,会为局部变量在栈(或堆)内存上分派响应的空间,以便存储他们的值。然后在函数中运用这些变量,直到函数终了。此时,局部变量就没有存在的必要了,因此可以开释他们所占的内存以供他们运用。如今各大浏览器通经常使用采纳的渣滓接纳有两种要领:标记消灭、援用计数。
标记消灭
这是javascript中最经常使用的渣滓接纳体式格局。当变量进入实行环境是,就标记这个变量为“进入环境”。从逻辑上讲,永久不能开释进入环境的变量所占用的内存,因为只需实行流进入响应的环境,就可以会用到他们。当变量离开环境时,则将其标记为“离开环境”。
渣滓网络器在运转的时刻会给存储在内存中的一切变量都加上标记。然后,它会去掉环境中的变量以及被环境中的变量援用的标记。而在此以后再被加上标记的变量将被视为预备删除的变量,原因是环境中的变量已无法接见到这些变量了。末了。渣滓网络器完成内存消灭事情,烧毁那些带标记的值,并接纳他们所占用的内存空间。
援用计数
另一种不太罕见的渣滓接纳战略是援用计数。援用计数的寄义是跟踪纪录每一个值被援用的次数。当声清楚明了一个变量并将一个援用范例赋值给该变量时,则这个值的援用次数就是1。相反,假如包括对这个值援用的变量又取得了别的一个值,则这个值的援用次数就减1。当这个援用次数变成0时,则申明没有办法再接见这个值了,因此就可以将其所占的内存空间给收回来。如许,渣滓网络器下次再运转时,它就会开释那些援用次数为0的值所占的内存。
然则用这类要领存在着一个题目,下面来看看代码:
function problem(){
var objA = new Object();
var objB = new Object();
objA.someOtherObject = objB;
objB.anotherObject = objA;
}
在这个例子中,objA和objB经由过程各自的属性互相援用;也就是说这两个对象的援用次数都是2。在采纳援用计数的战略中,因为函数实行以后,这两个对象都离开了作用域,函数实行完成以后,objA和objB还将会继承存在,因为他们的援用次数永久不会是0。如许的互相援用假如说很大批的存在就会致使大批的内存泄漏。
我们晓得,IE中有一部分对象并非原生JavaScript对象。比方,其BOM和DOM中的对象就是运用C++以COM(Component Object Model,组件对象)对象的情势完成的,而COM对象的渣滓接纳器就是采纳的援用计数的战略。因此,纵然IE的Javascript引擎运用标记消灭的战略来完成的,但JavaScript接见的COM对象依然是基于援用计数的战略的。说白了,只需IE中触及COM对象,就会存在轮回援用的题目。看看下面的这个简朴的例子:
var element = document.getElementById("some_element");
var myObj = new Object();
myObj.element = element;
element.someObject = myObj;
上面这个例子中,在一个DOM元素(element)与一个原生JavaScript对象(myObj)之间建立了轮回援用。个中,变量myObj有一个名为element的属性指向element;而变量element有一个名为someObject的属性回指到myObj。因为轮回援用,纵然将例子中的DOM从页面中移除,内存也永久不会接纳。
不过上面的题目也不是不能解决,我们可以手动割断他们的轮回援用。
myObj.element = null;
element.someObject = null;
内存治理
运用JavaScript编程,我们平常都不须要管内存接纳的题目,假如说想要写出高水平的代码照样有点题目值得注意。一个重要题目就是分派给WEB浏览器的可用内存一般比分派给桌面应用程序要少。如许做的目标重如果出自于平安方面的斟酌,目标是防备运转JavaScript的网页耗尽悉数体系内存致使体系崩溃。内存限定题目不仅会影响给变量分派内存,同时还会影响挪用栈以及在一个线程中可以同时实行的语句的数目。
因此,确保占用起码的内存可以让页面取得更好的机能。而优化内存占用的最好体式格局,就是实行中的代码只保留必要的数据。一旦数据不在有效,最好经由过程将其值设置为null来开释其援用——这个做法叫消除援用。这一做法适合于大多数全局变量和局部变量的属性。局部变量会在他们离开实行环境的时刻自动被消除援用,下面来看看代码:
function createPerson(name){
var localPerson = new Object();
localPerson.name = name;
return localPerson;
}
var globalPerson = createPerson("Tracy");
globalPerson = null; //手工消除援用
在这个例子中,变量globalPerson取得了createPerson()函数的返回值。在createPerson()函数内部,我们创建了一个对象并将其值赋给局部变量localPerson,然后又为局部变量增加了一个名为name 的属性。末了,当挪用这个函数的时刻,localPerson以函数值的情势返回并赋值给globalPerson。因为localPerson在createPerson()函数实行终了后就离开了实行环境,因此无需我们显现地去为他们消除援用。然则关于globalPerson而言,则须要我们不运用它的时刻手动为他消除援用。
不过,消除一个值的援用并不意味着自动接纳该值所占的内存。消除援用的真正作用是让值离开实行环境,以便渣滓网络器下次运转时将其接纳。