Create by jsliang on 2019-2-11 15:30:34
Recently revised in 2019-3-17 21:30:36
Hello 小夥伴們,如果覺得本文還不錯,記得給個 star , 小夥伴們的 star 是我持續更新的動力!GitHub 地址
並不是只有特定的季節才能跑路,只因為人跑得多了,這條路就定下來了。
金三銀四跳槽季,jsliang 於 2019年2月11日 寫下了這篇文章,開始準備自己的面試之旅。
至 2019年3月17日 為止,jsliang 搭建出個人的面試知識體系,海量地翻閱了一些前輩留下的資料,結合個人需求進行了幾場面試,從而進一步完善該文章並進行了發表,希望對準備跳槽或者正在跳槽中的小夥伴有所幫助。
一 目錄
不折騰的前端,和鹹魚有什麼區別
二 前言
請時刻準備好自己的簡歷,不管是網際網路經濟不佳面臨裁員,還是因為公司內部鬥爭嚴重心亂如麻,還是因為厭倦了目前的一切……只有隨時更新自己,把自己的簡歷準備好,你才知道哪一刻跑路是最佳選擇。
2.1 自我介紹
Hello 小夥伴們好,我叫樑峻榮,網名叫 jsliang,由於崇拜前端大佬 技術胖(jspang)的原因,又因為自己學的是前端(JavaScript),所以給自己取了個 jsliang(JavaScriptLiang) 的網名,希望自己能通過建立自己的前端知識體系,從而在前端路上走得更遠。並將自己的經驗分享給小夥伴,攜手小夥伴們一起前行。
下面是講講個人故事:
首先,jsliang 高考後的暑期就聽大學師兄的建議,開始學習程式設計,那時候學習了 C 語言,覺得世界上最神奇的事情不過如此,敲兩下鍵盤,按下回車,電腦就會一閃一閃地響應我們!於是在大學的時候,陸陸續續學過 C、C#、.Net 等……。
-_-|| 由於學得都是基礎,又都還給老師了,在這裡就不多累述了。
然後,在大二就開始接觸 HTML,那時候選修了個《網頁設計基礎》,跟著老師做了個只有幾個頁面的靜態網站。在大三的時候,參加了學校的特訓班,分角色按流程從頭到尾做了個包含角色管理、購物等功能的網站。同時,由於在特訓班的時候,看到後端使用 ThinkPHP(簡稱 TP),覺得蠻不錯的,於是自己搗鼓,使用 TP 3.2.3 + Bootstrap 3 + MySQL 打造了自己的部落格(已下線)。
接著,由於選修了門 Node.js 的課,所以也跟著大佬的步伐接觸了下 Vue、Koa 這些,那時候對 npm 等諸多不懂,為了折騰這個,我的前端世界自此開啟了個大門。
最後,我在自己的畢業設計中使用 Node.js + Vue + ElementUI + MongoDB 打造了個校園外賣、快遞代拿等功能的社群單頁應用。
在 2018 年 5 月的時候,家裡催促,於是直接出來面試。不像其他大佬的畢業等於失業,很幸運地 jsliang 面試第一家就給了 offer,於是就進了這家公司,那時候感覺自己前面的大學生活白過了,只懂 ES5、jQuery、HTML/HTML5、CSS/CSS3 的皮毛。
在熟悉了三個月的業務,公司給的任務能順利完成後,我覺得自己不夠努力:外面的前端翻天覆地,我的技術卻只是 jQuery is all!
於是 2018 年 8 月,jsliang 開始寫 Markdown,將 5 月份到 8 月份記錄到 Word 文件上的筆記整理成了 jsliang 的文件庫,並在 jsliang 的掘金 上發表了第一篇文章。
18 年 8 月至今,jsliang 大致經歷了以下這些:
- 學 Webpack,並用 Webpack 構建一個多頁面配置。然後幸運的是,剛好碰到公司的一個仿站任務,於是整個前端小組直接用了我的 Webpack + jQuery + VS Code 的 Live Share 套路進行協同開發!
- 學 微信小程式,並將它應用到電信開發的微信小程式專案翼小微中。
- 學 ECharts 報表,並用它做了個 Vue + ECharts 的報表,來展示愛音樂公司的運營資料。
- 學 Node,然後搭了個企業網站(company.jsliang.top),並寫了篇小文章(目前最高成就,獲得了 1100 多贊)。
- 學 Vue,由於之前學的 Vue,在工作上有好多沒有,逐漸淡忘了,所以從基礎開始,準備寫一套《Vue 從 0 到 1》。
以上,就是 jsliang 的程式設計生涯。
今兒,在這裡寫寫 jsliang 為了跳槽,根據個人想法進行的一些前端面試資料整理,小夥伴們覺得不錯的點個贊或者去 GitHub 點個 star,覺得有誤請指出,謝謝~
2.2 跳槽原委
馬老闆曾經說過,跳槽有兩個原因:
- 錢沒給到位。
- 心被委屈了。
首先,如果非要給 jsliang 我自己的跳槽定個位,那肯定是錢沒給到位,勞動與產出不成正比。在我 2018 年 5 月入職前,與人事的交談中瞭解到每年的 8 月和 2 月可以提薪,當初的技術棧是:HTML、CSS、ES5。
然後,2018 年 6 月到 2019 年 1 月,學習並應用到工作中的技術有:
- jQuery
- Webpack
- JSP
- 微信小程式
- Vue
- ECharts
其中 2018 年 8 月剛轉正,也不敢說自己技術進步很大,也不敢說自己專案貢獻很大,為公司謀了多大利益,所以沒有提薪想法。
2019 年 1 月底感覺自己專案也做了,凌晨 4/5/6 點的體育西路也看過了,技術也提升了,於是跟人事交談,期望 2 月能加薪,人事表示年終述職演講得好的給提薪,2 月開工的時候表示提薪名單沒我份……
你沒看錯,提薪全靠 PPT。PPT 裡提高了不給,沒提就是沒有。
當初想法很簡單,你隨便加個 5/600 我也滿足了。
最後,jsliang 曾跟專案總監私下談話,建議可以發展一些新產品,這樣公司或許能獲取一些新收入,我也可以進一步挑戰我的技術。但是,由於我司是個老牌子公司,並且大部分依賴於接手電信專案進行擴張……
enm...所以心也委屈了。
在 2018 的努力下,GitHub 破 600 近 700 star,掘金破 10 萬閱讀量,3000 粉絲:
GitHub 見證:點選檢視
掘金見證:點選檢視
2.3 進擊目標
- 目標城市:廣州
- 目標薪資:10K - 15K
- 目標技術:
1. 熟悉 HTML/HTML5、CSS/CSS3、ES5/ES6。
2. 瞭解 OOP 概念,並嘗試在工作中使用過 OOP 技巧。
3. 對 MVC/MVVM 架構有一定了解,如有 Vue/React/Angular 或者 微信小程式開發經驗更佳。
4. 使用過 Bootstrap 或者 ElementUI 等 UI 庫,並對前端 UI 庫有一定的個人理解。
5. 瞭解 Git、Webpack 等工具。
6. 對 Java、Node.js 等後端程式設計有一定了解。
7. 一年及以上工作經驗。
複製程式碼
- 廣州前端分析:
- 廣州 13K 薪資要求:
- 2/3 年工作經驗。
- 熟悉 OOP,並能在工作中使用,且能獨立開發外掛等……
- 你可以不懂 Vue,但 React 你必須得會!
- 廣州 15k+ 薪資要求:
- 5 年+ 工作經驗。
- 全能,懂前端,熟悉後端,能寫文件……
- 帶領過小隊進行開發。
- 廣州異常偏科公司:
- 要求必須懂後端。
- 要求必須懂安卓或者 IOS 開發。
- 要求必須精通 jQuery 全家桶(jQuery UI、jQuery Mobile 等……)。
該分析資料來自 Boss 直聘
2.4 開篇點題
本文的知識點將涉及 HTML、CSS、JS、HTTP、Vue、Webpack、打包工具、效能優化等,沒有前置條件,看得懂可以瞅瞅複習下,看不懂可以瞅瞅學習下。
關於面試,在這記下慕課網視訊看到的,個人非常認同的三個問答:
- 問:拿到一個面試題,第一時間看到什麼? 答:考點
- 問:如何看待網上搜出來的永遠看不完的題海? 答:不變應萬變
- 問:如何對待面試題? 答:題目到知識再到題目
然後在複習面試題的過程中,個人有些小看法:
- 個人感言一:為什麼我總是比不上別人優秀?
當編寫業務程式碼中,碰到某個業務 bug 時,我會習慣性地百度這個業務 bug,看看網友是怎麼解決的。但是,學霸級的程式猿,會多走一步,他們會思考產生這個業務 bug 的底層原因是什麼,下次碰到類似的是如何應用該技術解決。所以,日積月累,我的確比不上人家了。
- 個人感言二:辭職並不是件便捷的事。
way 1:面試成功,跟自己公司遞辭呈,走流程,同時跟對面 hr 申請一個月後入職。
way 2:面試成功,跟自己公司遞辭呈,詢問能不能快速離職,收到回覆跟對面 hr 確認時間。【推薦】
way 3:先遞辭呈,同時面試,面試成功的,一律申請走完原公司一個月的流程之後的日子入職。
jsliang 於 2 月底拿到 offer 並遞交辭呈,3 月 - 4 月進入一個月倒數計時,4 月第一週才能拿到離職證明。
最後在這裡祝各位小夥伴能找到稱心如意的工作~
三 HTML
HTML 屬於結構層,負責描繪出內容的結構。
CSS 屬於表示層,負責如何顯示有關內容。
JavaScript 屬於行為層,負責內容應如何對事件做出反應。
3.1 HTML 學習推薦
3.2 HTML 語義化
語義化的含義就是用正確的標籤做正確的事情,HTML 語義化就是讓頁面的內容結構化,它有如下優點:
- 便於對瀏覽器、搜尋引擎解析;
- 便於盲人瀏覽網頁;
- 便於閱讀原始碼的人對網站進行分開,維護和理解;
簡單來說,能用 <header>
、<footer>
等 H5 新標籤的就不用 <div class="header">
,不要使用 <div>
來存放段落等……
3.3 HTML5 新標籤
HTML5 中新增標籤大致有:<header>
、<footer>
、<aside>
、<nav>
、<video>
、<audio>
、<canvas>
等等。
3.4 常見瀏覽器及其核心
Chrome | Firefox | Safari | IE | Opera | |
---|---|---|---|---|---|
排版引擎 | Blink | Gecko | Webkit | Trident | Blink |
JS 引擎 | V8 | SpiderMonkey | Nitro | Chakra | V8 |
國內一些瀏覽器使用較多的是 Webkit 核心。
- 針對不同瀏覽器核心,HTML 辨別:
- IE 核心瀏覽器識別:
<!--[if IE]><![endif]-->
- 非 IE 核心瀏覽器識別:
<!--[if !IE]><![endif]-->
- 針對不同瀏覽器核心,CSS 辨別:
/* 設定文字不可選取 */
* {
-moz-user-select: none; /* 火狐 瀏覽器 */
-webkit-user-select: none; /* Webkit 瀏覽器 */
-o-user-select: none; /* Opera 瀏覽器 */
-ms-user-select: none; /* IE10 瀏覽器 */
-khtml-user-select: none; /* 早期瀏覽器 */
user-select: none; /* 預設 */
}
複製程式碼
3.5 cookies、session、sessionStorage、localStorage
-
cookies:儲存於瀏覽器端的資料。可以設定 cookies 的到期時間,如果不設定時間,則在瀏覽器關閉視窗的時候會消失。
-
session:儲存於伺服器端的資料。session 儲存特定使用者會話所需的屬性和配置資訊。
-
cookies 和 session 的區別在於:
- cookies 資料存放在客戶的瀏覽器上,session 資料存放在伺服器上。
- 前端都是裸君子,沒有安全可言,cookies 可能會被黑客利用作資料欺騙。所以重要資訊記得存 session。
- session 如果在生效期內量過大,會佔用伺服器效能。
- 單個 cookies 儲存的資料不能超過 4 K,很多瀏覽器限制一個站點儲存最多 20 個 cookies。
-
sessionStorage:生命週期存在於標籤頁或視窗,用於本地儲存一個會話(session)中的資料,這些資料會隨著視窗或者標籤頁的關閉而被清空。
-
localStorage:生命週期是永久的,除非使用者主動清除瀏覽器上儲存的 localStorage 資訊,否則它將會永久存在。
-
sessionStorage 和 localStorage 操作方法:
setItem
、getItem
以及removeItem
。
以 localStorage 為例:
localStorage.getItem('name'); // 獲取 name 的值
localStorage.setItem('name', 'jsliang'); // 設定 name 的值為 jsliang
localStorage.removeItem('name'); // 刪除 name 的值
複製程式碼
參考 1:《前端分享之cookie的使用及單點登入》
參考 2:《Cookie、session和localStorage、以及sessionStorage之間的區別》
四 CSS
HTML 屬於結構層,負責描繪出內容的結構。
CSS 屬於表示層,負責如何顯示有關內容。
JavaScript 屬於行為層,負責內容應如何對事件做出反應。
4.1 CSS 學習推薦
4.2 CSS reset
在工作的過程中,會發現各式各樣的瀏覽器對某個標籤有自己獨特的樣式。
但是在前端開發中,如果不採用統一標準,那麼會產生千奇百怪的 bug。所以為了減少後期 bug 的出現,前端開發人員會重置一遍 CSS 樣式,儘可能地使開發的網頁在各個瀏覽器相差不大。
下面是 jsliang 在使用的樣式重置,當然如果小夥伴有不同的想法,可以去 百度/必應/google 搜尋並使用其他版本的樣式重置:
4.3 CSS 盒模型
在工作的過程中,也許小夥伴需要 div 塊的總寬度為 100px,然後發現總是被 margin 撐高,這是因為盒模型定義的問題:
CSS 中有個屬性叫 box-sizing
。
box-sizing: border-box
box-sizing: content-box
複製程式碼
border-box
中,整個div
的寬、高,包括margin
、padding
、border
。content-box
中,整個div
的寬、高,則不包括上面元素。
如上圖,如果一個 div
,你的程式碼如下:
div {
box-sizing: border-box;
margin: 10px;
width: 100px;
height: 100px;
padding: 10px;
}
複製程式碼
那麼,你的整個寬高還是 100px
。
但是,如果你的程式碼如下:
div {
box-sizing: content-box;
margin: 10px;
width: 100px;
height: 100px;
padding: 10px;
}
複製程式碼
那麼,你的整個盒子寬高是 120px
。
如果你在設計頁面中,發現內容區被撐爆了,那麼,請檢查下現在的 border-box
是什麼,最好在引用 reset.css
的時候,就對 border-box
進行統一設定,方便管理。
4.4 CSS 單位
在 CSS 中,除了我們常用的 px
,還有其他單位小夥伴們可以瞭解一下:
單位 | 描述 |
---|---|
% | 百分比 |
px | 畫素。計算機螢幕上的一個點為 1px 。 |
em | 相對單位。相對於父元素計算,假如某個 p 元素為 font-size: 12px ,在它內部有個 span 標籤,設定 font-size: 2em ,那麼,這時候的 span 字型大小為:12 * 2 = 24px |
rem | 相對單位。相對於根元素 html 的 font-size ,假如 html 為 font-size: 12px ,那麼,在其當中的 div 設定為 font-size: 2rem ,就是當中的 div 為 24px 。 |
rpx | 微信小程式相對單位。1rpx = 螢幕寬度 / 750 px。在 750px 的設計稿上,1rpx = 1px。 |
除此之外還有 pt、ex 等單位,但由於不太好換算,故在此不提。
4.5 CSS 選擇器
選擇器是匹配元素的一種模式。
- 關於 CSS 解析器:
HTML 經過解析生成 DOM Tree;而在 CSS 解析完畢後,需要將解析的結果與 DOM Tree 的內容一起進行分析建立一棵 Render Tree,最終用來進行繪圖。
Render Tree 中的元素與 DOM 元素相對應,但非一一對應:一個 DOM 元素可能會對應多個 renderer,如文字折行後,不同的「行」會成為 render tree 種不同的 renderer。也有的 DOM 元素被 Render Tree 完全無視,比如 display:none 的元素。
在建立 Render Tree 時,瀏覽器就要為每個 DOM Tree 中的元素根據 CSS 的解析結果來確定生成怎樣的 renderer。對於每個 DOM 元素,必須在所有 Style Rules 中找到符合的 selector 並將對應的規則進行合併。選擇器的「解析」實際是在這裡執行的,在遍歷 DOM Tree 時,從 Style Rules 中去尋找對應的 selector。
- CSS 解析順序
在 CSS 的選擇器中,它會按照優先順序 從右向左解析,因為這樣匹配元素的時候,能儘量少地查詢,所以選擇器最好寫地簡潔一點。
- CSS 常用選擇器
- 萬用字元:
*
- ID 選擇器:
#ID
- 類選擇器:
.class
- 元素選擇器:
p
、a
等…… - 後代選擇器:
p span
、div a
等…… - 偽類選擇器:
a:hover
等…… - 屬性選擇器:
input[type="text"]
等…… - 子元素選擇器:
li:firth-child
、p:nth-child(1)
等……
- CSS 選擇器權重
!important -> 行內樣式 -> #id -> .class -> 元素和偽元素 -> * -> 繼承 -> 預設
4.6 CSS 常見佈局
- 水平垂直居中。這種佈局老生常談,jsliang 在本文也有提到,詳解請 點選連結
- 兩列布局。一側固定,另一側自適應。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Two Column Layout</title>
<style>
.container {
display: flex;
}
.child-one {
width: 300px;
height: 300px;
background: red;
}
.child-two {
width: 100%;
height: 300px;
background: deepskyblue;
}
</style>
</head>
<body>
<div class="container">
<div class="child-one"></div>
<div class="child-two"></div>
</div>
</body>
</html>
複製程式碼
- 三列布局。類似於兩列布局,新增多一個固定寬的
<div>
塊而已。當然,小夥伴們可能會說:jsliang 你要考慮flex
的相容性啊!enm...支援所有最新版本的瀏覽器!請更新你的瀏覽器哦親~
避免被寄刀片,附上
float
佈局:《css常見佈局》
4.7 CSS3 新特性
經典:CSS3 相關屬性你瞭解嗎,說說都有哪些?能說說你工作中常用的一些 CSS3 屬性嗎?
那麼,CSS3 新特性都有哪些呢?
- transition:過渡
- transform:旋轉、縮放、移動或者傾斜
- animation:動畫
- gradient:漸變
- shadow:陰影
- border-radius:圓角
為了方便記憶,我們將它們扔到同一個 HTML 檔案上,小夥伴拷貝到本地上開啟,可以看到一個擁有漸變的小球,做著橫向運動,如果你滑鼠移動到它上面,它的寬度會放大,並且進行傾斜。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS3 新特性</title>
<style>
div {
width: 100px;
height: 100px;
border-radius: 50px;
background: linear-gradient(red, orange);
box-shadow: 10px 10px 5px #888888;
position: relative;
transition: width 2s;
animation: mymove 5s infinite;
}
div:hover {
width:300px;
transform: rotate(7deg);
}
@keyframes mymove {
from { left: 0px; }
to { left: 200px; }
}
</style>
</head>
<body>
<div></div>
</body>
</html>
複製程式碼
參考 1:《CSS3 圓角》
參考 2:《CSS3 漸變(Gradients)》
參考 3:《CSS3 transition 屬性》
參考 4:《CSS3 transform 屬性》
參考 5:《CSS3 animation(動畫) 屬性》
參考 6:《CSS3 box-shadow 屬性》
參考 7:《個人總結(css3新特性)》
4.8 BFC
- 什麼是 BFC?
BFC 就是 塊級格式上下文,它是一個獨立的渲染區域,讓處於 BFC 內部的元素和外部的元素相互隔離,使內外元素的定位不會相互影響。
一定的 CSS 宣告可以生成 BFC,瀏覽器對生成的 BFC 有一系列的渲染規則,利用這些渲染規則可以達到一定的佈局效果。
- 為什麼需要 BFC 呢?
- 它可以防止 margin 元素重疊(div 中包含 ul,而 div 與 ul 之間的垂直距離,取決於 div、ul、li 三者之間的最大外邊距,這時候給 ul 一個 display:inline-block 即可解決這個問題)
- 清除內部浮動(div 中包含 ul,而 ul 採用 float:left,那麼 div 將變成一長條,這時候給 div 加上規則使其變成 BFC 即可)
- 如何產生 BFC?
- display: inline-block
- position: absolute/fixed
- 工作中一般可能不會顧及這個:
- float 很少使用了,儘可能使用 flex
- css reset 一般會清除掉一些問題,減少 BFC 的使用。
參考文獻:《我對BFC的理解》
4.9 行內元素和塊級元素
行內元素:寬度和高度由內容決定,與其他元素共佔一行的元素,我們將其叫行內元素。例如:<span>
、<i>
、<a>
等……
塊級元素:預設寬度由父容器決定,預設高度由內容決定,獨佔一行並且可以設定寬高的元素,我們將其叫做塊級元素。例如:<p>
、<div>
、<ul>
等……
在日常開發中,我們經常使用 CSS 的 display
屬性來打破兩者的壁壘:display: inline-block
,使它們擁有更多的狀態。
4.10 行內樣式、內嵌式、連結式以及匯入式
在引用 CSS 上,分為四種形式:行內樣式、內嵌式、連結式以及匯入式,下面介紹這四種模式。
- 行內樣式
直接對 HTML 的標記使用 style 屬性,然後將 CSS 程式碼直接寫進去:
<p style="color: #fff; backgournd: deepskyblue;"></p>
複製程式碼
- 內嵌式
將 CSS 寫 <head>
與 </head>
之間,並且用 <style>
和 </style>
標記進行宣告:
<head>
<style>
p {
color: #fff;
background: deepskyblue;
}
</style>
</head>
複製程式碼
- 連結式
通過將 <style>
上的 CSS 提起到指定的 CSS 檔案上,然後通過 <link>
的方式在 HTML 上鍊接起來。
<head>
<link href="reset.css" type="text/css" rel="stylesheet">
</head>
複製程式碼
- 匯入樣式
<head>
<style>
@import url(reset.css);
</style>
</head>
複製程式碼
- 各種方式的優先順序
在優先順序上,行內樣式 > 連結式 > 內嵌式 > @import 匯入式。
4.11 水平垂直居中
- 什麼是 Flex 佈局?
Flex 是 Flexible Box 的縮寫,意為”彈性佈局”,用來為盒狀模型提供最大的靈活性。
- Flex 佈局有哪些便利
/* 設定 Flex 模式 */
display: flex;
/* 決定元素是橫排還是豎著排,要不要倒序 */
flex-direction: column;
/* 決定元素換行格式,一行排不下的時候如何排 */
flex-wrap: wrap;
/* flex-flow = flex-direction + flex-wrap */
flex-flow: column wrap;
/* 同一排下對齊方式,空格如何隔開各個元素 */
justify-content: space-between;
/* 同一排下元素如何對齊,頂部對齊、中部對齊還是其他 */
align-items: center;
/* 多行對齊方式 */
align-content: space-between;
複製程式碼
- 如何通過 Flex 實現元素水平垂直居中?
HTML
<div class="container">
<div class="child"></div>
</div>
複製程式碼
CSS
.container {
margin: 0 auto;
width: 300px;
height: 200px;
background: deepskyblue;
display: flex;
/* 實現元素水平居中 */
justify-content: center;
/* 實現元素垂直居中 */
align-items: center;
}
.child {
width: 100px;
height: 100px;
background: #fff;
}
複製程式碼
- 除了 Flex,還能使用其他形式進行水平垂直居中嗎?
HTML
<div class="container">
<div class="child"></div>
</div>
複製程式碼
CSS
.container {
position: relative;
width: 300px;
height: 200px;
background: pink;
margin: 0 auto;
}
.child {
position: absolute;
width: 100px;
height: 100px;
top: 50%;
left: 50%;
/* 下面兩種方式均可 */
/* margin-top: -50px;
margin-left: -50px; */
transform: translate(-50%, -50%);
background: #fff;
}
複製程式碼
- 除此之外再談談 CSS 水平居中或者垂直居中?
水平居中:
- 行內元素:
display: inline-block; text-align: center;
- 塊級元素:
margin: 0 auto;
- Flex:
display: flex; justify-content: center;
垂直居中:
- 行高 = 元素高:
line-height: height
- Flex:
display: flex; align-items: center;
參考文獻:
① 《CSS實現垂直居中的常用方法》
② 《CSS 用 position: absolute 與 transform 來居中塊級元素的問題》
五 JavaScript
HTML 屬於結構層,負責描繪出內容的結構。
CSS 屬於表示層,負責如何顯示有關內容。
JavaScript 屬於行為層,負責內容應如何對事件做出反應。
5.1 JS 學習推薦
- 《JavaScript 高階程式(第三版)》
- 《你不知道的 JavaScript》
- 《JavaScript 忍者祕籍》
- 《ES6 標準入門》—— 阮一峰
- 《JavaScript 設計模式》—— 張容銘
- 《JavaScript 設計模式與開發實踐》—— 曾探
5.2 JS 引用方式
- 行內引入:
<body>
<input type="button" onclick="alert('行內引入')" value="按鈕"/>
<button onclick="alert(123)">點選我</button>
</body>
複製程式碼
- 內部引入:
<script>
window.onload = function() {
alert("js 內部引入!");
}
</script>
複製程式碼
- 外部引入:
<body>
<div></div>
<script type="text/javascript" src="./js/index.js"></script>
</body>
複製程式碼
注意:
- 不推薦寫行內或者在 HTML 中插入
<script>
,因為瀏覽器解析順序緣故,如果解析到死迴圈之類的 JS 程式碼,會卡住頁面。 - 建議在 onload 事件之後,即等 HTML、CSS 渲染完畢再執行程式碼。
5.3 原型與原型鏈
關於 prototype
、__proto__
、new
、call()
、apply()
、bind()
、this
這些的知識點,由於篇幅太長,jsliang 已經抽離了出來,並做了簡潔詳細講解,詳見:
下面放出相關知識點:
- 例項的
__proto__
屬性(原型)等於其建構函式的prototype
屬性。 - Object.proto === Function.prototype
- Function.prototype.proto === Object.prototype
- Object.prototype.proto === null
5.4 作用域與閉包
在 JS 中,最容易混淆的就是作用域的情況。
在傳統的後端語言(例如 C 語言)中,一對花括號 {}
就是一個塊級作用域,作用域內變數不會相互影響,但是在 JS 中,像 if 條件語句的 {}
就不算一個獨立的作用域:
var x = 1;
console.log(x); // 1
if(true) {
var x = 2;
console.log(x); // 2
}
console.log(x); // 2
複製程式碼
所以有時候我們就需要變通,通過自執行函式建立臨時作用域:
function foo() {
var x = 1;
console.log(x); // 1
if(x) {
(function(x) {
console.log(x); // 1
var x = 2;
console.log(x); // 2
})(x)
}
console.log(x); // 1
}
foo();
複製程式碼
說到建立臨時作用域,我們就不得不談一下閉包。
那麼,什麼是閉包呢?
閉包簡單定義:函式 A 裡面包含了 函式 B,而 函式 B 裡面使用了 函式 A 的變數,那麼 函式 B 被稱為閉包。
又或者:閉包就是能夠讀取其他函式內部變數的函式
function A() {
var a = 1;
function B() {
console.log(a);
}
return B();
}
複製程式碼
- 閉包經典問題:現在我們有一段程式碼:
for(var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
複製程式碼
請問這段程式碼輸出什麼?
答案:3 個 3。
解析:首先,for
迴圈是同步程式碼,先執行三遍for
,i 變成了 3;然後,再執行非同步程式碼setTimeout
,這時候輸出的 i,只能是 3 個 3 了。
- 那麼,我們有什麼辦法依次輸出 0 1 2 麼?
- 使用 let:
for(let i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
複製程式碼
在這裡,每個 let 和程式碼塊結合起來形成塊級作用域,當 setTimeout() 列印時,會尋找最近的塊級作用域中的 i,所以依次列印出 0 1 2。
如果這樣講不明白,我們可以執行下下面這段程式碼:
for(let i = 0; i < 3; i++) {
console.log("定時器外部:" + i);
setTimeout(function() {
console.log(i);
}, 1000);
}
複製程式碼
此時瀏覽器依次輸出的是:
定時器外部:0
定時器外部:1
定時器外部:2
0
1
2
複製程式碼
即程式碼還是先執行 for
迴圈,但是當 for
結束執行到了 setTimeout
的時候,它會做個標記,這樣到了 console.log(i)
中,i 就能找到這個塊中最近的變數定義。
- 使用立即執行函式解決閉包問題
for(let i = 0; i < 3; i++) {
(function(i){
setTimeout(function() {
console.log(i);
}, 1000);
})(i)
}
複製程式碼
以上,我們就講解完了閉包及解決閉包的方式。
觀點 1:有些資料表示閉包中產生的大量區域性變數,會造成記憶體消耗過大,從而造成網頁的效能問題。
觀點 2:有些資料表示目前瀏覽器引擎都基於 V8,而 V8 引擎有個 gc 回收機制,不用太過擔心變數不會被回收。
提示:所以,如果你覺得不夠保險,那就在退出函式之前,將不使用的區域性變數全部刪除。
5.5 淺拷貝與深拷貝
- 什麼是深拷貝?什麼是淺拷貝?
簡單來說,有兩個物件 A 和 B,B = A,當你修改 A 時,B 的值也跟著發生了變化,這時候就叫淺拷貝。如果不發生變化,就叫深拷貝。
- 為什麼會出現深拷貝與淺拷貝?
- 首先我們需要知道基本資料型別(number、string、boolean、null、undefined)與引用資料型別(無序物件,資料以及函式)。
- 然後在基本資料型別中,例如:
let a = 1; let b = a; a = 2; console.log(b)
。當我們嘗試這樣子寫時,b 在棧記憶體中開闢了一個新記憶體,所以 b 的值不會改變,仍是 1. - 接著在引用資料型別中,例如
let a = [1, 2, 3], b = a; a[0] = 3; console.log(b)
。當我們嘗試這樣子寫時,b 會偷懶,引用跟 a 同一塊的記憶體地址,從而 a 的修改會影響 b,使得 b 變成 [3, 1, 3]。 - 最後,我們可以知道在引用資料型別中,會產生淺拷貝的問題。
- 如何實現深拷貝?
- 首先我們嘗試使用遞迴去解決深拷貝:
function deepClone(obj) {
let objClone = Array.isArray(obj) ? [] : {};
if(obj && typeof obj === "object") {
for(key in obj) {
if(obj.hasOwnProperty(key)) {
// 判斷 obj 子元素是否為物件,如果是,遞迴複製
if(obj[key] && typeof obj[key] === "object") {
objClone[key] = deepClone(obj[key]);
} else {
// 如果不是,簡單複製
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
let a = [1, 2, 3, 4];
let b = deepClone(a);
a[0] = 2;
console.log(a, b);
// Console
// a = [2, 2, 3, 4];
// b = [1, 2, 3, 4];
複製程式碼
- 使用 JSON 物件的 parse 和 stringify
注意:採用 JSON 進行的深拷貝,無法拷貝到 undefined、function、symbol 這類資料,它是有小 bug 的深拷貝。
function deepClone(obj) {
let _obj = JSON.stringify(obj);
let objClone = JSON.parse(_obj);
return objClone
}
let a = [0, 1, [2, 3], 4];
let b = deepClone(a);
a[0] = 1;
a[2][0] = 1;
console.log(a, b);
// Console
// a = [1, 1, [1, 3], 4];
// b = [0, 1, [2, 3], 4];
複製程式碼
5.6 模組化與元件化
在前端發展中,隨著前後端分離,前端社群的不斷壯大,前端能做的事情越來越多,承受的任務越來越重,程式碼也就越來越長了。就好比 jsliang 個人使用 jQuery 開發的時候,動不動就上千行程式碼,這在一個編輯器上看起來就有點亂了。如果碰上沒有程式碼摺疊的編輯器,你就更加難受了。
有的小夥伴的編輯器不是 VS Code,也不能進行程式碼摺疊
所以,面對越來越多的程式碼,我們就急需將這些程式碼分門別類,將程式碼按功能劃分,將同一功能的程式碼整合在一起,於是就有了模組化開發:一個檔案就是一個模組,當我們需要某個檔案的時候,我們只需要引用這個模組即可……
首先,是 CommonJS 的提出,在 Node.js 以及 Webpack 都支援 CommonJS,它規定了一個檔案就是一個模組,檔案內部定義的變數屬於這個模組,不會對外暴露從而汙染全域性變數的規則。在 CommonJS 中,通過 exports 或者 module.exports 進行匯出,通過 require 進行 同步載入 所需要依賴的模組。由於它是同步載入模組的形式,所以比較通用於伺服器端。
然後,根據 CommonJS 只能同步載入的問題,AMD 根據瀏覽器的特性,進行了非同步載入模組的提出。同時,AMD 有個問題,就是在使用 require.js 的時候,必須提前載入所有模組。
接著,根據 AMD 的問題,CMD 提出來了:通過按需載入的形式,哪裡需要就呼叫哪裡,而不用等到所有的模組都載入了再解析。
最後,ECMA 國際推出了 ES6 的 modules。在 ES6 中,通過 export 關鍵字匯出模組,通過 import 關鍵字引用程式碼。當然,由於瀏覽器廠商諸多,ES6 在瀏覽器的尚不支援,目前主流做法是先將 ES6 通過 babel 編譯成 require。
當然,JS 都進行模組化了,jsliang 想起自己專案中的那一坨 CSS,真心沒有回顧的想法!所以我們還需要知道為了方便管理 CSS,大佬們還是有做事兒的:Less 以及 Sass,這兩者使 CSS 的編寫更有組織性和目的性了。
說起模組化,我們又可以順帶提及元件化了,一開始為了區分這兩者,jsliang 也是百度了大量文章,最後成功把自己整蒙了,還是說說感覺可以的解釋:
元件化更關注的是 UI 部分:彈出框、頭部,內容區、按鈕等,都可以編寫成元件,然後在適用的地方進行引用。而模組化更側重於功能或者資料的封裝,比如全域性的 JSON 配置檔案,比如通用的驗證方法,比如規範時間戳等。
所以,說到這裡,我們就可以提到前端工程化:將整個開發流程就行工程規劃,從而提高整個團隊的開發效率。
在前端工程化中,最重要的就是提高整個團隊在 編碼 -> 測試 -> 維護 這三個階段的生產效率。團隊的協調至關重要,將每個任務細分給各個成員,從而獲取極致的工作效率,是管理者最喜歡看到的。而在上面的模組化和元件化的應用,就屬於前端工程化中的一部分,其目的就是在一些複雜的專案中,方便團隊進行合作開發,提高生產效率。
參考文獻:
① 《到底什麼是前端工程化、模組化、元件化》
② 《【前端工程化系列】簡談前端模組化開發與開發規範》
③ 《個人關於模組化的理解》
④ 《元件化開發和模組化開發概念辨析》
⑤ 《JavaScript模組化 --- Commonjs、AMD、CMD、es6 modules》
⑥ 《淺談什麼是前端工程化》
5.7 物件導向與程式導向
- 什麼是程式導向與物件導向?
- 程式導向就是做圍牆的時候,由你本身操作,疊第一層的時候:放磚頭,糊水泥,放磚頭,糊水泥;然後第二層的時候,繼續放磚頭,糊水泥,放磚頭,糊水泥……
- 物件導向就是做圍牆的時候,由他人幫你完成,將做第一層的做法抽取出來,就是放磚頭是第一個動作,糊水泥是第二個動作,然後給這兩個動作加上步數,最後告訴機器人有 n 層,交給機器人幫你工作就行了。
- 為什麼需要物件導向寫法?
- 更方便
- 可以複用,減少程式碼冗餘度
- 高內聚低耦合
簡單來說,就是增加程式碼的可複用性,減少我們們的工作,使程式碼更加流暢。
- 手寫個物件導向程式碼?
function Person(name, phone) {
this.name = name;
this.phone = phone;
this.eat = function() {
console.log(name + " 吃飯");
}
return this;
}
let p1 = new Person("jsliang", "18818881888");
console.log(p1.name); // jsliang
p1.eat(); // jsliang 吃飯
複製程式碼
當然,jsliang 只能寫到這裡了,再寫下去就是設計模式等知識點了。
所以希望小夥伴們還是瞭解下物件導向思想,有助於進一步提升自己。
5.8 防抖與節流
關於 防抖與節流,jsliang 特意將資料結合起來:
- 防抖與節流
- 重繪與迴流
- 瀏覽器解析 URL
- DNS 域名解析
- TCP 三次握手與四次揮手
- 瀏覽器渲染頁面
小夥伴們可以前往 《面試知識點 - JS 防抖與節流》 檢視。
5.9 ES6
ES6 是個大知識點,如果你面試的公司不是 “飽經滄桑” 的那種,那麼一定會出點 ES6 問題,例如:
- 說說 let、var、const 區別
- 講講 Promise 及其使用
因為 jsliang 感覺自己連 ES6 的門還沒進,所以在這裡就不 自作聰明,推薦下阮一峰大佬的教程:
希望小夥伴們看完能有所收穫,並在工作中大量使用。
5.10 陣列操作
在 JavaScript 中,用得較多的之一無疑是陣列操作,這裡過一遍陣列的一些用法:
map
: 遍歷陣列,返回回撥返回值組成的新陣列forEach
: 無法break,可以用try/catch中throw new Error來停止filter
: 過濾some
: 有一項返回true,則整體為trueevery
: 有一項返回false,則整體為falsejoin
: 通過指定連線符生成字串push / pop
: 末尾推入和彈出,改變原陣列, 返回推入/彈出項【有誤】unshift / shift
: 頭部推入和彈出,改變原陣列,返回操作項【有誤】sort(fn) / reverse
: 排序與反轉,改變原陣列concat
: 連線陣列,不影響原陣列, 淺拷貝slice(start, end)
: 返回截斷後的新陣列,不改變原陣列splice(start, number, value...)
: 返回刪除元素組成的陣列,value 為插入項,改變原陣列indexOf / lastIndexOf(value, fromIndex)
: 查詢陣列項,返回對應的下標reduce / reduceRight(fn(prev, cur), defaultPrev)
: 兩兩執行,prev 為上次化簡函式的return值,cur 為當前值(從第二項開始)
相信小夥伴在工作中耍的已經是一套一套的了,或者像 jsliang 一樣只會簡單的使用 push
、map
這幾個,感興趣的小夥伴可以 百度/bing/google 找找一些 奇技淫巧,說不定對工作效率有很大提升~
六 Vue
推薦:
6.1 MVVM
在 MVVM 架構下,View 和 Model 之間並沒有直接的聯絡,而是通過 ViewModel 進行互動,Model 和 ViewModel 之間的互動時雙向的,因此 View 資料會同步到 Model 中,而 Model 資料的變化也會立即反應到 View 上。
ViewModel 通過雙向資料繫結把 View 層和 Model 層連線了起來,而 View 和 Model 之間的同步工作完全是自動的,無需人為干涉,因此開發者只需要關注業務邏輯,不需要手動操作 DOM,不需要關注資料狀態的同步問題,複雜的資料狀態維護完全由 MVVM 來統一管理。
- M - Model。Model 代表資料模型,也可以在 Model 中定義資料修改和操作的業務邏輯。
- V - View。View 代表 UI 元件,它負責將資料模型轉化為 UI 展現出來。
- VM - ViewModel。ViewModel 監聽模型資料的改變和控制檢視行為、處理使用者互動,簡單理解就是一個同步 View 和 Model 的物件,連線 Model 和 View。
6.2 生命週期
- 請大致講下 Vue 的生命週期?
- 建立前/後:在 beforeCreated 階段,Vue 例項的掛載元素
$el
和資料物件 data 以及事件還未初始化。在 created 階段,Vue 例項的資料物件 data 以及方法的運算有了,$el
還沒有。 - 載入前/後:在 beforeMount 階段,
render
函式首次被呼叫,Vue 例項的 $el 和 data 都初始化了,但還是掛載在虛擬的 DOM 節點上。在 mounted 階段,Vue 例項掛載到實際的 DOM 操作完成,一般在該過程進行 Ajax 互動。 - 更新前/後:在資料更新之前呼叫,即發生在虛擬 DOM 重新渲染和打補丁之前,呼叫 beforeUpdate。在虛擬 DOM 重新渲染和打補丁之後,會觸發 updated 方法。
- 銷燬前/後:在執行例項銷燬之前呼叫 beforeDestory,此時例項仍然可以呼叫。在執行 destroy 方法後,對 data 的改變不會再觸發周期函式,說明此時 Vue 例項已經解除了事件監聽以及和 DOM 的繫結,但是 DOM 結構依然存在。
- 什麼是 Vue 生命週期?
Vue 例項從建立到銷燬的過程,就是生命週期。從開始建立、初始化資料、編譯模板、掛載 DOM -> 渲染、更新 -> 渲染、銷燬等一系列過程,稱之為 Vue 的生命週期。
- Vue 有幾個生命週期,它們的作用主要是什麼?
8 個,建立前/建立後、掛載前/掛載後、更新前/更新後、銷燬前/銷燬後。Vue 生命週期的作用是方便我們通過它的生命週期,在業務程式碼中更好地運算元據,實現相關功能。
- 第一次頁面載入會觸發 Vue 哪幾個鉤子?
會觸發 4 個生命鉤子:建立前/建立後、掛載前/掛載後
- DOM 渲染在哪個週期就已經完成?
在 beforeMounted
時它執行了 render
函式,對 $el 和 data 進行了初始化,但此時還是掛載到虛擬的 DOM 節點,然後它在 mounted
時就完成了 DOM 渲染,這時候我們一般還進行 Ajax 互動。
6.3 雙向資料繫結
Vue 採用 資料劫持 結合 釋出者-訂閱者 模式的方式,通過 Object.defineProperty()
來劫持各個屬性的 setter 以及 getter,在資料變動時釋出訊息給訂閱者,觸發相應的監聽回撥。
- 第一步:需要 Observe 的資料物件進行遞迴遍歷,包括子屬性物件的屬性,都加上 setter 和 getter。這樣的話,給這個物件的某個值賦值,就會觸發 setter,那麼就能監聽到了資料變化。
- 第二步:Compile 解析模板指令,將模板中的變數替換成資料,然後初始化渲染頁面檢視,並將每個指令對應的節點繫結更新函式,新增監聽資料的訂閱者,一旦資料有變動,收到通知,更新資料。
- 第三步:Watcher 訂閱者是 Observer 和 Compile 之間通訊的橋樑,主要做的事情有:
- 在自身例項化時往屬性訂閱器(dep)裡面新增自己。
- 自身必須有一個 update() 方法
- 待屬性變動
dep.notice()
通知時,能呼叫自身的update()
方法,並觸發 Compile 中繫結的回撥,則功成身退。
- 第四步:MVVM 作為資料繫結的入口,整合 Observer、Compile 和 Watcher 三者,通過 Observer 來監聽自己的 model 資料變化,通過 Compile 來解析編譯模板指令,最終利用 Watcher 搭起 Observer 和 Compile 之間的橋樑,達到資料變化 -> 檢視更新;檢視互動變化(input) -> 資料 model 變更的雙向繫結效果。
js 實現簡單的雙向繫結
<body>
<div id="app">
<input type="text" id="txt">
<p id="show"></p>
</div>
<script>
window.onload = function() {
let obj = {};
Object.defineProperty(obj, "txt", {
get: function() {
return obj;
},
set: function(newValue) {
document.getElementById("txt").value = newValue;
document.getElementById("show").innerHTML = newValue;
}
})
document.addEventListener("keyup", function(e) {
obj.txt = e.target.value;
})
}
</script>
</body>
複製程式碼
Object.defineProperty 接收三個引數:物件,屬性名,配置物件
這裡使用的是 Object.defineProperty,這是 Vue 2.0 進行雙向資料繫結的寫法。在 Vue 3.0 中,它使用 Proxy 進行資料劫持。
- 為什麼 Vue 3.0 中使用 Proxy 了?
- Vue 中使用 Object.defineProperty 進行雙向資料繫結時,告知使用者是可以監聽陣列的,但是隻是監聽了陣列的 push()、pop()、shift()、unshift()、splice()、sort()、reverse() 這八種方法,其他陣列的屬性檢測不到。
- Object.defineProperty 只能劫持物件的屬性,因此對每個物件的屬性進行遍歷時,如果屬性值也是物件需要深度遍歷,那麼就比較麻煩了,所以在比較 Proxy 能完整劫持物件的對比下,選擇 Proxy。
- 為什麼 Proxy 在 Vue 2.0 編寫的時候出來了,尤大卻沒有用上去?因為當時 es6 環境不夠成熟,相容性不好,尤其是這個屬性無法用 polyfill 來相容。(polyfill 是一個 js 庫,專門用來處理 js 的相容性問題-js 修補器)
6.4 Virtual DOM
Vue 在 render
中 createElement
的時候,並不是產生真實的 DOM 元素,實際上 createElement
描述為 createNodeDescription
,因為它所包含的資訊會告訴 Vue 頁面上需要渲染什麼樣的節點。
因此,我們將這樣的節點描述為 “虛擬節點”(Virtual Node),簡稱 VNode。“虛擬 DOM” 是我們對由 Vue 元件樹建立的整個 VNode 樹的稱呼。
作為一枚切圖仔,很榮幸地跟小夥伴說:“其實我也不懂 Virtual DOM!”
但是,總會有些面試場合會提到的,所以這裡找了幾篇資料,小夥伴們可以進一步學習:
其他的就需要小夥伴自己尋找了,如果覺得有不錯的解析 Virtual DOM 的文件/視訊,小夥伴也可以推薦過來哈~
6.5 template 編譯
- Vue template 編譯的理解
Vue 中 template 就是先轉化成 AST 樹,再得到 render 函式返回 VNode(Vue 的虛擬 DOM 節點)。
- 通過 compile 編譯器把 template 編譯成 AST 語法樹(abstract syntax tree - 原始碼的抽象語法結構的樹狀表現形式),compile 是 createCompiler 的返回值,createCompiler 是用以建立編譯器的。另外 compile 還負責合併 option。
- AST 會經過 generate(將 AST 語法樹轉換成 render function 字串的過程)得到 render 函式,render 的返回值是 VNode,VNode 是 Vue 的虛擬 DOM 節點,裡面有標籤名、子節點、文字等待。
6.6 key
key 的作用就是在更新元件時判斷兩個節點是否相同。相同就複用,不相同就刪除舊的建立新的。
對於 diff 過程來說 key 是起不到提速作用的,詳見:key 的作用
6.7 nextTick
-
用法:
Vue.nextTick( [callback, context] )
-
引數:
{Function} [callback]
{Object} [context]
-
說明:在下次 DOM 更新迴圈結束之後執行延遲迴調。在修改資料之後立即使用這個方法,獲取更新後的 DOM。
-
案例:
// 修改資料
vm.msg = 'Hello'
// DOM 還沒有更新
Vue.nextTick(function () {
// DOM 更新了
})
// 作為一個 Promise 使用 (2.1.0 起新增,詳見接下來的提示)
Vue.nextTick().then(function () {
// DOM 更新了
})
複製程式碼
關於 nextTick 的更多理解,jsliang 就不獻醜了,需要學習的小夥伴可以檢視:
或者自行查詢更優秀的資源。
6.8 父子元件通訊
關於 Vue 中的父子元件通訊,相信經常開發 Vue 的小夥伴比 jsliang 知道的多很多。
沒怎麼使用 Vue 的小夥伴可以看下下面的文章,並嘗試自己寫一寫:
下面我們講下使用 bus.js 實現非父子元件通訊:
假設在工作中,有三個 .vue 檔案:A.vue、B.vue、C.vue。A.vue 是主頁面,B.vue 和 C.vue 類似於頭部導航條和底部導航欄。現在,B.vue 點選會切換路由,C.vue 需要獲取 B.vue 傳遞的資訊。
A.vue
<template>
<div>
<top-nav></top-nav>
<div class="container">
<router-view></router-view>
</div>
<bottom-nav></bottom-nav>
</div>
</template>
複製程式碼
bus.js
import Vue from 'vue';
// 使用 Event Bus
const bus = new Vue();
export default bus;
複製程式碼
B.vue
<template>
<div class="bottom-nav">
<div class="nav-one" @click="goToPage({path: '/HomeIndex', meta:'首頁'})">
<i class="icon-home"></i>
<span>首頁</span>
</div>
</div>
</template>
<script>
import bus from '../utils/bus'
export default {
methods: {
goToPage(route) {
this.$router.push(route.path);
bus.$emit('meta', route.meta);
}
}
}
</script>
複製程式碼
C.vue
<template>
<div class="top-nav">
<span class="title">{{title}}</span>
</div>
</template>
<script>
import bus from '../utils/bus'
export default {
data() {
return {
title: ''
}
},
created() {
bus.$on('meta', msg=> {
this.title = msg;
})
}
}
</script>
複製程式碼
七 微信小程式
微信小程式,簡稱小程式,英文名 Mini Program,是一種不需要下載安裝即可使用的應用,它實現了應用“觸手可及”的夢想,使用者掃一掃或搜一下即可開啟應用。
7.1 檔案主要目錄及檔案作用
- component —————————————————— 元件資料夾
- navBar —— 底部元件
- navBar.js —— 底部元件的 JS 程式碼
- navBar.json —— 底部元件的配置檔案
- navBar.wxml —— 底部元件的 HTML 程式碼
- navBar.wxss —— 底部元件的 CSS 程式碼
- pages ————————————————————— 頁面資料夾
- index —— 首頁
- index.js —— 首頁的 JS 程式碼
- index.json —— 首頁的配置檔案
- index.wxml —— 首頁的 HTML 程式碼
- index.wxss —— 首頁的 CSS 程式碼
- public ————————————————————— 圖片資料夾
- utils —————————————————————— 工具資料夾
- api.js —— 控制 API 的檔案
- md5.js —— 工具 - MD5 加密檔案
- timestamp.js —— 工具 - 時間戳檔案
- app.json ——————————————————— 設定全域性的基礎資料等
- app.wxss ——————————————————— 公共樣式,可通過 import 匯入更多
- project.config.json ———————— 專案配置檔案
複製程式碼
7.2 微信小程式生命週期
onLoad()
:頁面載入時觸發。onShow()
:頁面顯示/切入前臺時觸發。onReady()
:頁面初次渲染完成時觸發。onHide()
:頁面隱藏/切入後臺時觸發。onUnload()
:頁面解除安裝時觸發。
7.3 如何封裝資料請求
- 封裝介面:
專案/utils/api.js
// 將請求進行 Promise 封裝
const fetch = ({url, data}) => {
// 列印介面請求的資訊
console.log(`【step 1】API 介面:${url}`);
console.log("【step 2】data 傳參:");
console.log(data);
// 返回 Promise
return new Promise((resolve, reject) => {
wx.request({
url: getApp().globalData.api + url,
data: data,
success: res => {
// 成功時的處理
if (res.data.code == 0) {
console.log("【step 3】請求成功:");
console.log(res.data);
return resolve(res.data);
} else {
wx.showModal({
title: '請求失敗',
content: res.data.message,
showCancel: false
});
}
},
fail: err => {
// 失敗時的處理
console.log(err);
return reject(err);
}
})
})
}
/**
* code 換取 openId
* @data {
* jsCode - wx.login() 返回的 code
* }
*/
export const wxLogin = data => {
return fetch({
url: "tbcUser/getWechatOpenId",
data: data
})
}
複製程式碼
- 呼叫介面:
專案/pages/login/login.js
import {
wxLogin,
} from '../../utils/api.js'
複製程式碼
- 使用介面:
專案/pages/login/login.js
wxLogin({
jsCode: this.data.code
}).then(
res => {
console.log("【step 4】返回成功處理:");
console.log(res.data);
},
err => {
console.log("【step 4】返回失敗處理:");
console.log(err);
}
)
複製程式碼
7.4 頁面資料傳遞
- 通過 url 攜帶引數,在
onLoad()
中通過options
獲取 url 上的引數:
程式碼演示
<navigator url="../index/index?userId={{userId}}"></navigator>
<!-- 這兩段是分別在 HTML 和 JS 中的程式碼 -->
onLoad: function(options) {
console.log(options.userId);
}
複製程式碼
- 通過 Storage 來傳遞引數:
wx.setStorageSync('userId', 'jsliang');
wx.getStorageSync('userId');
複製程式碼
- WXML 傳遞資料到 JS
login.wxml
<text bindtap="clickText" data-labelId="{{userId}}">點選傳遞資料到 JS</text>
複製程式碼
login.js
clickText(e) {
console.log(e.currentTarget.labelid)
}
複製程式碼
- 元件呼叫傳參
元件接收資料:component-tag-name
Component({
properties: {
// 這裡定義了innerText屬性,屬性值可以在元件使用時指定
innerText: {
type: String,
value: 'default value',
}
}
})
複製程式碼
使用元件的頁面定義 json
{
"usingComponents": {
"component-tag-name": "../component/component"
}
}
複製程式碼
使用元件的頁面 HTML 程式碼
<view>
<!-- 以下是對一個自定義元件的引用 -->
<component-tag-name inner-text="Some text"></component-tag-name>
</view>
複製程式碼
- 通過介面呼叫傳遞引數
7.5 載入效能優化的方法
- 通過
this.$preload()
預載入使用者可能點選的第二個頁面。 - 元件化頁面,出現兩次以上的部分都進行封裝成元件。
- 提取共用的 CSS 樣式。
- 優化圖片:TinyPNG。
7.6 微信小程式與原生 APP、Vue、H5 差異
- 微信小程式優劣勢:
優勢:
- 無需下載
- 開啟速度較快
- 開發成本低於原生 APP
劣勢:
- 限制多。頁面大小不能超過 1M,不能開啟超過 5 個層級的頁面。
- 樣式單一。小程式內部元件已經成宿,樣式不可以修改。
- 推廣面窄。跑不出微信,還不能跑入朋友圈。
- 微信小程式 VS 原生 APP
微信小程式有著低開發成本、低獲客成本、無需下載的優勢。
- 微信小程式 VS H5
- 依賴環境不同。一個能在多種手機瀏覽器執行。一個只能在微信中的非完整的瀏覽器。
- 開發成本不同。一個可能在各種瀏覽器出問題。一個只能在微信中執行。
- 微信小程式 VS Vue
微信小程式看似就是閹割版的 Vue。
7.7 微信小程式原理
- 本質上就是一個單頁面應用,所有的頁面渲染和事件處理,都在一個頁面中進行。
- 架構為資料驅動的模式,UI 和資料分離,所有頁面的更新,都需要通過對資料的更改來實現。
- 微信小程式分為兩個部分:webview 和 appService。其中 webview 主要用來展示 UI,appServer 用來處理業務邏輯、資料及介面呼叫。它們在兩個程式中進行,通過系統層 JSBridge 實現通訊,實現 UI 的渲染、事件的處理。
八 瀏覽器
8.1 瀏覽器解析 URL
關於 瀏覽器解析 URL,jsliang 特意將資料結合起來:
- 防抖與節流
- 重繪與迴流
- 瀏覽器解析 URL
- DNS 域名解析
- TCP 三次握手與四次揮手
- 瀏覽器渲染頁面
小夥伴們可以前往 《面試知識點 - JS 防抖與節流》 檢視。
8.2 重繪與迴流
關於 重繪與迴流,jsliang 特意將資料結合起來:
- 防抖與節流
- 重繪與迴流
- 瀏覽器解析 URL
- DNS 域名解析
- TCP 三次握手與四次揮手
- 瀏覽器渲染頁面
小夥伴們可以前往 《面試知識點 - JS 防抖與節流》 檢視。
8.3 資料儲存
- 儲存於程式碼中,程式碼執行完畢釋放記憶體。
- 儲存於瀏覽器中,cookie 用於短期儲存使用者身份,登入狀態等較小的資訊;localStorage/sessionStorage 用於長期儲存資料,瀏覽器關閉不影響它們的記憶體,相比於 cookie,storage 能儲存較多;IndexedDB 是瀏覽器提供的接近於 NoSQL 的資料庫,允許儲存大量資料。
- 儲存於資料庫中。
8.4 記憶體管理與垃圾回收
V8 將記憶體分為兩類:新生代記憶體空間和老生代記憶體空間。
- 新生代記憶體空間:主要用來存放存活時間較短的物件。
- 老生代記憶體空間:主要用來存放存活時間較長的物件。
這兩者通過不同的演算法,對記憶體進行管理操作。
8.5 記憶體洩漏
-
意外的全域性變數:無法被回收。
-
定時器:未被正確關閉,導致所引用的外部變數無法被釋放。
-
事件監聽:沒有正確銷燬(低版本瀏覽器可能出現)。
-
閉包:會導致父級中的變數無法被釋放。
-
DOM 引用:DOM 被刪除時,記憶體中的引用未被正確清空。
-
如何檢視記憶體變化情況?
使用 Chrome 的 Timeline(新版本 Performance)進行記憶體標記,視覺化檢視記憶體的變化情況,找出異常點。
九 網路協議
9.1 網路分層
目前網路分層可分為兩種:OSI 模型和 TCP/IP 模型。
- OSI 模型
- 應用層(Application)
- 表示層(Presentation)
- 會話層(Session)
- 傳輸層(Transport)
- 網路層(Network)
- 資料鏈路層(Data Link)
- 物理層(Physical)
- TCP/IP 模型
- 應用層(Application)
- 傳輸層(Host-to-Host Transport)
- 網際網路層(Internet)
- 網路介面層(Network Interface)
更多詳情可以檢視下面這篇文章,裡面講得非常詳細:
9.2 HTTP/HTTPS
- HTTP:超文字傳輸協議(HTTP)是用於分散式,協作式和超媒體資訊系統的應用協議。它是Web上資料交換的基礎,是一種 client-server 協議,也就是說請求通常是由像瀏覽器這樣的接受方發起的。
- HTTPS:HTTPS(全稱:Hypertext Transfer Protocol over Secure Socket Layer),是以安全為目標的 HTTP 通道,簡單講是 HTTP 的安全版。即 HTTP 下加入 SSL 層,HTTPS 的安全基礎是 SSL,因此加密的詳細內容就需要 SSL。 它是一個 URI scheme(抽象識別符號體系),句法類同 http: 體系。用於安全的HTTP資料傳輸。https:URL 表明它使用了 HTTP,但 HTTPS 存在不同於 HTTP 的預設埠及一個加密/身份驗證層(在 HTTP 與 TCP 之間)。這個系統的最初研發由網景公司進行,提供了身份驗證與加密通訊方法,現在它被廣泛用於全球資訊網上安全敏感的通訊,例如交易支付方面。
9.3 HTTP 狀態碼
首先,我們大致區分下狀態碼:
- 1**開頭 - 資訊提示
- 2**開頭 - 請求成功
- 3**開頭 - 請求被重定向
- 4**開頭 - 請求錯誤
- 5**開頭 - 伺服器錯誤
然後,常見的狀態碼:
- 200 - 請求成功,Ajax 接受到資訊了。
- 400 - 伺服器不理解請求,工作中常見於跨域的時候後端給我報 400!
- 403 - 伺服器拒絕請求。
- 404 - 請求頁面錯誤。
- 500 - 伺服器內部錯誤,無法完成請求。
最後,小夥伴們如果想要了解更多,還是需要自行查詢資料的。
9.4 TCP 三次握手與四次揮手
關於 TCP 三次握手與四次揮手,jsliang 特意將資料結合起來:
- 防抖與節流
- 重繪與迴流
- 瀏覽器解析 URL
- DNS 域名解析
- TCP 三次握手與四次揮手
- 瀏覽器渲染頁面
小夥伴們可以前往 《面試知識點 - JS 防抖與節流》 檢視。
十 效能優化
通過優化從而提高頁面的載入速度。
10.1 HTML 優化
- 避免 HTML 中書寫 CSS 程式碼,因為這樣難以維護。
- 使用 Viewport 加速頁面的渲染。
- 使用語義化標籤,減少 CSS 程式碼,增加可讀性和 SEO。
- 減少標籤的使用,DOM 解析是一個大量遍歷的過程,減少不必要的標籤,能降低遍歷的次數。
- 避免 src、href 等的值為空,因為即時它們為空,瀏覽器也會發起 HTTP 請求。
- 減少 DNS 查詢的次數。
10.2 CSS 優化
- 優化選擇器路徑:使用
.c {}
而不是.a .b .c {}
。 - 選擇器合併:共同的屬性內容提起出來,壓縮空間和資源開銷。
- 精準樣式:使用
padding-left: 10px
而不是padding: 0 0 0 10px
。 - 雪碧圖:將小的圖示合併到一張圖中,這樣所有的圖片只需要請求一次。
- 避免萬用字元:
.a .b * {}
這樣的選擇器,根據從右到左的解析順序在解析過程中遇到萬用字元* {}
會遍歷整個 DOM,效能大大損耗。 - 少用 float:
float
在渲染時計算量比較大,可以使用 flex 佈局。 - 為 0 值去單位:增加相容性。
- 壓縮檔案大小,減少資源下載負擔。
10.3 JavaScript 優化
- 儘可能把
<script>
標籤放在body
之後,避免 JS 的執行卡住 DOM 的渲染,最大程度保證頁面儘快地展示出來。 - 儘可能合併 JS 程式碼:提取公共方法,進行物件導向設計等……
- CSS 能做的事情,儘量不用 JS 來做,畢竟 JS 的解析執行比較粗暴,而 CSS 效率更高。
- 儘可能逐條操作 DOM,並預定好 CSs 樣式,從而減少 reflow 或者 repaint 的次數。
- 儘可能少地建立 DOM,而是在 HTML 和 CSS 中使用
display: none
來隱藏,按需顯示。 - 壓縮檔案大小,減少資源下載負擔。
十一 演算法
在演算法這塊,jsliang 覺得自己還是比較薄弱的,如果小夥伴們跟 jsliang 一樣,也想豐富下這方面知識,歡迎一起刷 LeetCode 共同進步:
十二 其他
在 【其他】 這章,原本 jsliang 想談談面試中的一些小技巧,例如談薪;或者講講 HR 面需要詢問的問題,例如工作時長、加班機制、調薪機制等……
但是,最終看來,jsliang 的經歷還是有所欠缺,所經歷的面試不夠 “盛大”,所以說出的話可能就是 “胡言亂語”、“誤導觀眾”,故在此就不獻醜了,如果小夥伴們想知道更多,可以通過 QQ 群:798961601
找到我。
☆ 目前 jsliang 通過 3 天的請假,去了 5 場面試,收穫了 3 份 offer。
☆ 如果小夥伴不知道簡歷該怎麼寫、面試總是鎮靜不下來、總感覺面試沒譜,可以先找 jsliang 聊聊,我會講講個人的面試經歷,以及聽到的其他小夥伴的經歷~
十三 總結
在觀看這篇文章的過程中,小夥伴可能會有這些疑問:
- 看完覺得不過癮啊!你怎麼就這麼 “短” 啊?
回答:
系列套餐你值得擁有!
- 2019 面試實戰 - Round One
- 2019 面試實戰 - Round Two
- 2019 面試實戰 - Round Three
- 面試知識點 - JS 原型與原型鏈
- 面試知識點 - JS 防抖與節流
- 面試知識點 - 圖片
- 你這雜七雜八的都寫了什麼呀?看完我暈乎了!
回答:
每個人的學習經歷是不同的,所擁有的技術、知識點以及工作經驗等都是不同的。
所以 jsliang 的目的是通過這篇文章充實自己的同時,順帶挖掘自己的不足,例如物件導向造輪子、演算法問題等讓 jsliang 想進一步折騰,並應用到工作中。
因此,小夥伴應該根據自己實際去擴充套件補充屬於自己的知識點。
畢竟瞭解自己的,只有自己!
- 好像你這裡寫得也不是很全啊?看完我還是一知半解的!
回答:
每個人的目的都是不同的,不可能一篇文章寫完所有知識點,同時有些知識點可能 jsliang 也不感興趣、或者 jsliang 的層次不夠,接觸不到。
並且每個面試官都可能有自己的一套面試題,如果 jsliang 能將所有的面試題都寫出來,那還需要面試官做啥,大家都像考國家證照一樣直接電腦考試吧~(我也期待!!!)
如果小夥伴對文章存有疑問,想快速得到回覆。
或者小夥伴對 jsliang 個人的前端文件庫感興趣,也想將自己的前端知識整理出來。
或者小夥伴對文章後續的更新感興趣,掌握更多的面試技巧。
歡迎加 QQ 群一起探討:798961601
。
十四 參考文獻
本文中的許多內容,也許小夥伴看了會覺得眼熟,因為它們大部分是 jsliang 參考大量文獻,再經過刷選整理,最後根據自己理解後的一些闡述。
下面是個人覺得非常優秀的文章。
14.1 關於面試
- 《一位前端 2018 絕地求生記》
- 《中高階前端大廠面試祕籍,為你保駕護航金三銀四,直通大廠(上)》
- 《InterviewMap》
- 《一篇文章搞定前端面試》
- 《微信小程式必知面試題》
- 《微信小程式面試題,附答案》
- 《小程式踩過的那些面試題坑,附答案解決方法》
14.2 關於 HTML
- 《前端工程師手冊》
- 《HTML 教程- (HTML5 標準) - 菜鳥教程》
- 《前端分享之cookie的使用及單點登入》
- 《Cookie、session和localStorage、以及sessionStorage之間的區別》
14.3 關於 CSS
- 《前端工程師手冊》
- 《CSS 權威指南》
- 《CSS 揭祕》
- 《CSS 世界》
- 《我對BFC的理解》
- 《CSS實現垂直居中的常用方法》
- 《CSS 用 position: absolute 與 transform 來居中塊級元素的問題》
- 《css常見佈局》
- 《CSS3 圓角》
- 《CSS3 漸變(Gradients)》
- 《CSS3 transition 屬性》
- 《CSS3 transform 屬性》
- 《CSS3 animation(動畫) 屬性》
- 《CSS3 box-shadow 屬性》
- 《個人總結(css3新特性)》
14.4 關於 JS
- 【推薦】《JavaScript - MDN》
- 《小邵教你玩轉ES6》
- 《小邵教你玩轉JS物件導向》
- 《實現雙向繫結Proxy比defineproperty優劣如何》
- 《Vue 中關於 $emit 的用法》
- 《JavaScript 世界萬物誕生記》
- 《js中的new()到底做了些什麼??》
- 《MDN Function.prototype.call()》
- 《JavaScript中的call、apply、bind深入理解》
- 《箭頭函式 - 廖雪峰》
- 《ECMAScript 6 入門 - 阮一峰》
- 《Vue原理解析之Virtual Dom》
- 《virtual-dom(Vue實現)簡析》
- 《Vue.nextTick 的原理和用途》
14.5 關於其他
- 《前端效能優化最佳實踐》
- 《到底什麼是前端工程化、模組化、元件化》
- 《【前端工程化系列】簡談前端模組化開發與開發規範》
- 《個人關於模組化的理解》
- 《元件化開發和模組化開發概念辨析》
- 《JavaScript模組化 --- Commonjs、AMD、CMD、es6 modules》
- 《淺談什麼是前端工程化》
- 《前端分享之cookie的使用及單點登入》
- 《Cookie、session和localStorage、以及sessionStorage之間的區別》
- 《網路分層TCP/IP 與HTTP》
十五 網友反饋
檢視了下掘金評論區,感謝各位大大的反饋,由於本人將於 2019年4月1日 入職,故將一些個人覺得不錯的自己沒有察覺的知識點記錄下來,區分於原文,更為了猴年馬月後的下一次跳槽進一步完善。
意思就是,jsliang 這貨懶得改原文了,小夥伴們看著這裡進行知識點補充
- 閉包定義:
函式 A 裡面包含了 函式 B,而 函式 B 裡面使用了 函式 A 的變數,函式 B 被 return 了出去,那麼 函式 B 被稱為閉包。
box-sizing
屬性:
當值為 border-box
時,寬度 width = content + padding + border
,包含內邊距與邊框。
當值為 content-box
時,寬度 width = content
,不包含內邊距與邊框。
- em:
em
是一個相對的大小,這裡的相對於元素父元素的 font-size
。
- Side Project:
Side Project 對應的中文就是副業、業餘專案或者小專案。
感興趣的小夥伴可以去了解一下。
push
與shift
系列:
這裡原文已備註是有誤的,只是一時沒空,沒有修改。
- CSS 選擇器載入順序:
原文:!important -> 行內樣式 -> #id -> .class -> 元素和偽元素 -> * -> 繼承 -> 預設
網友:“應該是最後的優先順序最高。”
這裡最後的優先順序最高應該是指同等級優先順序覆蓋。瀏覽器通過 CSSParser 將 CSS 解析成 CSS Rule Tree 的時候,沒錯的話應該是按照原文中的排序先載入,然後同等級的時候,後面的屬性覆蓋前面的屬性。
- ARIA:
對於 HTML5 的語義化,ARIA 的意思是 Accessible Rich Internet Application,aria-*
的作用就是描述這個 Tag 在視覺化的情境中的具體資訊。例如:
aria-label
:為元件指定內建的文字標籤,用來替代開發者沒有使用<label>
標籤aria-labelledby
:會讀取與此具有相同的id
名的值
詳情可參考張鑫旭的 《WAI-ARIA無障礙網頁應用屬性完全展示》
- sessionStorage 和 localStorage:
文章描述不夠詳細。
- 兩列布局/三列布局:
child-tow
中設定width: 100%
的時候child-one
的寬度會隨機而變,設定flex: 1
就不會。所以看個人需求進行設定。- 文章中沒有講到應對相容性怎麼設定,可以考慮使用
float
進行相關的佈局。
- 淺拷貝與深拷貝:
可參考文章:《深拷貝的終極探索(90%的人不知道)》
Promise
與async
/await
:
文章描述不夠詳細。
- 跨域:
本來打算寫的,後面沒時間,給我刪了這塊,評論區有篇文獻參考:
以上,即為目前評論區的補充,感謝各位小夥伴的點贊支援。
jsliang 廣告推送:
也許小夥伴想了解下雲伺服器
或者小夥伴想買一臺雲伺服器
或者小夥伴需要續費雲伺服器
歡迎點選 雲伺服器推廣 檢視!
jsliang 的文件庫 由 樑峻榮 採用 知識共享 署名-非商業性使用-相同方式共享 4.0 國際 許可協議進行許可。
基於github.com/LiangJunron…上的作品創作。
本許可協議授權之外的使用許可權可以從 creativecommons.org/licenses/by… 處獲得。