IE8及IE8以下浏览器中,a 函数的内的 arguments.caller( IE9之后这个属性被移除) 指向 a.caller 执行时的 arguments (arguments.caller.callee === a.caller)。
八、字符串实时解析中的函数调用:eval()、new Function()、setTimeout()、setInterval()eval() 与 window.eval()
代码如下:
function a(){
console.log('out of b');
}
function b(){
function a(){ console.log("in b"); }
var f = function(){ a(); };
eval('a()'); // in b
window.eval('a()'); //out of b ,ie 6\7\8 in b, ie 9 out of b
(new Function('a();'))(); //out of b
setTimeout('a()',1000); // out of b
setTimeout(f,2000);// in b
}
b();
eval() 中的代码执行于eval() 语句所处的作用域内:
代码如下:
var Objinit = function(){
var param = 123;
return {
execute:function(codes){
eval(codes);
},
setCallback:function(f){
this.callback = f;
},
fireCallback:function(){
this.callback && this.callback.call(this);
},
getParam:function(){
return param;
}
}
};
var obj = Objinit ();
var param = 'outerParam';
console.log(param,obj.getParam()); //outerParam 123
obj.execute('param = 456');
console.log(param,obj.getParam()); //outerParam 456
obj.setCallback(function(){ eval("param = 8888")});
obj.fireCallback();
console.log(param,obj.getParam()); //8888 456
obj.setCallback(function(){ eval("eval(param = 9999)")});
obj.fireCallback();
console.log(param,obj.getParam()); //9999 456eval()
字符串中解析出的代码运在 eval 所在的作用域,window.eval() 则是运行在顶级作用域(低版本 chrome 和 低于IE9 则同 eval()).
IE 中 ,window.execScript(); 相当于 window.eval()
new Function()、setTimeout()、setInterval() 的第一个字符串参数所解析得到的代码,都是在顶级作用域执行。
九、函数闭包要理解函数闭包,先了解 js 的垃圾自动回收机制。
number、string、boolean、undefined、null 在运算和赋值操作中是复制传值,而对象类型的数据按引用传值。
js 的同一个对象型数据可能被多次引用,如果某个对象不再被引用,或者两个对象之间互相引用之外不在被第三方所引用,浏览器会自动释放其占用的内存空间。
函数被引用:函数被赋为其他对象的属性值,或者函数内部定义的数据在该函数外被使用,闭包的形成基于后一种情形。
闭包就是一个函数有权限访问另一个函数。
代码如下:
var f;
function fun(){
var a =1;
f = function(){ return ++a;};
}
fun(); //产生一个闭包
f(); // 闭包中 a=2
f(); // 闭包中 a =3 ,模拟静态变量
在 fun 内 声明的匿名函数赋给 fun 外的变量 f,该匿名函数内使用了在 fun 内声明的变量 a,于是 f可以访问变量 a,为了维持这种访问权限(f执 行时需要访问a,但何时执行未定), fun() 执行完毕产生的变量 a 不能被释放(除非f 中的函数被释放),于是产生了一个闭包(变量 a 被封 闭了,供 f 使用)。
产生闭包的关键是,一个在函数 A内的声明的函数 B被传出 A 之外,并且 B 函数内使用了在 函数A 内生成的数据(声明或按值传参)。
函数B传出函数A之外的方式有多种,如:
代码如下:
function fun(){
var a =1;
return {a:123,b:456, c: function(){ return ++a;} };
}
var f = fun();
f.c(); //a=2
广义上来说,函数运行时都会形成闭包,没有数据在函数外被引用时,闭包的生命周期很短:函数执行完毕即释放。
闭包的独立性:即使由同一个函数产生���多个闭包也是相互独立的。
代码如下:
function fun(){
var a =1;
return function(){ return ++a;};
}
var f1 = fun(); //一份闭包
var f2 = fun(); //另一份闭包
alert(f1()); //2
alert(f1()); //3
alert(f2()); //2
alert(f2()); //3
这两份闭包中的变量 a 是不同的数据,每产生一份闭包, fun() 执行了一次, 变量声明语句也执行了一次。十、最后说一下IE6的内存泄漏和闭包
在IE 6 中,非原生js对象(DOM 等)的循环引用会导致内存泄露,使用闭包时如果涉及非 js 原生对象引用时要注意。
function fun(){
var node = document.getElementById('a');
node.onclick = function(){ alert(node.value); };
node = null; //打断循环引用防止内存泄露