WEB開闢面面談之(5)——寫JS時必需注重的的一些問題

更多概況請看http://blog.zhangbing.club/%E…

下面例舉了一樣平常前段開闢中碰到的場景,處理計劃有許多,但從開闢階段就進行範例,能夠很大水平防止許多後續的潛伏和兼容題目。

獵取body元素

非規範做法

document.body

W3C範例要領

document.getElementsByTagName('body').item(0)

運用jQuery/Zepto

$('body');

獵取窗口題目

非規範做法

document.title

W3C範例要領

document.getElementsByTagName('title').item(0).innerHTML  

運用jQuery/Zepto

$('title').text()

監聽iframe的加載完成事宜

  • 寫法1:
iframe.onload = function() {...}

題目:存在兼容性題目,IE6、7無效

  • 寫法2:
iframe.onload = iframe.onreadystatechange = function(){...}

題目:邏輯龐雜,事宜綁定邏輯雜沓,在某些瀏覽器上onload和onreadystatechange都邑觸發,需要另外加標記位推斷,邏輯龐雜。

  • 簡約而完整兼容的寫法:
var bindIframeOnloadEvent = function(el, onload) {
 if (el.attachEvent){
    el.attachEvent("onload", onload);
 } else {
   el.onload = onload;
 }
};
bindIframeOnloadEvent(iframe, function(){...}); 

怎樣操縱iframe內部的window

  • 寫法1:
iframe.contentWindow

題目: 部份瀏覽器不兼容(IE67),獵取失利

  • 寫法2:
document.frames[frameId]

題目: 非規範挪用,兼容性是題目,強迫必需為iframe增加ID。

  • 簡約而完整兼容的寫法:
var getIframeWindow = function(el) {
return el.contentWindow || el.contentDocument.parentWindow;
};
var win = getIframeWindow(iframe);

設置iframe的邊框

  • 寫法1:
iframe.boder = 0;

題目: 非W3C規範,背面極能夠燒毀,部份瀏覽器不一定支撐

  • 寫法2:
iframe.style.boder = 'none'; 

題目: 完整依靠CSS掌握,但存在兼容性題目,IE繼承頭疼

  • 終究處理計劃:
iframe.boder = 0;
iframe.style.boder = 'none';

怎樣在a標籤上綁定鼠標點擊事宜

  • 寫法1:
<a href="javascript:func();">test</a>

題目:

  1. 不符合CSP範例
  2. 等價於全局eval。只能挪用公然的全局要領,污染全局變量
  3. 鼠標懸停時,狀態欄會顯現要運轉的代碼?!這對終究用戶不友好
  4. 運轉代碼的上下文是window對象,和事宜處置懲罰模子相違犯
  • 寫法2:
<a href="#" onclick="func();">test</a>

題目:

  1. 不符合CSP範例
  2. onclick和href在部份瀏覽器(IE繼承躺槍)行文詭異,實行爭執非常
  3. 等價於全局eval。只能挪用公然的全局要領,污染全局變量(緣由同寫法1)
  • 寫法3:
<a href="#" onclick="func();return false;">test</a>

題目:只處理了題目2,其他題目仍存在

  • 規範寫法:
<a id='aTest'>test</a>
<script>
document.getElementById('aTest').onclick = function() {
func();
};
</script>

運用jQuery/Zepto亦可,存在唯一的小題目是鼠標指針不是手形,是默許。可採用CSS款式來處理cursor:pointer 。

script標籤的謄寫要領深挖

