1、
错误的Jscript
IE的ECMAscript实现Jscript有严重混淆的命名
函数表达式。现在很多人反对命名函数表达式,甚至目前的版本仍在使用(5.8版中使用IE8)仍存在以下问题。
这里我们以伊江让那些错误,说支一芝碧,争取实现一看。让我们看看以下示例:
示例1:函数表达式的指示符泄漏到外部范围
函数(g){ };
类型G; / /
功能 我们已经说过,有名函数表达式在外层
作用域标识符无效,但Jscript显然是违反该规范的,在上面的例子中的标识符G解析为一个函数对象,这是错误的,许多错误是很难找到,因为这个
原因。
注:这似乎已经修复这个问题,IE9之后
示例2:使用命名函数表达式作为函数声明和函数表达式
类型G; / / 功能
函数(g){ };
在特性环境中,函数声明将优先于要解析的任何表达式。上述例子
显示了Jscript,这实际上是命名函数表达式作为函数,因为它解析G实际报关前。
这个例子引出下一个例子。
示例3:命名函数表达式
创建两个完全不同的函数对象!
函数(g){ };
F = G; / false
f.expando = 'foo;
g.expando; / /未定义
看到这里,每个人都会觉得问题是严重的,因为
修改任何一个对象和另一个对象
都是没有任何变化的,这是很糟糕的。通过这个例子,我们可以创建2个不同的对象。也就是说,如果想在f的
属性中
保存一些信息,然后通过引用同一对象的同一名称属性来使用它,那么这是一个大问题,因为它根本不可能。使用G是不可能的。
看一个稍微复杂一些的例子。
示例4:只按
顺序解析函数声明,忽略
条件语句块
函数g(){
返回1;
};
如果(false){
f函数g(){
返回2;
};
}
g(2);
这个bug查找更加困难,但是bug的原因非常简单。首先,G被解析为函数声明。因为在Jscript函数声明不是由代码块限制条件,这非常糟糕如果分支,G作为另一个函数g(){ return 2 },即是宣布了。然后,所有正则表达式求值,此时F是一个引用到另一个新创建的对象。由于表达的价值评价,它永远不会进入这个邪恶的分支,因此将继续参照第一个函数,函数g(){ return 1 }。在这种
情况下,问题是显而易见的:如果你不小心的话叫G F,你将调用一个无关的g函数对象。
你可能会问,不同的对象和arguments.callee之间的
区别是什么让我们来看看。
函数g(){
返回{
arguments.callee = = F,
arguments.callee = = G
};
};
(f);true,false }
(g);false,真}
你可以看到,对arguments.callee
参考总是调用的函数,这实际上是一件好事,这将稍后解释。
另一个有趣的例子是在赋值语句中使用命名函数表达式,该语句不包含声明:
(函数(){())
f =函数(f){ };
});
根据对代码的分析,我们本来想创建一个全局属性F(注:不可与一般的匿名函数,用于
名字的声明,Jscript混淆)在这里。首先,表达式是语句的函数,因此f被声明为局部变量。(和一般的匿名函数语句,然后相同)当函数
执行时,f已经被定义,函数的右边(f){被直接分配给局部变量F,所以F不是全局属性。
关于Jscript我们如此异常,及时预防这些问题,首先要防止泄漏和外部标识符的范围,其次,不应该被用来作为参考函数标识符名称;记得在G的较早的例子恼人的标识符如果我们不存在时,G是没有多少不必要的麻烦是可以避免的。因此,关键是总是指功能通过F或arguments.callee.if你使用命名函数表达式,你应该使用这个名字只有当你调试。最后,请记住,这是必要的
清理过程中宣言的命名函数声明错误创建的函数。
2、Jscript的
内存管理 知道不符合规范的代码,解析错误,如果我们使用它,我们会
发现内存实际上是个问题。让我们举个例子。
函数(){()
如果(真){
返回函数(g){ };
}
返回函数(g){ };
});
我们知道这个匿名函数调用返回的函数(有一个标识符G函数)然后分配到外我们还知道命名函数表达式的函数对象产生过剩,这是不是返回的函数对象相同,所以多余的G函数死在返回功能
关闭,所以记忆出现问题。这是因为函数在if语句和G在同一范围内声明。在这种情况下,它总是占用内存除非我们明确地断开G函数参考。
函数(){()
变量f;
如果(真){
f =函数(g){ };
}
{其他
f =函数(g){ };
}
将g
设置为null后,它将不再用于内存。
g = null;
返回F;
});
通过设置g为null,垃圾回收器回收g所引用的隐式函数,为了验证我们的代码,我们将做一些测试以确保我们的内存被
恢复。
测试
测试很简单,也就是说,命名函数表达式创建10000个函数,然后将它们存储在一个数组中。稍等片刻,看看这些函数占用了多少内存。然后断开这些引用并重复这个过程:
功能createfn(){
返回(函数(){())
var f;
如果(真){
f =函数f(){
return'standard;
};
}
否则如果(false){
f =函数f(){
return'alternative;
};
}
{其他
f =函数f(){
return'fallback;
};
}
F = null / var;
返回F;
});
}
var arr = { };
对于(var i = 0;i < 10000;i + +){
ARR {我} = createfn();
}
通过
运行在WindowsXP SP2中的
任务管理器可以看到以下结果:
IE7:
没有`空`:7.6k -> 20.3k
与`空`:7.6k -> 18k
IE8:
没有`空`:14k -> 29.7k
与`空`:14k -> 27k
正如我们所期望的,显示引用可以释放内存,但是内存没有释放,10000个对象的功能在释放大约300万内存之前,这是什么对于一些小
脚本,但是对于大型
程序,还是长时间运行在低内存设备中的时间,这是非常必要的。
以上是关于所有
介绍Jscript错误和内存管理,希望对你有帮助的
学习。