友情連結
引導:為友善自已以及其它同僚,請大家遵守前端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代碼檢查檢視以下連結
http://eslint.cn/docs/rules/
10,用“===“取代“==“
前者是嚴格判斷,後者會進行隐式的類型轉換;
11,關于for循環性能體驗
一般寫法:
var myarr = [" " " " " ];
for(var i=;i<myarr.length;i++){
//此寫法性能一般;
}
for(var i=,len=myarr.length;i<len;i++){
//此寫法性能良好
}
for(var i=,val;val = myarr[i++]){
console.log(i,val);
//此寫法性能好---推薦使用
}
12,統一使用縮進大小,以tab為基準;
13,var 的時候若有常量,全用大寫;
14,js中避免過多的DOM操作,需建立文檔片段;
資料較多的時候,會影響性能,如下:
for(var i=;i<;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=,len=;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();
}
function createNumB(){
console.log();
}
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: px;
}
26,操作DOM前,先把DOM節點删除或隐藏,因為隐藏的節點不會觸發重排
優化前:
var $items = document.getElementsByClassName('mydiv');
for (var i=; 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=; 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 = ;
console.time('Each需要花費的時間');
for(var i=;i<$KPI;i++){
$arr.each(function(i,val){
this;
});
}
console.timeEnd('Each需要花費的時間');
2),數組array實作
var $arr = $('li'),
$KPI = ;
// array實作
console.time('Array需要花費的時間');
for(var i=;i<$KPI;i++){
var _len = $arr.length;
for(var j=;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=;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 = ,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 = ,len=_span.length;i<len;i++){
_span[i].onclick = (function(arg){
return function(){
console.log(arg);
}
})(i);
}
總價:以上3中方法都可以,看個人喜好!
溫馨提示:zQuery位址:https://github.com/hzaini1989/zQuery