要點

  1. script標籤的type屬性不是必需的,默許缺省就是text/javascript
  2. script標籤的language屬性完整無用(asp時期微軟好像運用該屬性來標記服務端言語是vb照樣c#),不要弄巧成拙
  3. 動態建立的script標籤必需要指定type=’text/javascript’,不然JS不會實行
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = '###';
document.getElementsByTagName('body').item(0).appendChild(script);
  1. 動態建立的script追加行動是異步的,並不會馬上獲得script運轉效果,假如要守候加載完成需要監聽完成事宜
  2. 運用非規範或許比較新的屬性需要分外注重,不要使代碼邏輯依靠於這些特徵。如defer/async屬性
  3. 運用script.onerror來監聽劇本實行失利的狀況(語法毛病,初始化運轉時毛病等都邑觸發)
  4. 監聽script的完成事宜比較龐雜。
varbindScriptOnloadEvent = function(script, onload) {
    var done = false;
    script.onload = script.onreadystatechange = function() {
    if (!done && (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete')) {
        done = true;
        script.onload = script.onreadystatechange = null;
        onload();
        }
    };
};
bindScriptOnloadEvent(script, function(){...});

需要斟酌兼容性,所以代碼較多

substr函數不要運用

緣由:非規範,在部份瀏覽器報錯,以至連我的Android4.0上的瀏覽器都不認該函數

替換計劃:運用substring函數。

jQuery/Zepto挑選器的.text()和.html()要領

近況:大多數開闢同學會殽雜二者並亂花,不清楚什麼時候用哪一個

詳解:.text()要領用於獵取和設置文本內容,.html()要領用戶獵取和設置HTML內容,當要設置或獵取的內容僅僅為文本時,二者行動完整相同,但要操縱的文本內容是HTML時,行動有着本質區別。

總結:

  1. 依據實際需要挑選運用哪一個要領,如能判斷內容為純文本請運用text()要領。僅當確切需要襯着HTML時才用html()要領
  2. 從平安角度,text()要領比html()要領更平安,無注入風險。
  3. 嚴厲意義上,html()要領不符合CSP範例,直接將字符串剖析為DOM節點
  4. 營業需要確切要運用.html()要領襯着動態內容時,必需做平安搜檢,防止惡意代碼注入
  5. .text()和.html()獵取值能夠存在代碼縮進(空格和TAB),若有需要能夠運用$.trim()來剔除

數組與對象深挖

要點:

  • 數組對象唯一concat/reverse/slice/splice為規範API,而且相對完整兼容
  • 數組對象請勿運用indexOf、lastIndexOf、map、every、forEach等非規範API,不僅兼容性存在題目,而且效力不一定高,反而不如本身完成
  • 遍曆數組請將.length緩存到變量
for(vari=0,l=arr.length;i<l;i++){...}
  • 遍曆數組請勿運用此寫法
for(vari in arr){...}
  • 遍歷key-value型對象必需運用hasOwnProperty()來過濾遍歷效果。
for(var key in obj) {
if(!obj.hasOwnProperty(key) continue;
    //...
}
  • 不論是數組或對象,在遍歷操縱時不要轉變被遍歷的變量組織,如增刪元素,增刪key值等(雖然你能夠這麼做),關於元素本身及子成員的修正是相對平安的。

關於Prototype的運用

要點:

  • 不要亂花Prototype。不要隨意馬虎在Object/Array/Function等對象上追加prototype(雖然我們已有某些庫這麼做了)輕易發生歧義爭執,在運用for~in遍用時很輕易激發題目。
  • 自定義的prototype成員會在for~in輪迴中湧現,請依據實際狀況運用hasOwnProperty()來過濾遍歷效果。

不嚴謹的寫法:

function Test() {}
Test.prototype.a = 1;
Test.prototype.b = 2;
var o = new Test();
for(vari in o) {
console.log({key: i, value: o});
}
//{key:a, value:1}
//{key:b, value:2}
嚴謹的寫法:
var o = new Test();
for(vari in o) {
if(!o.hasOwnProperty(i)) continue;
console.log({key: i, value: o});
}
//無輸出 
  • 對象的__proto成員,用處是獵取當前實例的原型對象。非規範完成,存在兼容性題目,請不要運用
  • 原則上不要隨意馬虎重寫已存在的prototype要領。但能夠在單個實例中覆寫該要領
  • prototype上定義靜態對象變量,會形成一切對象共用,而不是離別建立實例,請在組織要領中分派實例

毛病寫法:

function Test() {}
Test.prototype.arr = [];
var a = new Test();
var b = new Test();
a.arr.push(1);
b.arr.push(2);
console.log(a.arr, b.arr);
//[1,2], [1,2]
準確寫法
function Test() {
this.arr = [];
}

var a = new Test();
var b = new Test();
a.arr.push(1);
b.arr.push(2);
console.log(a.arr, b.arr);
//[1], [2]

總結

JS是門天真的言語,天真到想怎樣寫都能夠。但內里坑照樣不少的。在有多種挑選時,多斟酌下哪一種要領更好,而不是自覺挑選一種。

    原文作者:張炳
    原文地址: https://segmentfault.com/a/1190000015425430
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