- createDocumentFragment的使用
首先,介绍了几种常见的动态创建html节点的方法,如下所示:
方法 |
说明 |
crateAttribute(name) |
用指定名称name创建特性节点 |
createComment(text) |
创建带文本text的注释节点 |
createDocumentFragment() |
创建文档碎片节点 |
createElement(tagname) |
创建标签名为tagname的节点 |
createTextNode(text) |
创建包含文本text的文本节点 |
以上这些方法,每次JavaScript对DOM的操作都会改变当前页面的呈现,并重新刷新整个页面,从而消耗了大量的时间。为解决这个问题,可以创建一个文档碎片,把所有的新节点附加其上,然后把文档碎片的内容一次性添加到document中,这个就是createDocumentFragment()的用武之处。
createDocumentFragment()说明
DocumentFragment:表示文档的一部分(或一段),更确切地说,它表示一个或多个邻接的 Document 节点和它们的所有子孙节点。
DocumentFragment 节点不属于文档树,继承的 parentNode 属性总是 null。
不过它有一种特殊的行为,该行为使得它非常有用,即当请求把一个DocumentFragment 节点插入文档树时,插入的不是 DocumentFragment 自身,而是它的所有子孙节点。这使得 DocumentFragment 成了有用的占位符,暂时存放那些一次插入文档的节点。它还有利于实现文档的剪切、复制和粘贴操作。
可以用Document.createDocumentFragment() 方法创建新的空 DocumentFragment 节点。
说明:添加多个dom元素时,先将元素append到DocumentFragment中,最后统一将DocumentFragment添加到页面。 该做法可以减少页面渲染dom元素的次数。经IE和FireFox下测试,在append1000个元素时,效率能提高10%-30%,FireFox下提升较为明显。
createDocumentFragment()用法示例
使用appendChild逐个向DOM文档中添加1000个新节点:
for (var i = 0; i < 1000; i++)
{
var el = document.createElement(‘p‘);
el.innerHTML = i;
document.body.appendChild(el);
}
使用createDocumentFragment()一次性向DOM文档中添加1000个新节点:
var frag = document.createDocumentFragment();
for (var i = 0; i < 1000; i++)
{
var el = document.createElement(‘p‘);
el.innerHTML = i; frag.appendChild(el);
}
document.body.appendChild(frag);
不要小瞧这10%-30%,效率的提高是着眼于多个细节的,如果我们能在很多地方都能让程序运行速度提高10%-30%,那将是一个质的飞跃,您也将步入骨灰级玩家的行列。
一、将条件分支,按可能性顺序从高到低排列
说明:可以减少解释器对条件的探测次数。
二、在同一条件子的多(>2)条件分支时,使用switch优于if
说明:switch分支选择的效率高于if,在IE下尤为明显。4分支的测试,IE下switch的执行时间约为if的一半。
三、使用三目运算符替代条件分支
使用前:
if (a > b)
{ num = a; }
else
{ num = b; }
使用后:
num = a > b ? a : b;
-
JS循环引用的内存泄露问题
如果循环引用中包含DOM对象或者ActiveX对象,那么就会发生内存泄露。内存泄露的后果是在浏览器关闭前,即使是刷新页面,这部分内存不会被浏览器释放。
简单的循环引用:
var el = document.getElementById(‘MyElement‘);
var func = function () {…}
el.func = func;
func.element = el;
但是通常不会出现这种情况。通常循环引用发生在为dom元素添加闭包作为expendo的时候。
如:
function init()
{
var el = document.getElementById(‘MyElement‘);
el.onclick = function () {……}
}
init();
init在执行的时候,当前上下文我们叫做context。这个时候,context引用了el,el引用了function,function引用了context。这时候形成了一个循环引用。
下面2种方法可以解决循环引用
- 置空dom对象
使用前:
function init()
{
var el = document.getElementById(‘MyElement‘);
el.onclick = function () {……}
}
init();
使用后:
function init()
{
var el = document.getElementById(‘MyElement‘);
el.onclick = function () {……}
el = null;
}
init();
将el置空,context中不包含对dom对象的引用,从而打断循环应用。 如果我们需要将dom对象返回,可以用如下方法:
使用前:
function init()
{
var el = document.getElementById(‘MyElement‘);
el.onclick = function () {……}
return el;
}
init();
使用后:
function init()
{
var el = document.getElementById(‘MyElement‘);
el.onclick = function () {……}
try{ return el; }
finally { el = null; }
}
init();
- 构造新的context
使服用前:
function init()
{
var el = document.getElementById(‘MyElement‘);
el.onclick = function () {……}
}
init();
使用后:
function elClickHandler() {……}
function init() {
var el = document.getElementById(‘MyElement‘);
el.onclick = elClickHandler;
}
init(); 把function抽到新的context中,这样,function的context就不包含对el的引用,从而打断循环引用。
-
Javascript中声明变量速度的研究
声明变量到底要不要var
- 使用var语句多次声明一个变量不仅是合法的,而且也不会造成任何错误。
- 如果重复使用的一个声明有一个初始值,那么它担当的不过是一个赋值语句的角色。
- 如果重复使用的一个声明没有一个初始值,那么它不会对原来存在的变量有任何的影响。
没有var声明的变量,是作为全局变量存在的;有var声明的变量,属于局部变量,尤其是在函数内部。并且,经过测试,带var声明比不带var速度要快,比如:"var a"比"a"具有更快的执行速度。我们有理由推测,局部变量的声明比全局变量的声明效率更高。 直接量与new
变量有好几种类型,但是同一类型的变量创建的方式可能不一样,比如string、Object、Array等这些类型的变量声明或者创建。
经过测试,通过直接量声明的速度明显快于通过new声明的速度,比如"var a={} "比"var a=new Object()"具有更快的执行速度。 局部变量与全局变量
现在笔者来告诉你,函数内尽量多设局部变量,这样即安全又快速,变量操作也更加合理,不会因为函数内胡乱操作全局变量而导致逻辑错误。
写个例子说明下,先建立一个全局变量:var m=1; ,接着我读取这个全局变量1000000次
全局变量:
for(var i=1000000;i--;)
{a=m;}
局部变量:
(function (){
var n=m;
for(var i=1000000;i--;)
{a=n;}
})();
执行速度2>1
通过上面测试表明,先将m这个全局变量的值存给局部变量n,在将n赋值给a具有更快的速度。
变量名长度
变量名是自己取的,为了照顾语义和规范,变量名可能稍长,但是注意了,变量名的长度也会影响代码的执行速度。
经过测试,长的变量名声明的执行速度没有短的快,比如"var a=1"比"var aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=1"具有更快的执行速度。
所以,我们在声明变量的时候,尽量缩写一些单词,并记忆一些常见的缩写,以下是缩写示例:
单词 |
缩写 |
array(数组) |
arr |
string(字符串) |
str |
number(数量/数字) |
num |
function(函数) |
fun |
message(消息/信息) |
mes |
userNumber(会员数量) |
userNum/uNum |
parentElement(父级节点/父级元素) |
parentEle |
returnArray(返回的数组) |
returnArr |
-
JS全局变量的副作用
JavaScript通过函数管理作用域。局部变量是在函数内部使用 var 声明的变量;全局变量则会在下列情况下出现:
- 在任何地方不使用 var 声明变量,或者直接向未声明的变量赋值。
- 在函数外部使用 var 声明的变量。
- 以 window. variable 形式声明的变量。
全局变量的问题在于,你的JavaScript应用程序和web页面上的所有代码都共享了这些全局变量,他们住在同一个全局命名空间,所以当程序的两个不同部分定义同名但不同作用的全局变量的时候,命名冲突在所难免。
web页面包含不是该页面开发者所写的代码也是比较常见的,例如:
- 第三方的JavaScript库
- 广告方的脚本代码
- 第三方用户跟踪和分析脚本代码
- 不同类型的小组件,标志和按钮
比方说,该第三方脚本定义了一个全局变量,叫做result;接着,在你的函数中也定义一个名为result的全局变量。其结果就是后面的变量覆盖前面的,第三方脚本就一下子嗝屁啦!
因此,要想和其他脚本成为好邻居的话,应该尽可能少的使用全局变量,并且始终使用var来声明变量。
以下是几种常见的误将局部变量声明为全局变量的例子。
一、函数内部不使用 var 声明变量
function sum(x, y) {
// 不推荐写法: 隐式全局变量
result = x + y;
return result;
}
此段代码中的result没有声明。代码照样运作正常,但在调用函数后你最后的结果就多一个全局命名空间,这可以是一个问题的根源。
经验法则是始终使用var声明变量,正如改进版的sum()函数所演示的:
function sum(x, y) {
var result = x + y;
return result;
}
二、使用任务链进行部分 var 声明
// 反例,勿使用
function foo() {
var a = b = 0;
// ...
}
上面的片段中,a是本地变量但是b确实全局变量,这可能不是你希望发生的。
此现象发生的原因在于这个从右到左的赋值,首先,是赋值表达式b = 0,此情况下b是未声明的。这个表达式的返回值是0,然后这个0就分配给了通过var定义的这个局部变量a。换句话说,就好比你输入了:
var a = (b = 0);
如果你已经准备好声明变量,使用链分配是比较好的做法,不会产生任何意料之外的全局变量,如:
function foo() {
var a, b;
// ... a = b = 0; // 两个均局部变量
}
IT学苑提示隐式全局变量和明确定义的全局变量间有些小的差异,就是通过delete操作符让变量未定义的能力:
- 通过var创建的全局变量(任何函数之外的程序中创建)是不能被删除的。
- 无var创建的隐式全局变量(无视是否在函数中创建)是能被删除的。
这表明,在技术上,隐式全局变量并不是真正的全局变量,但它们是全局对象的属性。属性是可以通过delete操作符删除的,而变量是不能的。
使用即时函数函数,避免变量污染
为了避免全局的变量的污染,IT学苑推荐一种即时函数的写法,即将具有独立功能的代码放在一个即时函数里面。如下:
(function(){
//输出变量 itxueyuan
var itxueyuan="http://www.itxueyuan.com/javascript/";
document.write(itxueyuan+"<br />");
})();
document.write(itxueyuan);
结果,第一次输出http://www.itxueyuan.com/javascript/,第二次提示语法错误:

可见,变量itxueyuan的作用域仅限于及即时函数内部,有效避免了变量的污染,尤其是在引入第三方代码的情况下。由于IT学苑的JS代码很大一部分使用了这种模式,有效避免了变量冲突。
Javascript 优化
原文:http://my.oschina.net/u/242764/blog/483361