变量,作用域和内存问题
全局变量:全局变量定义可以提供所有代码块和函数调用
私有变量:在js下,只有函数里定义的变量才是私有的
基本数据类型:null,undefined,number,string,Boolean
引用数据类型:object,
变量提升和作用域
预解释(变量提升)
在当前的作用域中,js代码执行之前,浏览器首先会把var和function的声明内容,进行提前声明或定义
声明和定义的区别
var a //声明:告知浏览器在内存中存储一个变量
var b=11 //定义:不但定义了变量,还进行了赋值
变量提升的函数和变量的区别
var在内存中只完成了声明,function在内存中完成了声明和定义,只是函数没调用的时候存储的是字符串
例如:
console.log(a)//输出 undefined
var a=11
fun()//执行函数
function fun(){
console.log("这是函数")
}
变量提升注意事项
1.不定义var的区别
console.log(a)//输出undefined
console.log(b)//报错,没有变量提升的过程
var a=11
b=22
2.不管条件是否成立,都要进行变量提升
console.log(a)//输出undefined,变量还存在
if(false){
var a=12
}
3.当执行一个匿名函数的时候,是不进行预解释的,代码的执行和定义一起完成了
(function(){
var a=b=3//var b=3 a=b
})()
console.log(a)//3 b变量提升了
console.log(b)//报错 a没有变量提升
4.当函数里的return语句执行时,下面的语句虽然不执行,但是也需要变量提升
注意:函数作用域下,有私有变量找私有变量,没有形参,形参没有找全局,但是如果形参和私有变量进行了变量提升,就不会找全局变量了
function fun(){
console.log(a)
return false
var a=66
}
fun()
5.在js中,变量和函数名称重复,也冲突,在变量提升时,如果名称声明过了,不会再次声明,但是可以重新赋值
function num(){
console.log(111)
}
num()
var num=66
console.log(num)//输出66,var不会重新声明,但是可以改变值
num()//报错
垃圾回收
js具有自动垃圾回收机制,无需手动清除
标记清除
原理:当js函数中声明一个变量,将变量标记为“进入环境”,则变量在内存中占有位置,当变量执行完毕,会将其标记为“离开环境”,js垃圾回收机制检测到“离开环境”,就会自动回收
在标准浏览器下常用这种回收方式,只是时间间隔不一样
引用计数
原理:js会跟踪每一个变量的引用次数,当变量被声明并将一个值赋给变量,则引用计数会标注为1,如果变量执行运算或又进行了赋值,则引用计数进行加1,相反,变量赋给其他变量,或者没再进行操作,则次数减1,直到次数变成0,则回收销毁
如果出现循环引用,a调用b,b也调用a,则内存会一直没有释放,容易出现内存泄漏
内存泄漏和内存溢出的区别
内存泄漏:动态给内存分配空间,在使用完毕之后,没有进行释放,导致一直占着内存,直到程序结束
内存溢出:不顾堆栈分配的数据大小,向内存写入过多的数据,导致数据越界
栈和堆的销毁方式
栈内存
全局变量:只有浏览器关闭的时候,才会回收
局部变量:只有定义在函数里的才是局部变量,函数会产生自己的作用域,当函数执行完毕时,js内存机制会自动进行释放
堆内存
对象或函数在堆内存开辟空间,堆内存就会生成一个引用地址,如果有代码引用了这个地址,则对象不会被销毁。如果想销毁,需要把引用设置成null即可。
例如:
var x = new Array()
x=null //销毁了
不被销毁的特殊情况
1.函数执行时,返回了一个对象,并在函数外调用,那么私有变量不会被销毁
function fun(){//延长作用域链
var x=[1,2,3]
return x
}
var arr=fun()
console.log(arr)//数组可以在函数访问,不被销毁
2.在一个私有作用域中,给dom元素绑定事件,这个私有作用域不会被销毁
var btn=document.getElementByld("btn")
btn.οnclick=function(){
var num=11
alert(num)
}
3.闭包(特殊作用域)
闭包是能够有权访问其他函数内部的私有变量的函数,可以理解为函数嵌套函数,必须满足以下特点,缺一不可:
1.函数嵌套函数
2.内部函数访问外部函数的变量
3.变量不会被垃圾机制所回收
例如:
function fun(){
var a=11
return function(){
var b=1
return ++a+(++b)
}
}
var f=fun()
var v2=f()
console.log(v2)//输出14
var v3=f()
console.log(v3)//输出15
注意:fun只执行一次,a不被销毁,闭包执行多选,b每次执行·都重新赋值成了1
闭包的作用
1.可以模拟私有方法
2.用来实现对象的封装
3.用闭包可以访问缓存,当代码执行时间过长,可以先从缓存中读取