JavaScript笔记:变量、作用域和内存问题

根据ECMA-262的定义,javascript的变量和其他语言的变量有很大区别。javascript松散变量的本质,决定了它只是在特定时间内保存着特定值的名字而已。由于不存在某个变量必须要保存某个特定类型的值的规则,一个变量的值和类型可以在脚本的生命周期内改变。

1、基本类型和引用类型的值

ECMAScript变量可能包含两种不同数据类型的值:基本类型和引用类型。
基本类型值指的是简单的数据段,引用类型值指的是那些可能由多个值组成的对象。
基本数据类型包括:Undefined Null Boolean Number String。是按值访问的。
引用类型的值是保存在内存中的对象。和其它语言不同,JavaScript不允许直接访问内存中的位置,也就是说,不能直接操作对象的存储空间。在操作对象时,实际上是在操作对象的引用而不是对象。

1、动态的属性

只能为引用类型添加属性,基本类型添加的属性我们访问不到:

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

var name = "Nicholas";
name.age = 27;
alert(name.age);      //undefined

2、复制变量值

引用类型的复制只是复制了地址,相当于多了一个指向这块内存的引用。

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

3、传递参数

ECMAScript中所有函数的参数都是值传递的。
在向参数传递基本类型的值时,被传递的值会赋值给一个局部变量。在向参数传递引用类型的值时,会把这个值在内存中的地址复制给一个局部变量,因此这个局部变量的变化,会反映到函数外面。
例子:

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"

4、检测类型

var s = "Nicholas";
var b = true;
var i = 22;
var u;
var n = null;
var o = new Object();
alert(typeof s);
alert(typeof i);
alert(typeof b);
alert(typeof u);
alert(typeof n);
alert(typeof o);
// 输出结果
//string
//number
//boolean
//undefined
//object
//object

typeof是检测基本数据类型的好帮手,但是对于引用类型,我们应该使用instanceof方法:

alert(person instanceof Object);   
alert(colors instanceof Array);
alert(pattern instanceof RegExp); 

当然,如果用instance来检测基本类型,则始终会返回false。

2、执行环境和作用域

执行环境,是JS中很重要的一个概念。执行环境定义了函数或者变量有权访问的其它数据。

在web浏览器中,全局执行环境被认为是window对象。

某个执行环境中的所有代码运行完毕后,该环境被销毁,其中的代码和函数也都被销毁(全局环境则当应用程序退出时才被销毁)。

每个函数都有自己的执行环境。当执行流进入一个函数时,函数的环境会被推入一个环境栈中。函数执行完毕后,环境从栈中弹出,把控制权返还给之前的环境。

当代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域链的作用,是保证对执行环境有权访问的变量和函数的有序访问。

标识符解析是沿着作用域链一级一级的搜索标识符的过程。搜索过程从作用域链的最前端开始(当前执行环境),直到找到标识符为止,如果找不到,则通常会报错。
例子:

var color = "blue";
function changeColor(){
    var anotherColor = "red";
    function swapColors(){
        var tempColor = anotherColor;
        anotherColor = color;
        color = tempColor;
        //可访问 color anotherColor tempColor 
    }
    //可访问color anotherColor,不可访问tempColor
    swapColors();
}
//只能访问color 
changeColor();

1、延长作用域链

当执行流进入下面任意一个语句时,作用域链就会得到加长。
1、try-catch 语句的catch块
2、with语句

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

2、没有块级作用域

在其它语言中,由花括号包裹的部分就是一个独立的执行环境,括号内的语句执行完毕后,里面定义的变量会被销毁。然而,JS没有块级作用域的概念,就导致了下面这样的代码也不会报错。

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

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

1、声明变量

使用var声明的变量会被自动加入到最近的执行环境中去。如果初始化时没有使用var声明,则改变量就会被自动加入到全局变量中。

2、查询标识符

查询顺序是沿着作用域链向上搜索:

// 实例代码1
var color = "blue";
function getColor(){
    return color;
}
alert(getColor());  //"blue"

// 实例代码2
var color = "blue";
function getColor(){
    var color = "red";
    return color;
}
alert(getColor());  //"red"

3、垃圾收集

JS具有自动垃圾清理的机制,也就是说,执行环境会负责管理代码执行过程中的内存。这种垃圾收集的机制的原理其实很简单:找出那些不再使用的变量,然后释放掉它们占用的内存。为此,垃圾收集器会周期性的执行这个操作。

1、标记清除

JS最常用的垃圾收集方式就是标记清除。当一个变量进入环境时,就将变量标记为“进入环境”。当变量离开环境时,则标记为“离开”。
垃圾收集器在运行的过程中会给所有内存中的变量都加上标记,然后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记。而在此之后,再被加上标记的变量将被视为准备删除的变量,因为环境中的变量已经无法访问到这些变量了。最后,垃圾处理器完成内存清理工作,销毁那些带标记的值,并回收它们的存储空间。

2、引用计数

引用计数是一种不太常见的垃圾收集策略。引用计数的策略是跟踪记录每个值被引用的次数。当某个变量的引用计数为0时,表示该变量已经无法被访问了,则改变量可以被回收。

3、管理内存

使用具备垃圾收集机制的语言编写程序,开发人员一般不用操心内存管理的问题。但是,确保使用最少的内存可以让页面获得更好的性能。优化内存占用的最好方式,就是为执行中的代码只保存最少的数据。一旦数据不再使用,最好通过将其设置为null来释放其引用。局部变量会在它们离开执行环境后自动被解除引用。

function createPerson(name){
    var localPerson = new Object();
    localPerson.name = name;
    return localPerson;
 }
var globalPerson = createPerson("Nicholas"); 
// 解除globalPerson的引用
globalPerson = null;
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值