匿名函数与闭包
匿名函数:
function(){return 'a'}
闭包:有权访问另一个作用域变量的函数(函数里的匿名函数),闭包不属于任何对象的属性和方法
闭包的作用:
1 返回局部变量:
function box(){
var a=1;
return function(){
return a;
}
}
console.log(box()())
2 将局部变量驻留在内存中:
function pox(){
var age=1;
age++;
return age;
}
function box(){
var age=1;
return function(){
age++;
return age;
}
}
console.log(pox()); //2
console.log(pox()); //2
console.log(box()());//2
console.log(box()());//2
var b=box(); //获得函数
console.log(b()) //2
console.log(b()) //3
PS:闭包里返回的局部变量不会被立即销毁回收,所以会占用更多的内存,过度使用会导致性能下降。
3 在循环里的匿名函数取得的变量都是最后一个:
例1:点击目标p节点,改变其属性
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>test</title>
<script type="text/javascript" src="demo.js"></script>
</head>
<body>
<p>1</p>
<p>2</p>
<p>3</p>
</body>
<script type="text/javascript">
function f(name){
var e = document.getElementsByTagName(name)
if(e){
for(var i = 0;i < e.length;i++){ //或将var改成let
e[i].onclick = function(){
console.log(i) //3
e[i].style.color = 'red'; //e[i]改成this
}
}
}
}
f('p');
</script>
</html>
或者改为:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>test</title>
<script type="text/javascript" src="demo.js"></script>
</head>
<body>
<p>1</p>
<p>2</p>
<p>3</p>
</body>
<script type="text/javascript">
function f(name){
var e = document.getElementsByTagName(name)
if(e){
for(var i = 0;i < e.length;i++){
e[i].onclick = (function(i){
return function(){ //返回匿名函数将变量驻留在内存中
return e[i].style.color = 'red'; //此时a[i]可以改为this,this在这是e[i]
}
})(i);//匿名函数自我执行
e[i]=null;//解除引用释放内存
}
}
}
f('p');
</script>
</html>
例2:
function box(){
var arr=[];
for(var i=0;i<5;i++){
arr[i]=function(){
return i; //匿名函数返回局部变量,此时是i的最终值
}
}
return arr;
}
// 调用
for(var i=0;i<5;i++){
document.write(box()[i]())
}
// 结果是:5个5,并不是0,1,2,3,4
改写:
改0:
function box(){
var arr=[];
for(var i=0;i<5;i++){
arr[i]=i //不用匿名函数,直接返回
}
return arr;
}
// 调用
for(var i=0;i<5;i++){
document.write(box()[i])//1,2,3,4,5
}
改1:
function box(){
var arr=[];
for(var i=0;i<5;i++){
arr[i]=(function(){
return i;
})()//匿名函数自我执行
}
return arr;
}
// 调用
for(var i=0;i<5;i++){
document.write(box()[i])//0,1,2,3,4
}
改2:常用
function box(){
var arr=[];
for(var i=0;i<5;i++){
arr[i]=(function(num){
return function(){ //返回一个匿名函数,匿名函数会将变量驻留在内存中
return num;
}
})(i) //匿名函数自我执行
}
return arr;
}
// 调用
for(var i=0;i<5;i++){
document.write(box()[i]())//0,1,2,3,4
}
4:关于this对象:
在匿名函数里的匿名函数使用this
例1:
var a=2;
var obj={
a:1,
run:function(){
return function(){
return this.a; //this这里指window
}
}
}
console.log(obj.run()()) //2 不是1
例2:
var a=2;
var obj={
a:1,
run:(function(){
return function(){
return this.a; //this这里指obj
}
})()
}
console.log(obj.run()) //1 不是2
// 其实obj.run()就是function(){return this.a}
更改this指向的两种方法:
例3:
var a=2;
var obj={
a:1,
run:function(){
return function(){
return this.a;
}
}
}
console.log(obj.run().call(obj) ) //1 对象冒充
例4:
var a=2;
var obj={
a:1,
run:function(){
var that=this;
return function(){
return that.a;
}
}
}
console.log(obj.run()()) //1 传递this
PS:内存泄漏:匿名函数里得到的局部变量需要手动清理,上面的3中例1的改写方法用到的。5:模仿块级作用域
for语句,if语句等其他循环语句没有单独的作用域,即没有封闭作用域的功能。
function box(){
(function(){
for(var i=0;i<3;i++){
console.log(i); //此处会输出
}
})()
console.log(i); //此处会报错
}
box()
6 私有变量
function Box(value){
var user = value;
this.getUser = function(){
return user;
}
this.setUser = function(value){
user = value;
}
}
var a = new Box('苏');
console.log(a.getUser());
var b = new Box('王');
console.log(b.getUser());
以上通过构造方法访问私有变量,但是对象的方法,在多次调用的时候会多次创建。使用静态私有变量:
(function (){
var user='' //变量初始化
Box = function(value){ //构造方法,全局变量
user = value;
};
Box.prototype.getUser = function(){
return user;
};
Box.prototype.setUser = function(value){
user=value;
}
})();
var box = new Box('苏');
console.log(box.getUser())
使用了prototype导致方法共享了,而user变成了静态属性(共享与不同对象的属性)。
7:模块模式:
1):对象字面量方式采用模块模式来创建
var box = function(){
var age = 100;
function run(){
return 1;
};
return { //直接返回对象
go:function(){
return age+run();
}
}
}();
console.log(box.go())
以上属于单例模式,永远保持对象的一个实例。
2):增强的模块模式:
function Box(){}
var desk=function(){
var age=100;
function run(){
return 1;
}
var box=new Box(); //可以实例化的对象
box.go=function(){
return age+run();
}
return box; //返回实例对象
}();
console.log(desk.go())