胡哥面试视频手录
胡哥面試視頻手錄
- 胡哥面試手錄
- 1. 如何提高工作效率?
- 2. 面試的時候怎么自我介紹比較好?
- 3. 面試官問:“你還有什么想問的嗎?”,這個時候該怎么回答?
- 4. 面試的簡歷,應該從這五大方面去寫:
- 5. 你的近期和長期的職業規劃是怎樣的?
- 6. 前端工作中該如何與同事相處、溝通?
- 7. 面試官問,入職之后將如何開展工作,應該怎么回答?
- 8. 面試官:對于加班你怎么看?
- 9. 請描述一下,你以前公司的開發流程是怎么樣的?
- 10. Web 前端崗位工資的基本構成和發放。
- 11. 公司面臨一些問題,我們該何去何從?
- 12. 前端找工作,被公司工資壓價怎么辦?
- 13. async 和 await 的區別
- 1. 區別
- 2. 優點
- 3. 補充
- 14. 打包之后 dist 目錄過大,該如何解決
- 15. 接口安全該如何回答
- aes加密工具:crypto.js 對稱加密
- rsa加密工具:jsencrypt 算法
- 對稱加密與非對稱加密的區別是什么
- 16. keep-alive
- 17. vuex 如何回答?
- 18. 防抖節流
- 19. 時間復雜度和空間復雜度(非胡哥)
- 20. webpack的工作原理(打包原理)
- webpack的核心概念(天禹+熊鍵)
- 21. 數組扁平化算法
- 22. setTimeout時間為0_,程序發生了什么?
- 23. setTimeout時間誤差的解決辦法
- 24. js面向對象的相關總結
- es5:
- es6:
- 25. 高階函數
- 26. 瀏覽器引擎Chrome(v8)
- 27. 瀏覽器是如何渲染頁面的
- 28. js程序的執行順序是怎樣的?
- 29. vue-loader的作用
- 30. node可以通過哪些方法可以防止程序奔潰
- 31. http 和 https的區別
- 32. XSS攻擊是什么?如何避免?
- 33. csrf 攻擊(非胡哥)
- 34. css hack
- 35. src和href的區別
- 36. link和@import的區別?(非胡哥)
- 37. 胡哥快排
- 38. 邊界塌陷(外邊距重合)
- 未完待續。。。
胡哥面試手錄
1. 如何提高工作效率?
我是做前端工作的,我會把工作分為三個部分。
比如說:項目前、項目中期和項目后期。
這樣的話,我們在前、中、后期三個節點上面的效率就會得到最大的提升。
2. 面試的時候怎么自我介紹比較好?
注:你做自我介紹的時候,興趣愛好、學歷啥的簡歷上都有,不用拿來介紹。
我叫xxx,我掌握的技能有哪些?如:H5、C3、js、element-plus、node、vue等等。
在工作中我的打包工具用的是什么?如:webpack、vite。
我的版本控制工具(分布式)用的是什么?如:git
說完這些之后,最好加一些,在以前的工作當中,我們前端經常遇到的是什么問題?比如說接口安全的問題、常見的一些攻擊的問題、適配的問題等等。
3. 面試官問:“你還有什么想問的嗎?”,這個時候該怎么回答?
在這個時候,對于成熟的前端人員來說的話,想問的相對來說多一些:
4. 面試的簡歷,應該從這五大方面去寫:
個人信息:以簡潔明了為主。姓名、學歷、畢業院校、電話、郵箱,不要超過6項。
專業技能:以充實為主。把會的技能多寫上一些。
過往的經歷:過往的公司和時間要搭配,不要有空窗。
項目介紹:一到兩年(包裝2-3個項目)、三年(3-4個項目)。你工作3年就只有這3個項目嗎?回答:我放到簡歷上的項目,是我認為比較好的,其實其他的一些小的項目,有一些雷同的地方,我沒有往上寫,所以從中挑選了基本較好的項目。
注意點:
自我評價:本人比較善于溝通,團隊協作能力比較強,能夠完成領導交待前端相關的工作任務。
5. 你的近期和長期的職業規劃是怎樣的?
注意:聊的時候,一定不要跟人家談年限,最近兩年要干什么。。。
回答:我作為一個前端來說,我近期的職業規劃是把咱們公司的項目做好,另外呢,學無止境,把我的技術得以提升。多學一些組件、插件,多學一到兩款框架。
對于中長期的規劃來說的話,我打算呢將來我再研究一門后臺語言,比如說像Java、PHP、Python這些我研究一門,爭取研究一門之后,可以更加方便咱們前端跟后端去溝通,為咱們公司更好的去服務。另外呢,我也相信,咱們公司有合理的晉升機制和制度。所以呢,如果將來公司有這樣的機會,這種機會放在我跟前,我也是會毛遂自薦,服務好公司。
這就是我近期、中期和長期的一個職業規劃。
6. 前端工作中該如何與同事相處、溝通?
7. 面試官問,入職之后將如何開展工作,應該怎么回答?
如果公司錄用我了,我將會帶著我以前的技術和經驗,把這些東西帶到咱們的項目中,讓咱們的項目更好,更人性化。
我會快速的掌握咱們現在所寫的項目。包括它的路由是怎么架構的,接口的請求是怎么來處理的,還有它里面的一些難點重點的技術,我以前有沒有處理過。
這些都是我們前端人員在剛入職的時候要做的事情。以避免后邊在開展工作中遇到這些問題,再去處理就比較難處理了。
要考慮我是不是需要后臺或者其他的技術人員去配合,這個也要有一個正確的評估。為啥要評估這個呢?如果問題到了跟前再去跟后臺溝通,這樣的話,很可能會打亂后臺的工作計劃。
進入公司以后,我打算基于以上三個方面開展工作。
8. 面試官:對于加班你怎么看?
注意點:
回答:
我可以接受加班,不管是自己的原因還是其他的一些什么原因,都是可以免費接受的。
9. 請描述一下,你以前公司的開發流程是怎么樣的?
在我們公司以前技術部分這么幾個角色:
產品經理、UI、前端人員、后臺(后臺是一個統稱:Java、PHP、Android、iOS都是在寫后臺的業務邏輯),以上這些角色去進行項目開發。
前端在項目中的地位和工作流程:
產品經理: 當一個項目進來,最先跟這個項目客戶去接觸的一般是產品經理,產品經理的作用是:和客戶進行聊天,聊天的過程中,他會做一個產品需求文檔(說白了,就是客戶想要什么?),在這里面有一個重要的職責,有時候客戶很盲目,他不知道自己的需求到底是什么(比如說他想做一個賣菜的網站,他可能不知道什么是APP,但是他們會使用),這個時候產品經理要做的就是正確引導客戶需求。然后,產品經理需要把這些需求跟UI、前端等技術人員去講明白。
UI: 出了需求文檔之后,產品經理會把文檔給到UI、前端、后臺各一份。UI 把需求文檔做成原型圖(黑白的,像黑白照片)和設計圖,UI在整個工期里面大概要占到三分之一。當設計稿出來后,同時交給前端和后臺,因為基本上前端和后端干活是并行的。
前端: 開始根據頁面去制作各種各樣的效果。或者是DIA(diagram 圖表)或者是小程序。在這個過程中后臺也在干活。
后臺: 后臺就要開發它對應的數據管理部分。除此之外,后臺還需要去做 API 接口的東西,這個接口是為前端去開發的。
等到前端的頁面布局完了,后臺的接口也寫完了,剩下的就是前端去渲染數據,調用接口里面相對應的數據就可以了。這些完了之后,就是一個測試階段。
測試階段: 測試階段是 UI、前端、后臺都需要參與的,如果有專業的測試,他們的工作量就稍微會少一點。都參與可以保證出現問題可以及時得到處理。
部署: 測試完成之后,再把這個項目部署到客戶的服務器上去。
基本上整個工作流程就是這樣子的。
10. Web 前端崗位工資的基本構成和發放。
如:10k為例,我上家公司是這樣發放的:
基本工資:5000
崗位工資:如前端 3000
績效工資:2000左右(總工資的15%-20% )
績效工資是一個考核標準,干得好才有,你負責的部分出了問題會扣一部分或者扣除全部。
補貼補助:1000以內(話補、餐補、車補等等)。
社保公積金:一般情況下公積金+社保占 10%左右。
扣稅:5000以上需要交稅
真正到手的大概是九千左右的一個范圍
11. 公司面臨一些問題,我們該何去何從?
如果這個時候我走了,我會得到什么,我會失去什么?
我得到了:我得到的肯定是一份新工作,需要吃飯穿衣嘛這個很正常。
我失去了:我會失去老板和領導對我的信任,俗話說:“患難見真情”,如果我跟他們共渡難關,在工作中共同努力克服了困難,挺過這一關,那我在這個公司的價值會大大提升。而且我的口碑也會好很多。
每一個員工應該各司其職,盡職盡責把自己的工作做好,做好之后,才能夠讓公司踏踏實實,放心去解決問題。當然在自己的事情完成得很好的情況下,在力所能及的范圍之內去幫助其他的同事。如果一個團隊、一個公司的人都有這樣的想法,我覺得老板和領導一定會想盡辦法去解決公司的困難。
12. 前端找工作,被公司工資壓價怎么辦?
注:我說15000,HR壓榨成9000
做兩手準備:
這個時候跟 HR 去較勁,很大概率是會談崩的。
13. async 和 await 的區別
1. 區別
Async:
async 用來定義函數的,異步函數,打印函數名會得到一個promise對象。可以使用函數名稱來調用.then方法,如:函數名稱.then
async 內部實現,有返回值。其實是內部調用了 promise.resolve(),然后把它轉換成一個promise對象。如果出錯的話,調用的是promise.reject()。它用catch捕獲了一下
Await:
await 理論上來說后面可以跟任意的表達式。但是一般是跟promise的表達式
async function add() {const res = await 123console.log(res) // 123return res } console.log(add()) // 成功的promise,值是123await 等待后邊的promise對象執行完畢,拿到了promise.resolve()的返回值之后,在往后繼續去執行后邊的代碼,所以await有一個等待的意思。
await關鍵字只能寫在async的函數里。
await 后邊的表達式可能是失敗的,await 只能拿到成功的結果,如果失敗會向瀏覽器控制臺拋出錯誤。所以建議把await的代碼放到try…catch語句中捕獲錯誤會比較好。
async function test() {const res = await Promise.reject(123)return res } console.log(test()) // Uncaught (in promise) 123 async function test() {try {const res = await Promise.reject(123)} catch (error) {console.log('error', error) // 2. error 123} } console.log(test()) console.log(111) // 1. 1112. 優點
- async和await屬于ES2016(ES7)的語法。
- async和await是異步執行的,但是寫代碼的時候是同步的
- async和await方式更容易讓開發人員維護
3. 補充
promise 和 async await 區別:
- promise 屬于es6的語法,promise是鏈式調用的
- promise中包含了catch,而async和await是在函數內自己定義catch
- promise 提供方法要多一些。如:all, race, any, finally(原型方法), then(原型方法), catch(原型方法)
?
14. 打包之后 dist 目錄過大,該如何解決
命令:npm run build
需要在vue.config.js中配置 entry, output
處理方案:
打包后,會在dist下生成.map文件,那么這個文件其實是不必要的
解決:在vue.config.js中配置文件中:productionSourceMap: false。這樣就不會生成.map文件了。
使用組件和路由懶加載
組件和路由懶加載是按需加載的,這樣會降低一些文件的大小。
對于文件和圖片,最好壓縮一下。可以使用這個組件(此組件需要安裝):compression-webpack-plugin
導入組件:compression-webpack-plugin
配置:
- 最小化代碼配置 minisize(true)
- 分割代碼 splitChunks
- 超過限定值的文件進行壓縮 threshold: 文件大小(字節為單位)
15. 接口安全該如何回答
安全問題是一個很寬泛的問題,如:xss和csrf攻擊等等。
這里主要談論的是接口的安全問題。
接口安全:防止傳輸過程中,數據被抓包。我們會在數據傳輸的時候(前臺傳給后臺,后臺傳給前臺)進行加密和解密。
常用的加密算法:
aes rsa SHA1 SHA256 md5 … 有很多的算法
胡哥用過的有 aes rsa
aes加密工具:crypto.js 對稱加密
aes加密工具的使用:
安裝:npm i crypto-js –save -dev
在utils工具文件夾下創建crypto.js文件
crypto.js中寫入
import cryptojs from 'crypto-js' export default {encrypto(str) { // 加密// 生成秘鑰// 秘鑰是前端和后端都知道的,但是網絡上是不知道的,所以他們截取去了也沒有用。比如說我們前端生成秘鑰是11111,那么后端也要用11111去解密let key = crytojs.enc.utf8.parse('11111') // 生成偏移量 --- 一般都是傳進來的字符串// 生成偏移量作用:如果字符串內容長度不夠,會自動補齊let srcs = cryptojs.enc.utf8.parse(str)// 加密 --- 參數:偏移量,秘鑰,配置加密的參數let encrypted = cryptojs.AES.encrypt(str,key,{mode: cryptojs.mode.ECB, // 加密模式// ECB 表示等量加密,就是說長度跟你的str相同padding: crytojs.pad.pkcs7 // 加密、解密的標準})return encrypted.toString()},decrypto(str) { // 解密let key = crytojs.enc.utf8.parse('11111') // 解密不需要偏移量// 加密 --- 參數:偏移量,秘鑰,配置加密的參數let decrypted = cryptojs.AES.decrypt(str,key,{mode: cryptojs.mode.ECB, // 加密模式// ECB 表示等量加密,就是說長度跟你的str相同padding: crytojs.pad.pkcs7 // 加密、解密的標準})return decrypted.toString()} }注意:
rsa加密工具:jsencrypt 算法
jsencrypt 算法是一種非對稱加密算法,它得生成一對秘鑰,即公鑰和私鑰。前后端一樣的,加密的時候使用公鑰,解密的時候使用私鑰。
長度可以能是1024也可能是2048。已知破解的密碼長度為:768位。
rsa加密工具的使用:
安裝:npm i jsencrypt
在utils工具文件夾下創建jsencrypt.js文件
jsencrypt.js文件中寫入:
這里是生成公鑰 - 加密
function enjsencrypt(str) {var jsObj = new jsencrypt()var pubkey = ""jsObj.setPublicKey(pubkey)return jsObj.encrypt(str) }這里是生成私鑰 - 解密
function denjsencrypt(str) {var jsObj = new jsencrypt()var prikey = ""jsObj.setPublicKey(prikey)return jsObj.dencrypt(str) }詳解博客地址
對稱加密與非對稱加密的區別是什么
16. keep-alive
keep-alive 組件緩存,刷新的時候保持狀態。
keep-alive 緩存組件,避免組件內的數據重復渲染,直接可以在頁面中調用。
注意看描述:我有一個導航欄,一級導航欄新聞、房產兩個。二級導航欄,新聞下有體育、財經。我給整個一級導航欄新聞做了組件緩存。如:<keep-alive includes="News"></keep-alive>。
問題:我先點擊新聞,然后點擊體育,我再點擊房產。當我點擊新聞的時候,我希望它能回到上一次的狀態體育。但是它不會。直接停留到新聞頁面了。
需求:點擊新聞–》點擊體育–》點擊社會–》回到新聞下的體育頁面
解決:
當點擊新聞的時候,有兩個方法會觸發:activated 和 deactivated
在新聞組件中寫:
let url; beforeRouteLeave() {url = this.$route.path } activated() {this.$router.push(url) }胡哥當前視頻地址
17. vuex 如何回答?
vuex存放數據的狀態
需要安裝:npm i vuex
state 公共數據 組件中this.$store.state.變量名
mutations 同步方法 更新state中的數據
actions 異步方法,組件通過this.$store.dispatch(‘方法名’, 參數)
getters 讀取state中的數據
commit 狀態提交,對mutation進行提交
vuex頁面刷新,數據會重置。這里涉及到持久化的問題
解決:
把vuex中的數據放到localStorage中
插件vuex-persistedstate 這個插件需要安裝,然后在vuex中添加配置。
plugins: [createPersistedState({storage: window.sessionStorage })]persistedstate 本質是使用了localStorage
18. 防抖節流
返回頂部:到達一定距離才會出現。
監聽瀏覽器的滾動時間,返回當前滾動條與頂部的距離。
<div>里面的內容足夠多,讓其有滾動條出現</div> <script> function showTop() { // 兼容獲取滾動條位置var scrollTop = document.body.scrollTop || document.documentElement.scrollTopconsole.log('滾動條位置', scrollTop) }window.onscroll = showTop <script>問題:滾動條滾動時,方法觸發太頻繁
防抖
第一次觸發事件,不要立即執行,給出一個事件間隔,比如200ms
<= 200ms 大于等于200毫秒,沒有觸發,那就執行函數
<= 200ms 大于等于200毫秒,再次觸發滾動,當前的計時取消,重新計時
思路:如果短時間內,大量執行事件,那就執行一次
實現:setTimeout + 閉包
<div>里面的內容足夠多,讓其有滾動條出現</div> <script>function showTop() {// 兼容獲取滾動條位置var scrollTop = document.body.scrollTop || document.documentElement.scrollTopconsole.log('滾動條位置', scrollTop)}function debounce(fnName, delay) { // 實現間隔調用showToplet timer = nullreturn function() {// 1000毫秒以內,這個timer存在了,那么就清除timerif(timer) {clearTimeout(timer)}// 1000毫秒以內,這個timer不存在。setTimeout 返回的是一個ID號,從1開始timer = setTimeout(fnName, delay) // setTimeout(showTop, 1000)} }window.onscroll = debounce(showTop, 1000) </script>節流
個人感覺這里用節流會更好(沛華的代碼)
原理:在一定時間內只執行一次,降低觸發頻率
實現:閉包
<div>里面的內容足夠多,讓其有滾動條出現</div> <script>function showTop() {// 兼容獲取滾動條位置var scrollTop = document.body.scrollTop || document.documentElement.scrollTopconsole.log('滾動條位置', scrollTop)} function throttle(fnName, delay) { // 實現間隔調用showToplet lastTime = 0return function() {// 獲取當前時間let nowTime = Date.now()// 如果當前時間 - 上一次的時間 < 傳進來的時間 // 如:100 - 0 < 1000 嗎?如果小于1000,那就直接return了if(nowTime - lastTime < time) {return}// 大于傳進來的時間就會執行下面的代碼fnName.call(this)lastTime = nowTime} }window.onscroll = throttle(showTop, 1000) <script>19. 時間復雜度和空間復雜度(非胡哥)
定義:
20. webpack的工作原理(打包原理)
從入口文件開始出發,根據入口文件的依賴關系找到所有的模塊
調用各種loader進行處理,如果遇到處理不了的調用babel進行語法轉換。(babel-loader core preset)
如果一些功能性的,如壓縮等這個時候就要調用plugins中相應的插件來進行處理
編輯階段 —》根據出口的路徑,打包多個chunk,如果把css和html等都摘出去了,那么就會打包多個chunk,最后統一生成一個bundle
loader plugin babel 的區別
- loader用于處理各種類型文件的
- plugin是用于loader處理不了的,一些功能性的插件
- babel 是一個 JavaScript 編譯器。將es6+的語法轉換成瀏覽器所認識的js代碼。babel是一個獨立的工具,可以不在webpack中使用。
工程化:
狹義上的理解: 將開發階段的代碼發布到生產環境,包含:構建,分支管理,自動化測試,部署
廣義上理解: 前端工程化應該包含從編碼開始到發布,運行和維護階段
webpack的核心概念(天禹+熊鍵)
什么是 webpack(熊鍵)
- Webpack 是一個模塊打包器(bundler)。
- 在 Webpack 看來, 前端的所有資源文件(js/json/css/img/less/…)都會作為模塊處理。
- 它將根據模塊的依賴關系進行靜態分析,生成對應的靜態資源。
五大“護法”(熊鍵)
- Entry:入口起點(entry point)指示 webpack 應該使用哪個模塊,來作為構建其內部依賴圖的開始。
- Output: output 屬性告訴 webpack 在哪里輸出它所創建的 bundles,以及如何命名這些文件,默認值為 ./dist。
- Loader: loader 讓 webpack 能夠去處理那些非 JavaScript 文件(webpack 自身只能解析 JavaScript)。
- Plugins:插件則可以用于執行范圍更廣的任務。插件的范圍包括,從打包優化和壓縮,一直到重新定義環境中的變量等。
- Mode:模式,有生產模式 production 和開發模式 development。
理解 Loader
- Webpack 本身只能加載 JS/JSON 模塊,如果要加載其他類型的文件(模塊),就需要使用對應的 loader 進行轉換/加載。
- Loader 本身也是運行在 node.js 環境中的 JavaScript 模塊。
- 它本身是一個函數,接受源文件作為參數,返回轉換的結果。
- loader 一般以 xxx-loader 的方式命名,xxx 代表了這個 loader 要做的轉換功能,比如 json-loader。
loader常處理的文件類型(天禹)
- 【file-loader】:提取源代碼圖片資源,到指定位置,可修改文件名等操作。
- 【url-loader】:與file-loader功能幾乎一致,優勢是可以對圖片進行動態轉換base64編碼(控制limit屬性值可以控制閾值)。
備注:上述兩個loader中url-loader應用比file-loader廣泛。 - 【eslint-loader】:對項目中的js語法進行檢查。
- 【babel-loader】:將es6語法轉換為es5語法
備注1:直接使用只能處理簡單的語法,Promise等無法處理。
備注2:借助polyfill完成高級es6語法的轉換,缺點:所有都轉換,無法按需轉換,生成的js體積大。
備注3:使用core-js配合polyfill完成按需轉換。
常用的 loader 有(熊鍵):
- eslint-loader:審查代碼是否存在語法錯誤。
- babel-loader:將 es6 以上的語法編譯成 es5 及以下的語法。
- style-loader:是將 css-loader 打包好的 css 代碼以<style>標簽的形式插入到 html 文件中。
- css-loader:用于解釋 @import 和 url(),并通過 import 后進行解析,通常和 style-loader 結合使用。
- less-loader:將 less 語法編譯成 css 語法。
問題:
eslint-loader 配置:“0” “1” "2"代表什么?
- eslint 要想工作,必須定義配置文件,配置文件有兩種寫法
- .eslintrc.*
- package.json 文件中 eslintConfig
- 我們以第一種為例,項目根目錄新建.eslintrc.js
plugin常用插件
-
【extract-text-webpack-plugin】:用于提取項目中的css, 最終合并為一個單獨的文件。
備注:上述插件需要配合:css-loader、less-loader兩個loader使用,css-loader、less-loader處理之后,交給extract-text-webpack-plugin處理。
-
【html-webpack-plugin】:自動創建html文件,且自動引入外部資源。配置項如下:
-
【clean-webpack-plugin】:清空webpack的輸出目錄,防止其他文件“亂入”。
-
【MiniCssExtractPlugin 】:用于提取css為單獨文件
21. 數組扁平化算法
如:let arr = [1, [2], [3], [4]]
多維數組轉成一維數組,遞歸:逐層遍歷數組,數組的每個元素取出,拼接成新數組
// 數組扁平化 let arr = [1, [2, [3, [4]]]] // 方法一:使用es6的flat() // console.log(arr.flat(Infinity))// 方法二:使用遞歸 function flat(arr) { let result = [] // 判斷是否傳進來是數組 if (!Array.isArray(arr)) {// 不是數組,就把數據壓入result中result.push(arr) } else {for (let i = 0; i < arr.length; i++) {// console.log(arr[i])// 第一次進來這樣寫:result = result.concat(arr[0])// 第二次進來,又是一個數組,那又得調用flat(),重新從上往下執行函數:result = result.concat(arr[1])result = result.concat(flat(arr[i]))} } return result } console.log(flat(arr))視頻鏈接
22. setTimeout時間為0_,程序發生了什么?
// setTimeout(fun, 時間) setTimeout(() => {console.log(11) }, 0) console.log(22)分析:
- 代碼從上往下執行,當執行到setTimeout的時候,setTimeout是同步代碼,setTimeout里面的回調是異步代碼。
- 此時會把setTimeout里面的回到函數放入到計時器管理模塊中。
- 同步代碼執行完成后,當過了0秒(馬上),會把當前的回調放入到宏隊列中,如果微隊列的代碼執行完成后,會執行宏隊列中的代碼,然后依次執行宏隊列中的定時器回調。
事件輪詢中有個重要模塊:郎金杰
- 事件管理模塊
- 定時器管理模塊。
- dom 時間管理模塊。
- ajax 管理模塊。
- MutationsObserver 管理模塊。
- 回調對列:
- 宏任務:
- setTimeout,setInterval,ajax,dom事件監聽等。
- 微任務
- promise中的.then函數,async/await,mutationsobserver等。
- 宏任務:
23. setTimeout時間誤差的解決辦法
setTimeout(fun, 1000) 間隔1000毫秒執行
代碼的執行:
同步代碼執行時間:會先等待同步代碼執行完成,開始執行異步代碼。
異步代碼執行時間:在執行異步代碼的時候,會有等待的時間,因為要等前面隊列中的代碼都執行完成之后,才會執行這個setTimeout中的回調。
響應時間:比如你在美國訪問了京東setTimeout的倒計時,那么美國看到的京東倒計時一定有問題,響應過去都得3秒至少,setTimeout沒法1秒就執行。
在現實中setTimeout在執行的時候:等待時間 + 執行時間 + 響應時間。所以在現實中執行基本是大于1000毫秒的。
統計誤差時間:
/* 獲取時間戳的四種方式let start = new Date().valueOf()let start = new Date().getTime()let start = Date.now()let start = +new Date() */ setInterval(() => {let n = 0while (n++ <= 1000000) {} }, 1000) // 統計誤差 // 開始時間 let start = new Date().getTime() // 程序執行的秒數 let count = 0 // 間隔時間 let inits = 1000 let timer = setTimeout(fun, inits)function fun() {count++// 誤差時間 = 現在的時間 - (開始時間 + count * 1000)// 如果 誤差時間 = 計算出來的時間,那就沒有誤差。let errorTime = new Date().getTime() - (start + count * 1000) + 'ms'console.log(errorTime)// 解決思路:誤差時間累加(當誤差達到1000ms之后,不要count++,而是+2)。 }24. js面向對象的相關總結
面向對象(Object Oriented Programming, OOP),是一種編程思想
es5:
創建對象:
function 函數名(){} ==》new 函數名 ==》得到對象(類的實例對象)
字面量 {}
new Object()
面型對象的三大特征:
封裝:將對數據的操作細節隱藏起來,只暴露對外的接口。外界調用不需要(也不可能)知道細節,就能通過對外提供的接口來訪問該對象,同時也保證了外界無法任意更改對象內部的數據
繼承:子類可以繼承父類的屬性和方法
多態:同一個方法,在子類和父類中都可以定義,只是內容不同。
由繼承而產生了相關的不同的類,對同一個方法可以有不同的響應。比如 Cat 和 Dog 都繼承自 Animal,但是分別實現了自己的 eat 方法。此時針對某一個實例,我們無需了解它是 Cat 還是 Dog,就可以直接調用 eat 方法,程序會自動判斷出來應該如何執行 eat
OOP的優勢:
**遍歷對象:**for … in
對象轉化成字符串:
-
{} ==> string 使用 JSON.stringify()
-
string ==> {} 使用 JSON.parse()
繼承:
構造函數繼承(屬性繼承)
/* 屬性繼承:在子類調用父類函數,用call改變this指向 */function Father(uname, age){this.uname = uname;this.age = age;console.log('Father-this',this); }// var o = new Father('張三豐', 22); // 這里的this是Father // console.log('o', o);// 繼承 function Son(uname, age, score){// Father(uname, age);這樣寫的this指向不同,此時Father里面的this指向的是window// Father(uname, age);// 如果調用Father函數,并且能夠把Father里面的this指向兒子的實例對象,此時Father中的this指向的是SonFather.call(this, uname, age);this.score = score; }var obj = new Son('erzi', 19, 66); console.log('obj', obj);原型鏈繼承(方法繼承)
/*原型鏈:Son.prototype -> Father.prototype -> Object.prorotype -> nullES6中的extends關鍵字實現繼承,底層仍然用的是原型 */// 方法繼承 -- 就是原型繼承 function Father() {Father.prototype.say = function () {console.log('say方法');} }// 繼承 function Son() { } Son.prototype = new Father(); Son.prototype.eat = function () {console.log('吃飯'); }// 如果繼承下來父類的方法,那么要把父類實例對象賦值給子類的原型對象,指回構造函數本身 Son.prototype.constructor = Son;console.log(Son.prototype); console.log(Father.prototype);var obj = new Son(); obj.say(); obj.eat();組合繼承
/*1. 原型繼承:繼承屬性和方法,屬性值會重復2. 借用構造函數繼承:繼承屬性,解決屬性值重復的問題,但是父類的方法不會被繼承3. 組合繼承:原型繼承 + 借用構造函數繼承 */function Person(name, age, sex) {this.name = name;this.age = age;this.sex = sex; }; Person.prototype.sayHi = function () {console.log('啊捏哈賽有'); }; function Student(name, age, sex, score) {// 借用構造函數Person.call(this, name, age, sex);this.score = score; }; // 改變原型指向 --- 實現繼承 Student.prototype = new Person(); // 不傳值 Student.prototype.eat = function () {console.log('吃東西'); };// 如果繼承下來父類的方法,那么要把父類實例對象賦值給子類的原型對象,指回構造函數本身 Student.prototype.constructor = Student;var stu = new Student('小黑', 20, '男', 100); console.log(stu.name, stu.age, stu.sex, stu.score); stu.sayHi(); stu.eat();var stu2 = new Student('小黑2', 20, '女', 1010); console.log(stu2.name, stu2.age, stu2.sex, stu2.score); stu.sayHi(); stu.eat();// 這樣就做到了屬性和方法都被繼承了設計模式:
沿用了java中的設計模式,一共有23種。
es6:
用class作為類名稱。主要是js向后臺語言靠近。
static 定義靜態屬性
constructor 構造函數
super 父類構造函數,super必須寫在子類的屬性前面
extends 繼承關鍵字
25. 高階函數
定義:指一個函數的參數是函數或者返回值是函數,滿足其中一種情況就算是高階函數。
funA可以接受funB為參數,那么funA就是一個高階函數。
// add() 就是一個高階函數 function add(x, y, fun) {return fun(x) + fun(y) }function fun(x) {return Math.abs(x) }console.log(add(-2, 3, fun))常見的高階函數:map, reduce, filter, sort
還有一個函數柯里化的問題:
定義:柯里化是把接收多個參數的函數轉換成多個只接收一個參數的函數。
作用:參數復用
function add(a, b) {return a + b; } add(1, 2) // 3 普通做法 一次傳入兩個參數// 假設有一個 curring 函數可以做到柯里化 function curring(){} curring(1)(2) // 我們通過這樣的方式來接受參數,這樣就實現了柯里化 function curring(x) {return y => x + y // 返回一個函數,然后函數的x+y作為最終的返回值 } curring(1)(2) // => 3參數復用:
// 我們平時的寫法 --- 非參數復用的寫法 function myInfo(inf, name, age) {return `${inf}:${name}${age}` } const myInfo1 = myInfo('個人信息', 'ljc', '19') console.log(myInfo1); // 個人信息:ljc19 // 函數柯里化的寫法 --- 參數復用的寫法 復用了inf function myInfoCurry(inf) {return (name, age) => {return `${inf}:${name}${age}`} } let myInfoName = myInfoCurry('個人信息') const myInfo1 = myInfoName('ljc', '19') const myInfo2 = myInfoName('ljcc','19') console.log(myInfo2); // 個人信息:ljcc119 console.log(myInfo1); // 個人信息:ljc19博客地址
26. 瀏覽器引擎Chrome(v8)
v8引擎對內存有限制:
nodejs中對v8引擎的內存限制
- 64位的操作系統是1.4G
- 32位操作系統是0.7G
拿官方的一個案例為例,官方是以1.5G內存來進行參考的,1.5G如果要進行垃圾回收,大概是時間是50ms。
如果node要進行一些大內存對象的操作,可以使用buffer來緩沖對象的內存。因為buffer不受限制,因為buffer基于的邏輯是c++的,c++的內存是不受v8引擎限制的。
v8 如何來劃分內存和垃圾回收的?
分代回收機制,新生代和老生代
| 32位 | 內存大小限制是16M | 內存大小限制是700M |
| 64位 | 內存大小限制是32M | 內存大小限制是1.4G |
| 適合 | 周期短的對象(如:操作某個DOM對象)。一般短期對象較多,占用80%以上 | 周期長的對象(如:new Vue() , document, window等,它就一直存在) |
| 垃圾回收 | 采用了Scavenge算法進行操作的。在算法實現時主要采用Cheney算法。Scavenge的缺點:可用內存只有一半,另一半永遠是等待的。Scavenge的優點:只保留活躍的對象,不活躍的就消滅了。就是部分清空。 | 先用Mark-Sweep(標記清除,就是現在不清楚,等下一次進行掃描的時候發現還在,就會被清除掉,內容清除掉后,會留下一個空間),后用Mark-Compact(標記整理,就是把標記清楚后的空間合并起來。) |
27. 瀏覽器是如何渲染頁面的
cssom: Css Object Model 采用css代碼,并將每個選擇器呈現為樹狀結構,是對css樣式表的對象化表示。同時還提供了api來操作css。
w3c標準中:
cssom 包括兩個部分
下面是熊鍵的筆記
- 作用:將域名地址解析為 ip 地址
- 過程:
- 讀取 4 個緩存
- 瀏覽器 DNS 緩存
- 計算機 DNS 緩存
- 路由器 DNS 緩存
- 網絡運營商 DNS 緩存
- 1 個遞歸查詢
- 13 個根域名服務器
- 讀取 4 個緩存
-
第一次握手:客戶端發起,我將要發送請求了,你準備一下
-
第二次握手:服務端發起,我知道了,準備好了,放馬過來
-
第三次握手:客戶端發起,我也知道了,等著
-
為什么要三次握手?
- 目的:確保客戶端和服務端收、發能力都是正常的
- 第一次握手:服務端知道客戶端發送能力是正常的
- 第二次握手:客戶端知道服務端發送和接受能力是正常的
- 第三次握手:服務端知道客戶端接受能力是正常的
-
客戶端發送請求給服務器
-
請求報文
- 請求首行
- 請求地址
- 請求方式
- 查詢字符串參數
- 請求頭
- 攜帶 cookie(cookie)
- 攜帶 token(authorization)
- 空行
- 請求主體
- 請求體參數(POST)
- 請求首行
-
服務端返回響應給客戶端
-
響應報文
- 響應首行
- 響應狀態碼
- 1xx
- 2xx
- 3xx
- 4xx
- 5xx
- 響應狀態碼
- 響應頭
- set-cookie 設置 cookie
- 緩存 cache-control
- 空行
- 響應主體
- 響應數據
- 響應首行
- 最開始返回 index.html 頁面,瀏覽器解析 html 文件
- 遇到 DOM 標記,調用 HTML 解析器,將元素解析 DOM 樹
- 遇到 css 標記,調用 css 解析器,解析成 CSSOM 樹
- style 不阻塞
- link 阻塞(防止閃屏)
- 遇到 js 標記(script 阻塞),調用 js 引擎,解析 js 代碼
- 可能會操作 DOM,重新調用 HTML 解析器,將元素解析 DOM 樹
- 可能會操作 CSS,重新調用 css 解析器,解析成 CSSOM 樹
- 這個過程就會導致頁面重排重繪
- 將 DOM 樹和 CSSOM 樹組合生成 render 樹
- 布局 layout
- 渲染 render
- 斷開 TCP 連接需要 4 次:客戶端發送請求斷開兩次,服務端返回響應斷開兩次
- 第一次揮手:客戶端發起,客戶端數據發送完畢了,準備斷開了
- 第二次揮手:服務端發起,服務端數據接收完畢了,可以斷開了
- 第三次揮手:服務端發起,服務端數據發送完畢了,準備斷開了
- 第四次揮手: 客戶端發起,客戶端數據接收完畢了,可以斷開了
28. js程序的執行順序是怎樣的?
外部js文件先加載還是window.onload先加載?
外部js文件與body的位置有關
-
如果js是放在body里,是按照body的先后順序進行加載的。
-
如果js在body外(一般指head中),是在body加載完畢后,才加載js。
外部js文件不論是在head中還是在body中,都要優先于window.onload = function(){}執行。如果外部js有定時器等異步代碼,就會滯后執行。
29. vue-loader的作用
vue-loader的用法:用來解析和轉換vue文件,提取出其中的script、style、template,把他們交給對應的loader去處理。
vue-loader的特性:
熱重載:"熱重載"不是當你修改文件的時候簡單重新加載頁面。啟用熱重載后,當你修改 .vue 文件時,所有該組件的實例會被替換,并且不需要刷新頁面。它甚至保持應用程序和被替換組件的當前狀態!當你調整模版或者修改樣式時,這極大的提高了開發體驗。
使用場景:
30. node可以通過哪些方法可以防止程序奔潰
node 速度比較快,node是單線程的,不穩定,不適合處理復雜業務。
單線程,產生未處理異常,會捯飭程序奔潰。
問題:
調用了req.params
let http = require('http') let server = http.creawteServer(function(req, res){let ok = req.params.ok; // params 是undefined。如果是未定義就會導致程序奔潰res.writeHead(200,{'content-type': 'text/plain'})res.end('hello world') }).listen(8080, '127.0.0.1')解決方案1:
uncaughtException 來全局捕獲Error,捕獲之后,可以防止node奔潰 process.on(‘uncaughtException’, function(err){打印錯誤 })解決方案2:加上try-catch
let http = require('http') let server = http.creawteServer(function(req, res){// let ok = req.params.ok; // 把這個未定義的代碼拿到外面去try {handler(req, res)} catch(e) {console.log(e)}res.writeHead(200,{'content-type': 'text/plain'})res.end('hello world') }).listen(8080, '127.0.0.1')let handler = function(req, res) {let ok = req.params.ok; // 同樣是未定義,會報錯 }31. http 和 https的區別
http:
http(Hyper Text Transfer Protocol) 超文本傳輸協議,用于在瀏覽器和服務器之間傳遞信息的,http協議以明文的形式傳輸內容的,數據是不加密的。不適合傳輸敏感信息。比如:身份證、賬號、密碼等。
https:
https:(Hyper Text Transfer Protocol over Secure Socket Layer) 即基于SSL的HTTP協議,簡單地說就是HTTP的安全版。https是在http的基礎上加上了SSL協議。SSL是依靠證書來驗證服務器的身份的,它對瀏覽器和服務器之間通信是加密的。
https協議是由SSL+ http構成的,是可加密的,身份認證的網絡安全,比http更安全。
區別:
32. XSS攻擊是什么?如何避免?
定義:
XSS攻擊又叫CSS(Cross Site Script)跨站腳本攻擊。惡意攻擊者往web頁面中插入html代碼,用戶請求該頁面,嵌入其中的該代碼將會被執行,從而達到攻擊用戶的目的。
一般有三種攻擊類型:
解決:
博客地址
33. csrf 攻擊(非胡哥)
CSRF概念:CSRF跨站點請求偽造(Cross—Site Request Forgery),跟XSS攻擊一樣,存在巨大的危害性,你可以這樣來理解:
攻擊者盜用了你的身份,以你的名義發送惡意請求,對服務器來說這個請求是完全合法的,但是卻完成了攻擊者所期望的一個操作,比如以你的名義發送郵件、發消息,盜取你的賬號,添加系統管理員,甚至于購買商品、虛擬貨幣轉賬等。如下:其中Web A為存在CSRF漏洞的網站,Web B為攻擊者構建的惡意網站,User C為Web A網站的合法用戶。
解決:
為了防止CSRF攻擊,Token要求不能重復,需要含有時間戳信息、簽名信息。
如:token = base64(msg)格式化…base64(sha256(“密鎖”, msg))
token產生:
- token解包
- 比對簽名
- 判斷時間是否過期
博客地址
34. css hack
條件Hack:用來調整頁面的兼容性的。css hack 這個兼容性主要是針對IE來說的,因為IE一開始沒有遵循W3C的標準。
// 條件Hack的寫法 // if條件共包含6種選擇方式:是否、大于、大于或等于、小于、小于或等于、非指定版本 <!--[if <keywords>? IE <version>?]> HTML代碼塊 <![endif]-->兼容性:瀏覽器品牌不同,在解釋css的時候,解釋方式不一樣,所以樣式不兼容的問題。
注意:盡可能減少對CSS Hack的使用。Hack有風險,使用需謹慎
博客地址
35. src和href的區別
請求資源類型不同
作用結果不同
瀏覽器解析方式不同
36. link和@import的區別?(非胡哥)
37. 胡哥快排
function quickSort(arr) {if (arr.length < 1) {return arr} // 基準值(得到一個整數) --- 使用Math.floor是為了處理除不盡的情況 let provotIndex = Math.floor(arr.length / 2) // 求得基準值對應的元素 --- 從基準下標開始截取,截取一個 var provot = arr.splice(provotIndex, 1)[0]// 遍歷數組和基準數進行對比 let left = [] let right = [] for (let i = 0; i < arr.length; i++) {if (arr[i] < provot) {left.push(arr[i])} else {right.push(arr[i])} } // console.log(left, right)return quickSort(left).concat([provot], quickSort(right)) } let arr = [2, 3, 4, 5, 3, 2, 1, 5] const result = quickSort(arr) console.log(result)38. 邊界塌陷(外邊距重合)
同時給兄弟/父子設置上下邊距,理論上是兩者之和,實際上只有一半,這種現象叫作邊界塌陷。
如:給box1的margin-bottom: 20px,給box2的margin-top: 20px; 理論上應該是40的邊距,實際上只有20px的邊距。
<head><style>.box1 {width: 100px;height: 100px;border: 1px solid red;margin-bottom: 20px;}.box2 {width: 100px;height: 100px;border: 1px solid green;margin-top: 20px;}</style> </head> <body><div class="box1"></div><div class="box2"></div> </body>注意:
浮動元素和定位元素是不會發生邊界塌陷的。
這種現象一般發生在塊級元素的垂直方向。
解決方案:
-
margin 同為正數或者同為負數的時候,取的是絕對值大的數。
-
如果一正一負的時候,求的是和,如給box1的margin-bottom: 20px,給box2的margin-top: -20px; 那么最終邊界值為0。
2022年8月24日10: 17: 30
未完待續。。。
總結
- 上一篇: “百度首页人物”首期人物:《士兵突击》许
- 下一篇: oracle lag使用情景,lag函数