摘要:類似的情況還有,方法和方法等。今天我說一個最簡單。代碼如下和也可以實現,但是生成的是一個整數,如下分割線其它類型數據轉布爾數據下面的轉換,大家一看就明白了,不多說。緩存變量循環緩存分割線第一段就是每一次循環的時候,都要查詢一次。
1.前言
從大學到現在,接觸前端已經有幾年了,感想方面,就是對于程序員而言,想要提高自己的技術水平和編寫易于閱讀和維護的代碼,我覺得不能每天都是平庸的寫代碼,更要去推敲,去摸索和優化代碼,總結當中的技巧,積極聽取別人的建議,這樣自己的技術水平會提高的更快。那么今天,我在這里就分享一下關于javascript方面的寫作的實用技巧和建議,這些技巧和建議是我平常在開發項目上會用到的,希望能讓大家學到知識,更希望能起到一個交流意見的作用,也就是說大家有什么好的技巧或者建議,歡迎分享,或者覺得我的想法存在什么問題,歡迎指出!
2.更短的數組去重寫法[...new Set([2,"12",2,12,1,2,1,6,12,13,6])] //[2, "12", 12, 1, 6, 13] //es6的新特性3.對象深淺拷貝
關于對象的深淺拷貝,我個人見解就是有一下幾點:
1.深拷貝和淺拷貝只針對像Object, Array這樣的引用類型數據。
2.淺拷貝是對對象引用地址進行拷貝,并沒有開辟新的棧,也就是拷貝后的結果是兩個對象指向同一個引用地址,修改其中一個對象的屬性,則另一個對象的屬性也會改變。
3.深拷貝則是開啟一個新的棧,兩個對象對應兩個不同的引用地址,修改一個對象的屬性,不會改變另一個對象的屬性。
淺拷貝var myInfo={name:"守候",sex:"男"};
var newInfo=myInfo;
newInfo.sex="女";
console.log(myInfo) //{name: "守候", sex: "女"}假-深拷貝
假-深拷貝這個是自己隨性命名的,大家看看就好,別當真!
var myInfo={name:"守候",sex:"男"};
var newInfo=Object.assign({},myInfo)
newInfo.sex="女";
console.log(myInfo) //{name: "守候", sex: "男"} console.log(newInfo) //{name: "守候", sex: "女"}真-深拷貝
真-深拷貝這個是自己隨性命名的,大家看看就好,別當真!
看著深淺拷貝,區別寫法很簡單,但是那個上面的深拷貝寫法是有問題的。看下面案例
var arr=[{a:1,b:2},{a:3,b:4}] var newArr=Object.assign([],arr) //截斷數組 newArr.length=1 console.log(newArr)//[{a:1,b:2}] console.log(arr)//[{a:1,b:2},{a:3,b:4}] //操作newArr,這里看著對arr沒影響,實際上已經挖了一個坑,下面就跳進去 newArr[0].a=123 //修改newArr[0]這個對象,也是影響了arr[0]這個對象 console.log(arr[0])//{a: 123, b: 2}
為什么會這樣呢,因為Object.assign并不是深拷貝,是披著深拷貝外衣的淺拷貝。最多也是Object.assign會課拷貝第一層的值,對于第一層的值都是深拷貝,而到第二層的時候就是 復制引用。類似的情況還有,slice方法和concat方法等。
要解決這個問題,就得自己封裝方法!如下
//利用遞歸來實現深拷貝,如果對象屬性的值是引用類型(Array,Object),那么對該屬性進行深拷貝,直到遍歷到屬性的值是基本類型為止。 function deepClone(obj){ if(!obj&& typeof obj!== "object"){ return; } var newObj= obj.constructor === Array ? [] : {}; for(var key in obj){ if(obj[key]){ if(obj[key] && typeof obj[key] === "object"){ newObj[key] = obj[key].constructor === Array ? [] : {}; //遞歸 newObj[key] = deepClone(obj[key]); }else{ newObj[key] = obj[key]; } } } return newObj; } var arr=[{a:1,b:2},{a:3,b:4}] var newArr=deepClone(arr) console.log(arr[0])//{a:1,b:2} newArr[0].a=123 console.log(arr[0])//{a:1,b:2}
還有一個方法就是簡單粗暴法,我現在在用的一個方法!原理很簡單,就是先把對象轉成字符串,再把字符串轉成對象!也能實現同樣效果
var newArr2=JSON.parse(JSON.stringify(arr)); console.log(arr[0])//{a:1,b:2} newArr2[0].a=123 console.log(arr[0])//{a:1,b:2}
上面所說的淺拷貝,真假深拷貝(自己隨性命名的),這幾種情況,在開發上都有可能要用到,至于要使用哪一種方式,視情況而定!
4.使用事件委托一個簡單的需求,比如想給ul下面的li加上點擊事件,點擊哪個li,就顯示那個li的innerHTML。這個貌似很簡單!代碼如下!
很簡單,這樣就實現了,實際上這里有坑,也待優化!
1.for循環,循環的是li,10個li就循環10次,綁定10次事件,100個就循環了100次,綁定100次事件!
2.如果li不是本來就在頁面上的,是未來元素,是頁面加載了,再通過js動態加載進來了,上面的寫法是無效的,點擊li是沒有反應的!
所以就者需要用事件委托(即使不考慮上面的第二種情況,也是建議使用事件委托)!代碼如下
這樣寫,即使是動態添加進來的li點擊也有反應,還有一個就是ul只有一個,事件綁定在ul上,無論li多少個,都是添加一次事件!但是也是可能會有問題,如果li下面還有子元素,那么點擊的時候,target可能不是li,而是鼠標點擊那個位置的最底層元素!如下圖,如果鼠標點擊白色區域,那個target就是body元素,鼠標點擊綠色區域target就是div元素,鼠標點擊藍色區域target就是ul,點擊橙色就是li。
5.使用對象作為函數參數大家試想下這樣一個函數--函數接受幾個參數,但是這幾個參數都不是必填的,函數該怎么處理?是不是下面這樣
function personInfo(name,phone,card){ ... } //以上函數,可以任意傳參數。比如我想傳card等于1472586326。這下是不是這樣寫 personInfo("","","1472586326")
有沒有覺得上面寫法奇怪,不太優雅?下面這里看著舒服一點!
function personInfo(opt){ ... } personInfo({card:"1472586326"})
再想一下,如果一個函數,參數很多,怎么處理?
function test(arg1,arg2,arg3,arg4,arg5,arg6,arg7){ ... }
密集恐懼癥復發沒有復發?下面這樣看著會舒服一點!
function personInfo(opt){ ... }
最后再想一下,如果需求改了,操作函數也要改!函數也要增加一個參數。
//原來函數 function personInfo(name,phone,card){ ... } //修改后 function personInfo(name,age,phone,card){ ... }
這樣就是參數修改一次,函數的參數就要修改一次!如果是用對象,就不會出現這樣問題!
//修改前后都是這樣,變得是函數的操作內容和調用時候的傳參! function personInfo(opt){ ... }
看了上面的幾個栗子,總結來說,就是當函數的參數不固定的時候,參數多(三個或者三個以上)的時候,建議用一個對象記錄參數,這樣會比較方便,也為以后如果參數要改留了條后路!
6.使用push和apply合并數組合并數組這個已經是老生常談的話題了,方法也是多種多樣!
concatvar arr1=[1,2,3,4,5],arr2=[6,7,8,9,10]; arr1=arr1.concat(arr2) console.log(arr1)//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
concat會一個全新的數組,表示arr1和arr2兩個數組的組合,并讓arr1和arr2不變。簡單吧?
但如果arr1和arr2的長度都很長,那就產生了一個很長很長的數組,內存又被占用了那么多。但是數組長度沒限制!
var arr1=[1,2,3,4,5],arr2=[6,7,8,9,10]; for(var i=0,len=arr2.length;i這里是往arr1循環添加arr2的元素,但是有一個情況,arr1的長度遠小于arr2的長度,是不是循環arr1性能更好,循環次數更少。處理這個很簡單,但是萬一不知道arr1和arr2到底哪個長度更少呢?而且,for循環不夠優雅!(當然,這個可以用迭代方法來替代)
reducevar arr1=[1,2,3,4,5],arr2=[6,7,8,9,10]; arr1 = arr2.reduce( function(coll,item){ coll.push( item ); return coll; }, arr1 ); console.log(arr1)//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]逼格高了一點,而且用ES6的箭頭函數還可以減少一些代碼量,但它仍然需要一個函數,每個元素都需要調用一次。
push.applyvar arr1=[1,2,3,4,5],arr2=[6,7,8,9,10]; arr1.push.apply(arr1,arr2); console.log(arr1)//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]逼格看著高,代碼少,也不會產生新的數組,也不難理解,就是調用arr1.push這個函數實例的apply方法,同時把arr2當作參數傳入,這樣arr1.push這個方法就會遍歷arr2數組的所有元素,達到合并的效果。相當于arr1.push.apply(arr1,[6,7,8,9,10]);,最后相當于arr1.push(6,7,8,9,10)。遺憾的就是,這個方法對數組長度有限制,網上說法是不同瀏覽器,不同的長度限制,一般不超過10萬!
之前是建議用push.apply,但是現在保留意見,就是大家覺得哪個方式用哪個方式!這個沒有一定的對錯!
7.toFixed保留整數在開發上,經常會遇到最多保留多少位小數或者類似的問題,針對這個,使用toFixed可以很簡單的解決問題,但是如果數據是要和后臺交互的,而且后臺存儲的數據一般是保存數字類型,而使用toFixed后生成的是一個字符串,這下,就需要把toFixed生成的是一個字符串轉成數字類型,轉發很多。今天我說一個最簡單--+。代碼如下
var a=123.36896335.toFixed(2) console.log(a)//"123.37" a=+a console.log(a)//123.37PS:a=a|0和~~a也可以實現,但是生成的是一個整數,如下
var a=123.36896335.toFixed(2) console.log(a)//"123.37" a=a|0 console.log(a)//123 //---------------------------------分割線 var a=123.36896335.toFixed(2) console.log(a)//"123.37" a=~~a console.log(a)//1238.其它類型數據轉布爾數據下面的轉換,大家一看就明白了,不多說。
console.log(!!"123") //true !!12 //true !!-1 //true !![] //true !!"" //false !!null //false9.緩存變量 for循環緩存lengthvar arr=[1,2,3,4,5,6] for(var i=0,i第一段就是每一次循環的時候,都要查詢一次arr.length。第二段代碼就是緩存了arr.length,每次對比len就好,理論上是第二段代碼的寫法比較好,性能比較高!但是隨著瀏覽器的發展,這個細節的性能上的影響貌似遠遠小于預期,現在還是建議緩存!我寫了下面的測試用例(谷歌瀏覽器測試)!
var arr100=[], arr10000=[]; for(var i=0;i<100;i++){ arr100.push(i) } for(var i=0;i<10000;i++){ arr10000.push(i) } //緩存情況 function testCache(arr){ console.time(); for(var i=0,len=arr.length;i元素事件 這里我用jquery來講解,比較容易理解,原生js也是這個道理!如下代碼
$(".div1").click(function(){ ... }) //--------------------------分割線 var $div1=$(".div1"); $div1.click(function(){ ... })上面的代碼,改變的也是緩存了$(".div1"),但是這里就建議是第二種寫法了,因為第一種點擊一次就要查詢一次.div1,Dom的操作還是能減少就減少!
10.使用innerHTML添加元素比如有一個需求,往ul里面添加10個li,兩種方法,如下代碼
大家把代碼用瀏覽器打開,發現基本是第二種方式更快,第8點也說了,DOM操作能少就少!第一種要操作10次DOM,第二種只需要操作1次DOM。還有一個就是,這個只是很簡單的li,如果是下面的列表呢?用第一種方式,得createElement多少次,innerHTML多少次,appendChild多少次?代碼多,各個節點的邏輯和嵌套關系也亂!用第二種方式就是一個拼接字符串的操作,比第一種方式好多了,如果用es6的模板字符串,就更簡單了!
11.將參數轉成數組函數里的arguments,雖然擁有length屬性,但是arguments不是一個數組,是一個類數組,沒有push,slice等方法。有些時候,需要把arguments轉成數組,轉的方法也不止一個,推薦的是是下面的寫法!
var _arguments=Array.prototype.slice.apply(arguments)12.函數節流這里拿一個栗子說,比如mousemove,onscroll,onresize這些事件觸發的時候,可能已經觸發了60次事件,這樣很消耗性能,而且實際上,我們并不需要這么頻繁的觸發,只要大約100毫秒觸發一次就好!那么這樣就需要函數節流了!
普通寫法
var count = 0; function beginCount() { count++; console.log(count); } document.onmousemove = function () { beginCount(); };效果
節流寫法
var count = 0; function beginCount() { count++; console.log(count); } function delayFn(method, thisArg) { clearTimeout(method.props); method.props = setTimeout(function () { method.call(thisArg) },100) } document.onmousemove = function () { delayFn(beginCount) };效果
這種方式,其實是有問題的,在不斷觸發停下來等待100ms才開始執行,中間操作得太快直接無視。于是在網上找到下面這種方案!
第二種節流寫法
function delayFn2 (fn, delay, mustDelay){ var timer = null; var t_start; return function(){ var context = this, args = arguments, t_cur = +new Date(); //先清理上一次的調用觸發(上一次調用觸發事件不執行) clearTimeout(timer); //如果不存觸發時間,那么當前的時間就是觸發時間 if(!t_start){ t_start = t_cur; } //如果當前時間-觸發時間大于最大的間隔時間(mustDelay),觸發一次函數運行函數 if(t_cur - t_start >= mustDelay){ fn.apply(context, args); t_start = t_cur; } //否則延遲執行 else { timer = setTimeout(function(){ fn.apply(context, args); }, delay); } }; } var count=0; function fn1(){ count++; console.log(count) } //100ms內連續觸發的調用,后一個調用會把前一個調用的等待處理掉,但每隔200ms至少執行一次 document.onmousemove=delayFn2(fn1,100,200)我現在函數節流用得很少,這兩個寫法是比較基礎的,希望大家能共享下自己的比較好的方法!13.其他寫作建議關于其它的一些寫法技巧和建議,都是比較老生常談的,比如命名規范,函數單一性原則等。這一部分內容我自己總結和別人寫的基本一致!我就不展開說了(感覺展開說也基本是復制粘貼別人的文章,這事我不干),所以我推薦大家去看這篇文章(如何優雅的編寫 JavaScript 代碼)。有些知識我也是從這里獲得的!
14.小結好了,關于我自己總結的一些實用技巧和建議,就到這里了!關于javascript的技巧和建議,這點大家還是要多看網上的資源,也要自己多總結,畢竟我自己總結的只是我自己發現的,只是冰山一角。但還是希望這篇文章能幫到大家,讓大家學習到知識。當然,更希望的是能起到一個交流意見的作用。如果大家有什么建議,技巧。也歡迎分享。覺得我哪里寫錯了,寫得不夠好,也歡迎指出!讓大家一起互相幫助,互相學習!
-------------------------華麗的分割線--------------------
想了解更多,關注關注我的微信公眾號:守候書閣
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/88391.html
摘要:前言還有幾天就到國慶中秋了,快要放假了,先祝大家節日快樂之前寫過的寫作建議和技巧,那么今天就來聊聊吧說到,每一個網頁都離不開,但是對于,很多開發者的想法就是,只要能用來布局,把效果圖排出來就可以了,其它的細節或者優化,不需要怎么考慮。 1.前言 還有幾天就到國慶中秋了,快要放假了,先祝大家節日快樂!之前寫過js的寫作建議和技巧,那么今天就來聊聊css吧!說到css,每一個網頁都離不開c...
摘要:前言還有幾天就到國慶中秋了,快要放假了,先祝大家節日快樂之前寫過的寫作建議和技巧,那么今天就來聊聊吧說到,每一個網頁都離不開,但是對于,很多開發者的想法就是,只要能用來布局,把效果圖排出來就可以了,其它的細節或者優化,不需要怎么考慮。 1.前言 還有幾天就到國慶中秋了,快要放假了,先祝大家節日快樂!之前寫過js的寫作建議和技巧,那么今天就來聊聊css吧!說到css,每一個網頁都離不開c...
摘要:前端日報精選專題之函數記憶插件編寫與實戰源碼解析系列一簡單渲染個人小結實用技巧和寫法建議從入門到工程實踐中文技術周刊從前端小白到技術專家,這里有點可執行的建議你真的需要一個實用工具集嗎深入理解時序函數聊聊與特性英文 2017-09-06 前端日報 精選 JavaScript專題之函數記憶Vue 插件編寫與實戰Preact 源碼解析系列一 :簡單DOM渲染個人小結--javascript...
摘要:順便一說,這首歌的原唱是秋田,中島當年嗓子壞了,才有這歌。中文是直接翻譯來的,作曲是秋田。一部電影春夏秋冬又一春春夏秋冬又一春是由金基德執導,金英民吳英秀金基德主演的一部韓國電影。年月日于韓國上映。 原鏈接: http://bluezhan.me/weekly/#/9-2 1、web前端 Angular vs. React vs. Vue: A 2017 comparison 9 S...
閱讀 3378·2023-04-26 01:40
閱讀 3086·2021-11-24 09:39
閱讀 1397·2021-10-27 14:19
閱讀 2641·2021-10-12 10:11
閱讀 1302·2021-09-26 09:47
閱讀 1843·2021-09-22 15:21
閱讀 2697·2021-09-06 15:00
閱讀 884·2021-08-10 09:44