由浅入深之-变量作用域与内存问题

引言

正如ECMA里面所描述的,javascript变量是一个弱定义,对于变量的类型没有强制定义,这给大部分人开发带来一定的小麻烦,遇到一些必要的转型

变量

在javascript中,有静态变量,也有动态变量,让我们来回顾一下.

基本变量类型

  • string
  • number
  • null
  • undefined
  • boolean

这里的变量赋值很变态

1
2
3
4
5
6
7
8
var a='you';
var b=a;
b=3
console.log(a,b)//you,3
a -> you
b -> you -> 3

变态吗?呵呵,b居然是3,而且他是开辟了内存里有2个单位

你还可以更变态点

1
var a=b='you';

动态变量,引用类型

  • object
    在这里我们发现,我们经常用到的json数据格式就是引用类型object
    那有人问,array是不是呢?
    答案:是的
    是引用类型,其实这些就是一个定义,有动态属性的基本都是引用类型,这样就很好理解了
1
2
3
4
var obj=new Object();
var obj0=obj;
obj.name='you';
console.log(obj0.name);

上面对象赋值,那是有连接性的,正如一个Prometheus框架,你要new Graphic,赋给一个对象,最好重新new一下,不然你出现的东西还是一个啊,切记!切记!记不住,你把自己切了
只有实战当中才能看出神奇的东西,纯看书,不行哇,练起来

参数变量

一般用在函数中的形参,实参
形参

1
2
3
4
5
function back(){
var n=0;
return n;
}
back()//0

n是调用时分配内存,完事,就回收了

实参

1
2
3
4
5
function back(a){
return a;
}
back()//报bug,未传参
back(0);//0

伪类变量

this下面的变量

1
2
3
4
5
Prometheus.Graphic=function(){
this.name='you';//默认值
}
var obj=new Prometheus.Graphic();
console.log(obj.name)//you

变量检测类型

有instanceof 与typeof

typeof 识别变量类型

instanceof 用原型链来识别判断该对象是不是某一类型

所以是不是很明显,两者各有分工的含义

作用域

在某一个区域内,可以操作引用的变量或对象,你可以把他想像成,政府机构里面做办公室的公务员好了
大头肯定归上面管,小头归大头区域管
这里就出现一个全局与局部,这两理解应该不难
刚才提到函数内的变量分配后,会自动回收,利用这一个机制,就有所谓的闭包方法了,虽然看上去代码不是很好看,但管用

  • arguments
    为什么要提这个呢,实参对象的引用,其实这个是一个非常好用的作用域变量,对于玩过flash as3开发者来说,不陌生,这玩意儿可以解除事件监听哇
    1
    2
    3
    4
    function pp(){
    console.log(arguments.length);
    }
    pp(0,0,0);//3

神奇吗?要相信,还能这种机制

1
2
3
4
5
6
7
8
9
10
function pp(){
var p='ok';
function kk(){
var w=p;
var p='ok';
var k='you';
console.log(w,p,k);//undefined,ok,you
}
console.log(w,p,k);//undefined,ok,undefined
}

这个就是一个复杂的嵌套函数,测试作用域,有些未定义直接报undefined,一般最好直接||某个值或字符串,以确保,让你通过,不然上传某个项目,不能执行下去,这就丢大了

还有一个闭包环境,这个之前好像遗留,闭包环境也是好处在于局域变量不受全局变量影响

1
2
3
4
5
6
7
8
9
10
var test='test';
(function(root){
console.log(arguments.length)//1;
console.log(test);//undefined
var obj={name:'jack'}
var test;
console.log(test);//undefined
test='ok';
console.log(test);//ok
})(window);

这种需要自己去test,才能更了解js的多种情况,实践出真理.
闭包:有好处也有坏处,坏处是清不掉引用类型,导致内存泄漏

  • callee
    引用当前正在执行的函数

延长作用域

location.href大家不陌生吧,在原生里面去看的时候发现 是这样的

1
2
3
4
5
6
7
function geturl() {
with (location) {
var url = href + '?id=0';
}
return url;
}
console.log(geturl());

是不是不可思议,居然是这样的写法
这里with的作用就是接收location对象,{包含location所有方法}
变态一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var index = {
render: function () {
return 'ok';
}, init: function () {
}
}
function geturl() {
with (index) {
var url = render() + '?id=0';
}
return url;
}
console.log(geturl());

内存管理

javascript是自动回收机制,与as3类似,但是回收时,清的不干净那就增加内存了

  • 标签
    回收机制会给每个变量加上一个标签,就跟你名字一样,你要是拿了东西跑了,或者吃完就拉,虽然东西没了,但你人还在,只有把你干掉,才算不占资源,这…你懂的吧,呵呵

  • 计数
    这个贴了标签,下次再来,他又重新给一个标签,这就是计数,通常用到setimeout及setinterval就会感觉到,
    跑着跑着,怎么越来越慢,fps越来越小,因为他已经计的已经超int类型值范围了

  • 标记清除
    清除是这个内存最手动的一步,因为这个没有办法,有些对象,你不手动定义,回收机制得不到指令,也是无奈的,所以在写代码时,如果要清,请给对象加null

    1
    2
    3
    4
    function aa(){
    var a='ok';
    }
    aa();

执行完,a变量自动随着时间间隔被回收,并清除内存单元

  • 回收
    据历史遗留问题ie6回收机制是根据内存分配量而运行的,比较坑,而且是超过256个变量,4000多个对象或数组元素,容量达64KB才,分配内存进行回收,
    对于回收机制,浏览器其实也有接口预留的
    flash 中的GC()
    ie中的collectGrarbage()
    opera中的opera.collect()

  • 管理
    据各官方浏览器报,都是分配给浏览器很少的内存使用,以免真死机,可以去尝试一下死循环,呵呵

  • 解除引用
    在不用对象或变量时,最好设置null,这个符合回收机制的指令,会搜索所有带null的,真的清除内存单元

    1
    2
    3
    4
    5
    var obj=new Object();
    obj.name='ok';
    console.log(obj);
    obj=null
    console.log(obj);

总结:变量定义,函数定义,这些写的代码最终还是要用之取之删之,才能不浪费资源及性能,做好最基础的一步,上层建筑才有望搭建哇!共勉!