所有的過失在未犯以前掐暮,都已定下應(yīng)處的懲罰
引言
在這一篇路克,我打算放飛自我樟结,既然是亂燉..那么就可以光明正大的想到什么寫什么锥涕,全無章法,天馬行空狭吼。
然层坠,內(nèi)容不會脫離基礎(chǔ)的范圍,所以不會多么難懂刁笙,來源則是偶然發(fā)現(xiàn)的讀書筆記和以前在開發(fā)中記錄的一些小Tip破花。
既然是Tip,不免會顯得零碎疲吸,既然有前言座每,我想定個大綱是為寫作之常理,筆記依然摘悴。
主要包括以下內(nèi)容:
- 編程風(fēng)格和推薦的編程規(guī)范(通常團(tuán)隊(duì)會有一個規(guī)范峭梳,雖然不一定強(qiáng)制執(zhí)行)。
- 一些小知識點(diǎn)蹂喻,有些可能有助于解決Bug有些則這輩子不會用到第二次葱椭。
- 一些常用的代碼塊,通常來源于網(wǎng)上口四,多少會摻雜一些個人理解孵运。
和網(wǎng)上大多數(shù)的文章一般,由于水平有限蔓彩,在這種可以有很多解釋的概念上治笨,理解往往會出現(xiàn)偏差,這份筆記也不能免俗赤嚼。
假如有讀者的存在旷赖,還希望在讀這篇時(shí)保持自己獨(dú)立思考的能力,避免被不必要的帶偏更卒。
筆者雖會竟可能的去驗(yàn)證這些內(nèi)容等孵,但畢竟金無足赤,這篇文章輸出的內(nèi)容將會很主觀逞壁,如有建議還望賜教流济。
編程規(guī)范和一些約定成俗的內(nèi)容
這部分,我也不一定能嚴(yán)格執(zhí)行腌闯,而且很主觀绳瘟,很多內(nèi)容僅僅是適用于之前做的項(xiàng)目,可以有選擇的遵循或者干脆全然不顧姿骏。
“程序是寫給人讀的糖声,只是偶爾讓計(jì)算機(jī)執(zhí)行一下”
良好的編程習(xí)慣能使人在寫代碼時(shí)思維更加敏捷,編寫起來更為流暢,甚至執(zhí)行起來效率更高蘸泻。
而統(tǒng)一的編程風(fēng)格則可以使一個團(tuán)隊(duì)的項(xiàng)目具備更好的可讀性琉苇,通常可讀性就意味著便于維護(hù)和擴(kuò)展悦施。
通常情況并扇,一個項(xiàng)目不是作完就算了的,它需要迭代抡诞,升級穷蛹,添加需求。
而如若為了趕工時(shí)昼汗,而至可讀性于不顧肴熏,到項(xiàng)目即將完成的拂曉,迎接你的恐怕將是物理上早上四點(diǎn)的太陽顷窒。
首先蛙吏,讓我們來看看在我為數(shù)尚短的生產(chǎn)生活中,比較常見到的規(guī)范鞋吉。
//絕對不要出現(xiàn)魔法數(shù)字和魔法變量鸦做,無論何時(shí)何地何因都不要
//所謂魔法數(shù)字:通常是1,2,3,4
//而魔法變量則通常是:a,b,c,d 它們往往很萬能
switch(a){
case 1:
//業(yè)務(wù)邏輯
..........
//
break;
case 2:
//業(yè)務(wù)邏輯
.......
//
break;
case 3:
//興許完全無關(guān)的業(yè)務(wù)邏輯
.....
//
break;
}
//沒有注釋的情況下這些1 2 3 就是魔法數(shù)字,沒人知道它是怎么來的坯辩,即使有注釋它們依舊難懂馁龟。
//而a是個魔法變量,沒人知道它是做什么的即使有注釋漆魔。
上面這段代碼還有一個問題,沒有默認(rèn)操作却音,不知道什么時(shí)候就會報(bào)錯改抡,如果之前沒有對數(shù)據(jù)類型做限制,也許會更糟糕系瓢。
在實(shí)際的生產(chǎn)生活中阿纤,在這種代碼上做擴(kuò)展將如履薄冰,有時(shí)重新寫一遍反而更快夷陋。
//那魔法數(shù)字和魔法變量該怎么改進(jìn)呢欠拾?
//我看見過一種命名方式:也就是以功能命名,避免使用Flag,來一個例子骗绕。
var documenFlag //看到這個鬼知道是什么,某種意義上和魔法變量差不多
var documenFormType //正確的做法
//明顯下面這個要好懂得多
//魔法數(shù)字通常產(chǎn)生于枚舉類型藐窄,比如一個Select,很多人圖省事直接將數(shù)據(jù)庫里提取出來的值就這么應(yīng)用于前端頁面酬土。
//通常后端對于枚舉值會有一個詳細(xì)的映射關(guān)系注釋荆忍,問題是前端通常沒有,雖然在寫Select時(shí)感覺不出太大影響。
//然而如果這個Select關(guān)系到前端的業(yè)務(wù)邏輯刹枉,就會變得很難懂叽唱,假如一個月后你需要回來維護(hù)你的代碼,看到一個
//if(a==2){//業(yè)務(wù)邏輯}..你會花很多的時(shí)間來弄明白a從哪來微宝,2又是什么棺亭。
//我個人遇到這種情況,會在進(jìn)入業(yè)務(wù)邏輯之前寫一個映射蟋软,將1,2,3,4,5轉(zhuǎn)換成名詞侦铜。之后使用這些字符串作判斷。
//一些常見的約定
var pageIndex //變量
var _PageIndex //受保護(hù)的變量
var PAGE_INDEX //常量
//其它還有p_pageIndex //表參數(shù) g_pageIndex //表全局變量钟鸵,但這通常不常見
//這是在let,const之前最常見的約定了钉稍,即時(shí)有Let const依舊可以這么寫,只是把var 換掉棺耍,它們很好懂贡未。
//一種簡單的編碼風(fēng)格
//文件命名
PageIndex.html //雙首字母大小寫
PageInde.min.js //統(tǒng)一min為壓縮混淆后的文件
PageInde-1.0.min.js //‘-’鏈接版本號
//限定一行的字?jǐn)?shù)比如120個,';' 不可忽略蒙袍, ',' 分行, 縮進(jìn)'tab' 四個空格
//這里我無意討論 ';'的作用俊卤,很多人認(rèn)為不應(yīng)該寫,認(rèn)為徒增操作量害幅,沒用消恍,認(rèn)為不寫更好看。
//然而我認(rèn)為無論從執(zhí)行還是語義來講它還是必要的以现。
//況且現(xiàn)實(shí)來講狠怨,很多現(xiàn)有系統(tǒng)并不是基于ES6或以上的語法編寫的,維護(hù)它們的時(shí)候最好還是把';'加上邑遏。
//數(shù)學(xué)運(yùn)算
1 + 1 =2 //等于單邊空格佣赖,運(yùn)算符雙邊空格
if (type) {
}
function Add (x) {
}
//() 關(guān)鍵字的另一邊空格
// {} 外側(cè)空格
// 即時(shí)只有一個If 也不允許寫在單行里。
// 避免不同層次變量重名记盒,局部變量集中在一處憎蛤。比如:
var pageIndex = 0;
function next(a){
var pageIndex = 1, //避免,可以換成 _pageIndex 或者 subIndexPage
lastIndex = 0,
nexIndex = 2;
//純舉例纪吮,現(xiàn)實(shí)中不會有這種需要
....//業(yè)務(wù)邏輯
}
就像我之前說的俩檬,這些規(guī)則并不絕對要求遵守。
要我來說即使只是規(guī)范變量命名就能極大的提高代碼的可讀性了碾盟。
編程風(fēng)格可以做的事無巨細(xì)棚辽,展開來說也是一本書的內(nèi)容,既然這里只是基礎(chǔ)巷疼,我覺得稍微提的這點(diǎn)就足夠了晚胡。
JavaScript豆知識系列
剛學(xué)完JavaScript那會我很喜歡探求一些小知識點(diǎn)灵奖,也就是所謂豆知識,它們通常并非完全沒什么卵用估盘。
事實(shí)上到現(xiàn)在我大都不記得還有啥了瓷患,所幸我找到了記在印象筆記上的一些片段。
//聲明提前
//js 所有的聲明都會被提前遣妥,var a=1 ;在執(zhí)行的時(shí)候會變成var a ;/..隔著其它代碼.../ a = 1
//函數(shù)類型會自動提到頂部去擅编,除非你這么寫..var a = function(){}...
//一個局部變量的列子
var scope = "global";
function f() {
alert(scope); //你以為是"global"?
//輸出undefined 因?yàn)?下面的局部變量聲明提前了
var scope = "local"; //覆蓋全局變量
alert(scope);
}
//這也是為啥局部變量建議要一起在頂部聲明的原因
//頁面可優(yōu)化的部分
1、訪問元素的某些屬性
2箫踩、通過JavaScript修改元素的CSS屬性
3爱态、在onScroll中做耗時(shí)任務(wù)
4、圖片的預(yù)處理(事先裁剪圖片境钟,而不是依賴瀏覽器在布局時(shí)的縮放)
5锦担、在其他Event Handler中做耗時(shí)任務(wù)
6、過多的動畫
7慨削、過多的數(shù)據(jù)處理(可以考慮放入WebWorker內(nèi)執(zhí)行)
//基本沒實(shí)踐過洞渔,通常后端業(yè)務(wù)邏輯接口返回的速度比前端渲染要慢。
//而影響前端渲染的最大因素往往是帶寬的大小缚态。我曾經(jīng)用加帶寬這個答案來調(diào)戲面試管磁椒,關(guān)于頁面優(yōu)化的問題..
//深拷貝和淺拷貝
//JavaScript中萬物皆對象,而對象通常是引用類型的玫芦。
//具體來說所謂對象是存的其實(shí)是一個指向內(nèi)存中某處的地址浆熔。
//這就造成了通過 = 號賦值的對象它們指向的是同一個對象,一榮俱榮桥帆,一損俱損医增。
//解決這個問題就是深拷貝,思路通常就是用循環(huán)把所有的值取出來賦到一個新對象上去环葵。
/*
jquery中可以使用$.extend深拷貝 $.extend(true,bindData,oldData); 深拷貝
ES6中assign() 可以實(shí)現(xiàn)extend的裝飾功能调窍,拷貝的對象中的對象和數(shù)組是淺拷貝。
*/
//換成代碼
function cloneObj(obj){
var newObj=obj.constructor=Arry?[]:{};
if(typeof obj !=="object"){
return;
}
else{
for(key in obj){
newObj[key]=obj[key];
}
}
return newObj;
}
//基礎(chǔ)款张遭,內(nèi)部對象數(shù)組還是淺拷貝的..
function deepClone(obj){
var str,newObj=obj.constructor==Array?[]:{};
if(typeof obj!=="object"){
return
}
else{
for(key in obj){
newObj[key]=typeof obj[key]==='object'?deepclons(obj[key]):obj[key];
}
}
return newObj;
}
//加強(qiáng)款,函數(shù)還是淺拷貝來的..
//其實(shí)現(xiàn)實(shí)中..直接轉(zhuǎn)JSON再賦值再轉(zhuǎn)回來就可以了...不會寫的這么麻煩..以上兩個例子我從來沒用過..
//原型繼承
/*
構(gòu)造函數(shù)的原型繼承,在函數(shù)中使用 argument.callee.prototype= 可以的定義原型
Object 操作
獲得父級原型對象:
subObj.__proto__ (兼容問題);
Object.getPrototypeOf(obj);
修改 obj.attrName="attrValue"; //自有
Function.prototype.attrName="attrValue"; //原型
刪除 delete 只能刪除自有成員
判斷屬性自有:obj.hasOwnProperty("attrName");
自定義子對象的原型
childObj.__proto__=FatherObj //兼容問題
Object.setPrototpeOf(childObj,FatherObj);
ECM5 的create方法
var a=Object.create( 原型對象 );
可以傳入不同的值得到一個繼承該原型對象的object 可傳入null得到一個沒有原型的純粹的object
也可傳入Array等得到繼承相應(yīng)構(gòu)造函數(shù)的object地梨。
*/
//除了hasOwnProperty很多時(shí)候很有用..其它基本沒怎么用過..
//實(shí)踐中有一次將一個函數(shù)掛到Object上去..最后出了一萬個BUG..
//從此菊卷,對于操作內(nèi)置對象都是謹(jǐn)慎小心。
//跨域宝剖,不知道為什么洁闰,很多人面試喜歡問跨域,然而在實(shí)踐中扑眉,基本不會出現(xiàn)跨域的場景,對于前端來說這不安全。
//當(dāng)然也可以說是我菜腰素。
//簡單來說聘裁,通過scrpit和img標(biāo)簽去請求別的域名的js文件就是最簡單的跨域做法。
//還需要更復(fù)雜的操作弓千,要么交給后端..要么去找大佬吧衡便。
//冒泡和拖拽
/*
addEventListener('事件名',函數(shù)對象洋访,捕獲)
捕獲:true false true 捕獲階段提前觸發(fā)镣陕,false 冒泡階段觸發(fā)
事件觸發(fā)的三個階段:1、捕獲階段姻政,2呆抑、觸發(fā) 3、汁展,冒泡階段
Event操作
取消冒泡:
e.stopPropagation()
e.target 獲取事件的目標(biāo)函數(shù)
取消事件:e.preventDefault();
事件的坐標(biāo):
相對于屏幕:e.screenX/screenY
相對于頁面左上角的坐標(biāo): e.pageX/pageY
相對于文檔顯示區(qū)左上角的坐標(biāo): e.clientX/x e.clienY/y
相對于元素左上角的坐標(biāo) offsetX/offsetY
*/
//我曾經(jīng)背過拖拽的的面試題鹊碍,當(dāng)時(shí)可以說是理解的深入骨髓,但是隨著之后從來沒用過善镰,很快就忘完了妹萨。
常用JavaScript Tip及代碼塊
在中小型項(xiàng)目中,JavaScript往往東一榔頭西一錘子的拼湊炫欺,自己寫的可能更多的是數(shù)據(jù)處理乎完。
這時(shí)候找現(xiàn)成代碼的本事通常會是決定了一個前端晚上十一點(diǎn)是坐家里喝酸奶,還是坐在辦公室喝咖啡品洛。
//無題
console.time(label) console.timeEnd(label) //測試一段方法開始和結(jié)束的時(shí)間
encodeURI(str) ;encodeURIComponent(str); //中文的編碼和解碼,避免亂碼用兩層
encodeURI() //編碼
encodeURIComponent()//編碼
decodeURI() //解碼
decodeURIComponent() //解碼
base64 API //原生不支持中文
window.atob(); //解碼
window.btoa(); // 編碼
//過濾HTML結(jié)構(gòu)
function filterHtml(str) {
str = str.replace(/<\/?[^>]*>/g,''); //去除HTML tag
str.value = str.replace(/[ | ]*\n/g,'\n'); //去除行尾空白
str = str.replace(/\n[\s| | ]*\r/g,'\n'); //去除多余空行
return str;
}
//去空格
function trim(str){
return str.replace(/\s|\xA0/g,"");
}
//url 參數(shù)獲取
function getQueryString(name) {
var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
var r = window.location.search.substr(1).match(reg);
if (r != null) {
return unescape(r[2]);
}
return null;
}
//js 鍵盤
document.onkeydown = function(e){
var keyNum = window.event ? e.keyCode : e.which; //window.event 兼容IE
//判斷keyNum的值給對應(yīng)事件
}
jQuery:
$(document).keydown(function(e){
var keyNum = e;
});
//瀏覽器視口
jquery:
$(document).ready(function()
{
alert($(window).height()); //瀏覽器時(shí)下窗口可視區(qū)域高度
alert($(document).height()); //瀏覽器時(shí)下窗口文檔的高度
alert($(document.body).height());//瀏覽器時(shí)下窗口文檔body的高度
alert($(document.body).outerHeight(true));//瀏覽器時(shí)下窗口文檔body的總高度 包括border padding margin
alert($(window).width()); //瀏覽器時(shí)下窗口可視區(qū)域?qū)挾? alert($(document).width());//瀏覽器時(shí)下窗口文檔對于象寬度
alert($(document.body).width());//瀏覽器時(shí)下窗口文檔body的高度
alert($(document.body).outerWidth(true));//瀏覽器時(shí)下窗口文檔body的總寬度 包括border padding margin
}
)
瀏覽器窗口改變事件:
$(window).resize(function(){
});
//表單JSON化
$.fn.serializeObject = function()
{
var obj = {};
var arr = this.serializeArray();
$.each(arr, function() {
if (obj[this.name]) {
if (!obj[this.name].push) {
obj[this.name] = [obj[this.name]];
}
obj[this.name].push(this.value || '');
} else {
obj[this.name] = this.value || '';
}
});
return obj;
};
//一種基于閉包寫的插件方法
(function(window,document){
//邏輯代碼
window.methodName = window.methodName || methodName
})(window,document)
//阻止冒泡
原生JS
function (e){
var event = e || window.event ;//兼容寫法
//阻止冒泡
event.cancelBubble = true; //IE
event.stopPropagation();
//阻止默認(rèn)事件(a標(biāo)簽树姨,input)
event.returnValue = false; //IE
event.parentDefault();
//使用jq的話
return false //既能阻止冒泡,也能阻止默認(rèn)事件桥状。
}
//六位隨機(jī)驗(yàn)證碼
// 方法一
('000000' + Math.floor(Math.random() * 999999)).slice(-6);
// 方法二
Math.random().toString().slice(-6);
// 方法三
Math.random().toFixed(6).slice(-6);
// 方法四
'' + Math.floor(Math.random() * 999999);
//十六進(jìn)制顏色代碼
function() {
return '#'+('00000'+
(Math.random()*0x1000000<<0).toString(16)).slice(-6)};
//多維數(shù)組展開
var foo = [1, [2, 3], ['4', 5, ['6',7,[8]]], [9], 10];
// 方法一
// 限制:數(shù)組項(xiàng)不能出現(xiàn)`,`帽揪,同時(shí)數(shù)組項(xiàng)全部變成了字符數(shù)字
foo.toString().split(','); // ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]
// 方法二
// 轉(zhuǎn)換后數(shù)組項(xiàng)全部變成數(shù)字了
eval('[' + foo + ']'); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// 方法三,使用ES6展開操作符
// 寫法太過麻煩辅斟,太過死板
[1, ...[2, 3], ...['4', 5, ...['6',7,...[8]]], ...[9], 10]; // [1, 2, 3, "4", 5, "6", 7, 8, 9, 10]
// 方法四
JSON.parse(`[${JSON.stringify(foo).replace(/\[|]/g, '')}]`); // [1, 2, 3, "4", 5, "6", 7, 8, 9, 10]
// 方法五
const flatten = (ary) => ary.reduce((a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), []);
flatten(foo); // [1, 2, 3, "4", 5, "6", 7, 8, 9, 10]
// 方法六
function flatten(a) {
return Array.isArray(a) ? [].concat(...a.map(flatten)) : a;
}
flatten(foo); // [1, 2, 3, "4", 5, "6", 7, 8, 9, 10]
//特殊字符轉(zhuǎn)譯
function htmlspecialchars (str) {
var str = str.toString().replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"');
return str;
}
htmlspecialchars('&jfkds<>'); // "&jfkds<>"
事實(shí)上转晰,過度依賴找現(xiàn)成的代碼會逐漸影響創(chuàng)造力。
但是以輪播為例士飒,你不可能在十分鐘內(nèi)寫出比現(xiàn)成庫還要好的輪播查邢。而使用現(xiàn)成的庫做輪播十分鐘已經(jīng)足夠了。
然而只會用現(xiàn)成的庫酵幕,這將使你成為一個正真的碼農(nóng)扰藕,雖然很多時(shí)候這是沒有辦法的事情。
但至少芳撒,把你在用的庫的原理搞懂邓深,不然假如讓你定制它所不具備的功能時(shí)你會很尷尬未桥。
好吧,通常這種時(shí)候你會去找滿足需求的庫芥备,我知道的冬耿。
結(jié)語
這是一篇沒什么目的性的筆記,主要由我倆年前的學(xué)習(xí)筆記和偶爾記錄一下的工作筆記拼湊而成门躯。
以文學(xué)來類比就是散文了淆党,最后的代碼塊,網(wǎng)上估計(jì)很多文章中都出現(xiàn)過讶凉,側(cè)面反映了它們很有用染乌。
然后其實(shí)真正決定你晚上十一點(diǎn)的并不是這個,而是你知道的功能庫懂讯,以及你們老大能給你爭取多少時(shí)間荷憋。
更多的時(shí)候其實(shí)更依賴于你所在的團(tuán)隊(duì)到底幾個人...
至此,我認(rèn)為算是JavaScript基礎(chǔ)的部分基本就結(jié)束了褐望。
之后勒庄,要還能寫,也許就是ES6 Node 設(shè)計(jì)模式瘫里,項(xiàng)目實(shí)踐一類的实蔽。
幸運(yùn)的是它們依舊隨處可見。