引导:为方便自已以及其它同事,请大家遵守前端js规范,挺高工作效率!---持续更新中…..
注:后端只需遵守js规范,后面的js优化部分了解即可;
1,统一采用闭包的立即执行的方式,不要污染全局变量;
(funcction(){
// to do ...
})(window)
2,不要污染全局变量,尽量采用局部变量的;
;(function(){
不规范的书写方式:
var name = 'andy';
var age = 'lcuy';
....
function createNums(params) {
var sex = 'boy';
var city = 'BeiJing';
...
}
规范的书写方式:
统一的类型可以new 一个公共函数
function createPeople(){
var name = 'andy',
age = 'lcuy',
sex = 'boy',
city = 'BeiJing';
}
})(window);
```
## 3,为了区分全局变量和局部变量,书写方式如下:
全局变量采用 $ 符
如 var $name = ‘andy’;
局部变量采用 _ 符
如 var _age = ‘30’;
## 4,不要想当然的创建过多的函数,统一放到一个位置,或在原型里添加: 若是构造函数,首字母要大写
var Union_config = function(){
create:function(){
var Union_config = function(){
init:function(){
// 初始化函数
....
},
sumbit:function(){
// 提交表单信息
...
},
...
...
};
return Union_config;
}
};
var myUnion = Union_config.create();
// 调用函数 以下可以按需调用函数方法;
myUnion.sumbit(); ...
5,注释!!!---为了方便其它同事,自己写代码的时候一定要写注释; 若是定义的全局注释或者函数等注释采用标准等文档注释;
如:
/**@zJquery 通用js库
* @author huangzhao
* * ....
* */
6,链式调用以及其它用法
如: $('.div1').html(''); $('.div2').html('');
可以写成: $('.div1,.div2').html('');
如: $('.div1').css('color','red');
$('.div1').addClass('active');
可以写成: $('.div1').css('color','red').addClass('active');
// 可以采用链式
7,函数命名统一采用驼峰命名法
如:
function createNums(){
//....
}
8,规范定义JSON对象,补全双引号 对于JSON数据,我们推荐采用标准地书写格式,方便查看;
如:{name:'andy',age:'18'} 改成 {"name":"andy","age":"17"}
9,关于ESLite代码检查查看以下链接
10,用“===“取代“==“
前者是严格判断,后者会进行隐式的类型转换;
11,关于for循环性能体验
一般写法:
var myarr = [" " " " " ];
for(var i=0;i<myarr.length;i++){
//此写法性能一般;
}
for(var i=0,len=myarr.length;i<len;i++){
//此写法性能良好
}
for(var i=0,val;val = myarr[i++]){
console.log(i,val);
//此写法性能好---推荐使用
}
12,统一使用缩进大小,以tab为基准;
13,var 的时候若有常量,全用大写;
如 var KPI = 123;
14,js中避免过多的DOM操作,需创建文档片段;
数据较多的时候,会影响性能,如下:
for(var i=0;i<500;i++)
{
var _span = document.createElement('span');
var _text = document.createTextNode(i);
_span.appendChild(_text);
document.body.appendChild(_span);
}
通过创建文档片段来优化性能:如下:
var $frgment = document.createDocumentFragment();
for(var i=0,len=500;i<len;i++){
var _span = document.createElement('span'),
_text = document.createTextNode(i);
_span.appendChild(_text);
$frgment.appendChild(_span);// 先添加到文档片段中
}
document.body.appendChild($frgment);// 最后再绑定给要赋予的元素
15,如何处理onload事件要执行的多个函数?
function createNumA(){
console.log(1);
}
function createNumB(){
console.log(2);
}
window.onload = createNumA;//这个不会执行,被下面的覆盖了;
window.onload = createNumB;//当然,这个可以执行,覆盖了上面的onload事件
// 解决方法1:可以用隐式函数----此方法比较常见,便于理解
window.onload = function(){
//都会被执行
createNumA();
createNumB();
};
// 解决方法2:
function addEventOnload(func){
var oldOnload = window.onload;
if(typeof window.onload != 'function'){
window.onload = func;
}else{
window.onload = function(){
oldOnload();
func();
};
}
}
// 调用方法
addEventOnload(createNumA);
addEventOnload(createNumB);
提示:以上两个方法都推荐使用,看个人喜好;
16,js代码要做到高内聚/低耦合!
高内聚:就是指某个系统模块有一段相关行很强的代码组成,只负责一项任务开发,俗称“单一责任原则”;
低耦合:一段完整的js代码,模块与模块之间尽可能独立存在,原因是可能每个模块处理的js代码功能不同。模块与模块之间的接口尽量也少而简单。如果某个模块比较大,尽量拆分来做,便于修改以及调用;
例如:
// 阶乘函数
function factorial(num){
if(num <= 1 ){
return 1;
}else{
return num * factorial(num-1);
}
};
factorial(3);
console.log(factorial(3));// 6=1*2*3
// 上面的函数,这样定义没有问题,但问题是这个函数的执行与函数名factorail紧紧耦合在了一起。
// 为了消除这种紧密耦合的现象,用arguments.callee来解决
function factorial(num){
if(num <= 1){
return 1;
}else{
return num * arguments.callee(num-1);
}
}
/* 注意:在函数内部,有两个特殊的对象,arguments和this
虽然,arguments的主要用途是保存函数参数,但这个对象有个名叫callee的属性,
该属性是一个指针,指向拥有arguments对象的函数
*/
17, 定义多个函数的时候,如果参数相同,可以用apply()和call()改变环境对象,得到引用
每个函数都包括非继承而来的方法,apply()和call();
apply()和call()方法相同,区别在于接受的参数不同而已;
function sum(num1,num2){
return num1 + num2;
}
function callSum(num1,num2){
return sum.apply(this,arguments);
}
function callSum1(num1,num2){
return sum.apply(this,[num1,num2]);
}
function callSum2(num1,num2){
return sum.call(this,num1,num2);
}
console.log(callSum(10,10)); //10
console.log(callSum1(10,10)); //10
console.log(callSum2(10,10)); //10
// 但是,传递参数并不是apply()和call()的真正用武之地,他们真正的强大的地方是能够扩充函数赖以运行的作用域
window.color = 'red';
var $o = {"color":"blue"};
function sayColor(){
console.log(this.color);
}
sayColor();//red
sayColor.call(this);//red
sayColor.call(window);//red
sayColor.call($o);//blue
除此,推荐大家使用ECMAScript5中定义的一个方法:bind()方法
var objSayColor = sayColor.bind($o);
objSayColor();//blue
18,不要使用eval()函数
原因:1),性能差;2),不能打断点调试;3),容易受到攻击;4),可读性差;5),优化概率低;
19,减少花费在作用域链上的时间,增加脚本的整体性能
优化之前:
function createUi(){
var _span = document.getElementsByTagName('span');
console.log(_span.length);
for(var i = 0,len = _span.length;i<len;i++){
_span[i].title = document.title + 'txt' + i;
console.log(i);
}
}
createUi();
createUi中包含了二个对于全局变量document对象的引用,特别是循环中的document引用,查到次数是O(n),每次都要进行作用域链查找。通过创建一个指向document的局部变量,就可以通过限制一次全局查找来改进这个函数的性能。
优化之后:
function createUi(){
var _doc = document,
_span = _doc.getElementsByTagName('span');
for(var i = 0,len=_span.length;i<len;i++){
_span[i].title = _doc.title + 'txt' + i;
}
}
20,避免with()语句
缺点:1),运行缓慢;2),会创建自己的作用域,因为会增加代码块中执行的作用域的长度;3),难以优化;
21, 提倡对象字面量
// 避免
var $a = new Array();
$a[0] = 1;
$a[1] = 'andy';
$a[2] = 'false';
var $obj = new Object();
$obj.name = 'andy';
$obj.age = 20;
// 提倡
var $a = [1,'andy','false'];
var $b = {
name:'andy',
andy:20
}
22,建议多使用innerHtml
页面上创建DOM节点的方法有两种:
使用诸如createElement()和appendChild()之类的DOM方法,以及使用innerHTML。
对于小的DOM更改,两者效率差不多,但对于大的DOM更改,innerHTML要比标准的DOM方法创建同样的DOM结构快得多。
当使用innerHTML设置为某个值时,后台会创建一个HTML解释器,然后使用内部的DOM调用来创建DOM结构,而非基于JS的DOM调用。由于内部方法是编译好的而非解释执行,故执行的更快。
23,通过模板元素clone,替代createElemnet
如果文档中存在现成的样板节点,应该是用cloneNode()方法,因为使用createElement()方法之后,
你需要设置多次元素的属性,使用cloneNode()则可以减少属性的设置次数——同样如果需要创建很多元素,==应该先准备一个样板节点==
优化之前:
var $frag = document.createDocumentFragment();
for (var i = 0; i < 10; i++) {
var _el = document.createElement('p');
_el.innerHTML = i;
$frag.appendChild(_el);
}
document.body.appendChild($frag);
优化之后:
var $frag = document.createDocumentFragment();
var $pEl = document.getElementsByTagName('p')[0];
for (var i = 0; i < 10; i++) {
var _el = $pEl.cloneNode(false);
_el.innerHTML = i;
$frag.appendChild(_el);
}
document.body.appendChild($frag);
24,|| 和 && 布尔运算符的应用
function eventHandler(e) {
if (!e) e = window.event;
}
//可以替换为:
function eventHandler(e) {
e = e || window.event;
}
if (myobj) {
doSomething(myobj);
}
//可以替换为:
myobj && doSomething(myobj);
25,一次性修改样式属性;
目的:防止页面过多重排
优化前:
ele.style.backgroundColor = "#e6e6e6";
ele.style.color = "#000";
ele.style.fontSize = "12rem";
优化后:
.addActive {
background: #eee;
color: #093;
height: 200px;
}
document.getElementById(‘myDiv’).className = ‘addActive’;
26,操作DOM前,先把DOM节点删除或隐藏,因为隐藏的节点不会触发重排
优化前:
var $items = document.getElementsByClassName('mydiv');
for (var i=0; i < $items.length; i++){
var _item = document.createElement("li");
_item.appendChild(document.createTextNode("Option " + i);
$items[i].appendChild(_item);
}
优化后:
$items.style.display = "none";
for (var i=0; i < items.length; i++){
var _item = document.createElement("li");
_item.appendChild(document.createTextNode("Option " + i);
$items[i].appendChild(_item);
}
$items.style.display = "";
DOM的核心问题是:DOM修改导致的页面重绘、重新排版!重新排版是用户阻塞的操作,同时,如果频繁重排,CPU使用率也会猛涨!
27,用数组方式来遍历Dom对象集合;
html:
<ul id="testList" >
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
</ul>
js:
1),each:
var $arr = $('li'),
$KPI = 1000000;
console.time('Each需要花费的时间');
for(var i=0;i<$KPI;i++){
$arr.each(function(i,val){
this;
});
}
console.timeEnd('Each需要花费的时间');
2),数组array实现
var $arr = $('li'),
$KPI = 1000000;
// array实现
console.time('Array需要花费的时间');
for(var i=0;i<$KPI;i++){
var _len = $arr.length;
for(var j=0;j<_len;j++){
$arr[i];
}
}
console.timeEnd('Array需要花费的时间');
总结:经过测试,在性能方面,对于each方法这种优雅实现是有代价的。花费的时间长;然而通过数组来实现, Dom对象集合就是一个类数组,具有length和value属性。花费时间短;
28,不要在函数体内做过多的嵌套判断;
优化前:
function createNums(){
var _r = {};
_r.data = {};
_r.data.age = 20;
if(_r){
if(_r.data){
if(_r.data.age){
console.log('true');
}else{
console.log('false');
}
}
}
}
createNums();
优化后:
function createNums1(){
var _r = {};
_r.data = {};
_r.data.age = 20;
if(!_r){
return;
}
if(!_r.data){
return;
}
if(_r.data.age){
console.log('true');
}else{
console.log('false');
}
}
createNums1();
29,适当用while代替for循环,可以提高性能;如数组元素与排序无关的情况
var $date = new Date();
var $arrs = [1,1,2,3,4,5,6,7,8,9,10,11,11,22,33,44,555,55555555555555,555,55,55,32,32,8,8,8,8,1324123414],
$sum = 0,
$len = $arrs.length;
优化前:
for(var i=0;i<$len;i++){
$sum += $arrs[i];
}
console.log($sum);
console.log(new Date() - $date);
优化后:
while($len --){
$sum += $arrs[$len];
}
console.log($sum);
console.log(new Date() - $date);
提示:数据小的情况下可能差别不大,如果数据量比较大,第二种写法效果就比较明显了;大家可根据情况应用,一般情况下要知道,能用for循环的就不要用for..in循环(因为for.in循环会自动在后台创建一个枚举器,比较损坏性能),此外,能用while循环的尽量不要用for循环;最后也推荐大家用下do..while循环(前三种是前测试循环,最后一个是后测试循环);
30,关于闭包的问题解决方法:
html:
<span>1</span>
<span>2</span>
<span>3</span>
js:
var _doc = document,
_span = _doc.getElementsByTagName('span');
for(var i = 0,len=_span.length;i<len;i++){
_span[i].onclick = function(){
console.log(i);
}
}
//提示;我们会发现打印出来的都是 3;这就是所谓的闭包
1),闭包的问题用闭包的方法去解决
解决思路:
增加若干个对应的闭包空间(这里是匿名函数),专门用来存储原来需要引用的下标;
var _doc = document,
_span = _doc.getElementsByTagName('span');
for(var i = 0,len=_span.length;i<len;i++){
(function(arg){ //
_span[i].onclick = function(){ //onclick函数实例的function scope的closole 对象属性有一个引用arg,只要外部空间的arg不变,这里的引用值也不会改变
console.log(arg);
}
})(i);
}
2),将下标作为对象属性(name:’i’,value:’i’的值)添加到每个数组项中;
var _doc = document,
_span = _doc.getElementsByTagName('span');
for(var i = 0,len=_span.length;i<len;i++){
_span[i].i =i; //为当前数组项目即当前span对象添加一个名为i的属性,值为循环体的i变量的值;
_span[i].onclick = function(){//此时当前span的对象的i属性并不是循环体i变量的引用,而是一个独立span对象的属性,属性值在声明的时候就确定了;
console.log(this.i);
}
}
3),闭包方法的延伸
// 此方法和方法1类似但又有不同;
// 相同点:都是增加若干个对应的闭包空间来存储下标;
// 不同点:方法1是在新增的匿名闭包空间完成事件的绑定;方法3是将事件绑定在新增的匿名函数返回的函数上;
var _doc = document,
_span = _doc.getElementsByTagName('span');
for(var i = 0,len=_span.length;i<len;i++){
_span[i].onclick = (function(arg){
return function(){
console.log(arg);
}
})(i);
}
总价:以上3中方法都可以,看个人喜好!
温馨提示:zQuery地址:https://github.com/hzaini1989/zQuery