日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

2021年7月 虾皮、货拉拉、有赞等面经总结

發(fā)布時(shí)間:2023/12/9 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 2021年7月 虾皮、货拉拉、有赞等面经总结 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

大家好,我是若川,加我微信 ruochuan12 進(jìn)源碼交流群。今天分享一篇7月份新鮮出爐的面經(jīng),文章較長(zhǎng),可以收藏再看。學(xué)習(xí)源碼系列、面試、年度總結(jié)、JS基礎(chǔ)系列。

本文來自作者@幾米陽光?投稿?原文鏈接:https://juejin.cn/post/6991724298197008421

最近朋友內(nèi)推面試了幾家公司(貨拉拉、蝦皮、有贊、樂信、Qtrade蘋果樹、富途、涂鴉、OPPO、微保、微眾、元戎啟行),也收獲了滿意的offer。整理了下面試遇到的問題,作為記錄。

JS相關(guān)

JS原型及原型鏈

function?Person()?{} Person.prototype.name?=?'Zaxlct'; Person.prototype.sayName?=?function()?{alert(this.name); } var?person1?=?new?Person(); //JS 在創(chuàng)建對(duì)象的時(shí)候,都有一個(gè)__proto__?的內(nèi)置屬性,用于指向創(chuàng)建它的構(gòu)造函數(shù)的原型對(duì)象。 //每個(gè)對(duì)象都有?__proto__?屬性,但只有函數(shù)對(duì)象才有?prototype?屬性 //?對(duì)象?person1?有一個(gè)?__proto__屬性,創(chuàng)建它的構(gòu)造函數(shù)是?Person,構(gòu)造函數(shù)的原型對(duì)象是?Person.prototype console.log(person1.__proto__?==?Person.prototype)?//true //所有函數(shù)對(duì)象的__proto__都指向Function.prototype String.__proto__?===?Function.prototype??//?true String.constructor?==?Function?//true prototype.jpg

JS繼承的幾種方式

詳解

  • 原型繼承

  • function?Parent?()?{this.name?=?'Parent'this.sex?=?'boy' } function?Child?()?{this.name?=?'child' } //?將子類的原型對(duì)象指向父類的實(shí)例 Child.prototype?=?new?Parent() //優(yōu):繼承了父類的模板,又繼承了父類的原型對(duì)象 //缺:1.無法實(shí)現(xiàn)多繼承(因?yàn)橐呀?jīng)指定了原型對(duì)象了) //???2.創(chuàng)建子類時(shí),無法向父類構(gòu)造函數(shù)傳參數(shù)
  • 構(gòu)造函數(shù)繼承

  • 在子類構(gòu)造函數(shù)內(nèi)部使用call或apply來調(diào)用父類構(gòu)造函數(shù),復(fù)制父類的實(shí)例屬性給子類。

    function?Parent?(name)?{this.name?=?name } function?Child?()?{//用.call?來改變?Parent?構(gòu)造函數(shù)內(nèi)的指向Parent.call(this,?'child') } //優(yōu):解決了原型鏈繼承中子類實(shí)例共享父類引用對(duì)象的問題,實(shí)現(xiàn)多繼承,創(chuàng)建子類實(shí)例時(shí),可以向父類傳遞參數(shù) //缺:構(gòu)造繼承只能繼承父類的實(shí)例屬性和方法,不能繼承父類原型的屬性和方法
  • 組合繼承

    組合繼承就是將原型鏈繼承與構(gòu)造函數(shù)繼承組合在一起。

    • 使用原型鏈繼承來保證子類能繼承到父類原型中的屬性和方法

    • 使用構(gòu)造繼承來保證子類能繼承到父類的實(shí)例屬性和方法

    • 寄生組合繼承

    • class繼承

    • 在class 中繼承主要是依靠?jī)蓚€(gè)東西:

      • extends

      • super

      class?Parent?{constructor?(name)?{this.name?=?name}getName?()?{console.log(this.name)} } class?Child?extends?Parent?{constructor?(name)?{super(name)this.sex?=?'boy'} }

      Event Loop 事件循環(huán)

      同步與異步、宏任務(wù)和微任務(wù)分別是函數(shù)兩個(gè)不同維度的描述。

      同步任務(wù)指的是,在主線程上排隊(duì)執(zhí)行的任務(wù),只有前一個(gè)任務(wù)執(zhí)行完畢,才能執(zhí)行后一個(gè)任務(wù);異步任務(wù)指的是,不進(jìn)入主線程、而進(jìn)入任務(wù)隊(duì)列(task queue)的任務(wù),只有等主線程任務(wù)執(zhí)行完畢,任務(wù)隊(duì)列開始通知主線程,請(qǐng)求執(zhí)行任務(wù),該任務(wù)才會(huì)進(jìn)入主線程執(zhí)行。

      當(dāng)某個(gè)宏任務(wù)執(zhí)行完后,會(huì)查看是否有微任務(wù)隊(duì)列。如果有,先執(zhí)行微任務(wù)隊(duì)列中的所有任務(wù);如果沒有,在執(zhí)行環(huán)境棧中會(huì)讀取宏任務(wù)隊(duì)列中排在最前的任務(wù);執(zhí)行宏任務(wù)的過程中,遇到微任務(wù),依次加入微任務(wù)隊(duì)列。棧空后,再次讀取微任務(wù)隊(duì)列里的任務(wù),依次類推。

      同步(Promise)>異步(微任務(wù)(process.nextTick ,Promises.then, Promise.catch ,resove,reject,MutationObserver)>宏任務(wù)(setTimeout,setInterval,setImmediate))

      await阻塞 后面的代碼執(zhí)行,因此跳出async函數(shù)執(zhí)行下一個(gè)微任務(wù)

      Promise 與 Async/Await ?區(qū)別

      async/await是基于Promise實(shí)現(xiàn)的,看起來更像同步代碼,

      • 不需要寫匿名函數(shù)處理Promise的resolve值

      • 錯(cuò)誤處理: Async/Await 讓 try/catch 可以同時(shí)處理同步和異步錯(cuò)誤。

      • 條件語句也跟錯(cuò)誤處理一樣簡(jiǎn)潔一點(diǎn)

      • 中間值處理(第一個(gè)方法返回值,用作第二個(gè)方法參數(shù)) 解決嵌套問題

      • 調(diào)試方便

      const?makeRequest?=?()?=>?{try?{getJSON().then(result?=>?{//?JSON.parse可能會(huì)出錯(cuò)const?data?=?JSON.parse(result)console.log(data)})//?取消注釋,處理異步代碼的錯(cuò)誤//?.catch((err)?=>?{//???console.log(err)//?})}?catch?(err)?{console.log(err)} }

      使用aync/await的話,catch能處理JSON.parse錯(cuò)誤:

      const?makeRequest?=?async?()?=>?{try?{//?this?parse?may?failconst?data?=?JSON.parse(await?getJSON())console.log(data)}?catch?(err)?{console.log(err)} }

      promise怎么實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用跟返回不同的狀態(tài)

      實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用:使用.then()或者.catch()方法之后會(huì)返回一個(gè)promise對(duì)象,可以繼續(xù)用.then()方法調(diào)用,再次調(diào)用所獲取的參數(shù)是上個(gè)then方法return的內(nèi)容

    • promise的三種狀態(tài)是 fulfilled(已成功)/pengding(進(jìn)行中)/rejected(已拒絕)

    • 狀態(tài)只能由 Pending --> Fulfilled 或者 Pending --> Rejected,且一但發(fā)生改變便不可二次修改;

    • Promise 中使用 resolve 和 reject 兩個(gè)函數(shù)來更改狀態(tài);

    • then 方法內(nèi)部做的事情就是狀態(tài)判斷:

      • 如果狀態(tài)是成功,調(diào)用成功回調(diào)函數(shù)

      • 如果狀態(tài)是失敗,調(diào)用失敗回調(diào)函數(shù)

      函數(shù)柯里化

      柯里化(Currying) 是把接收多個(gè)參數(shù)的原函數(shù)變換成接受一個(gè)單一參數(shù)(原來函數(shù)的第一個(gè)參數(shù)的函數(shù))并返回一個(gè)新的函數(shù),新的函數(shù)能夠接受余下的參數(shù),并返回和原函數(shù)相同的結(jié)果。

    • 參數(shù)對(duì)復(fù)用

    • 提高實(shí)用性

    • 延遲執(zhí)行 只傳遞給函數(shù)一部分參數(shù)來調(diào)用它,讓它返回一個(gè)函數(shù)去處理剩下的參數(shù)。柯里化的函數(shù)可以延遲接收參數(shù),就是比如一個(gè)函數(shù)需要接收的參數(shù)是兩個(gè),執(zhí)行的時(shí)候必須接收兩個(gè)參數(shù),否則沒法執(zhí)行。但是柯里化后的函數(shù),可以先接收一個(gè)參數(shù)

    • //?普通的add函數(shù) function?add(x,?y)?{return?x?+?y }//?Currying后 function?curryingAdd(x)?{return?function?(y)?{return?x?+?y} }add(1,?2)???????????//?3 curryingAdd(1)(2)???//?3

      JS對(duì)象深克隆

      遞歸遍歷對(duì)象,解決循環(huán)引用問題

      解決循環(huán)引用問題,我們需要一個(gè)存儲(chǔ)容器存放當(dāng)前對(duì)象和拷貝對(duì)象的對(duì)應(yīng)關(guān)系(適合用key-value的數(shù)據(jù)結(jié)構(gòu)進(jìn)行存儲(chǔ),也就是map),當(dāng)進(jìn)行拷貝當(dāng)前對(duì)象的時(shí)候,我們先查找存儲(chǔ)容器是否已經(jīng)拷貝過當(dāng)前對(duì)象,如果已經(jīng)拷貝過,那么直接把返回,沒有的話則是繼續(xù)拷貝。

      function?deepClone(target)?{const?map?=?new?Map()function?clone?(target)?{if?(isObject(target))?{let?cloneTarget?=?isArray(target)???[]?:?{};if?(map.get(target))?{return?map.get(target)}map.set(target,cloneTarget)for?(const?key?in?target)?{cloneTarget[key]?=?clone(target[key]);}return?cloneTarget;}?else?{return?target;}}return?clone(target) };

      JS模塊化

      nodeJS里面的模塊是基于commonJS規(guī)范實(shí)現(xiàn)的,原理是文件的讀寫,導(dǎo)出文件要使用exports、module.exports,引入文件用require。每個(gè)文件就是一個(gè)模塊;每個(gè)文件里面的代碼會(huì)用默認(rèn)寫在一個(gè)閉包函數(shù)里面AMD規(guī)范則是非同步加載模塊,允許指定回調(diào)函數(shù),AMD 是 RequireJS 在推廣過程中對(duì)模塊定義的規(guī)范化產(chǎn)出。

      AMD推崇依賴前置, CMD推崇依賴就近。對(duì)于依賴的模塊AMD是提前執(zhí)行,CMD是延遲執(zhí)行。

      在ES6中,我們可以使用 import 關(guān)鍵字引入模塊,通過 exprot 關(guān)鍵字導(dǎo)出模塊,但是由于ES6目前無法在瀏覽器中執(zhí)行,所以,我們只能通過babel將不被支持的import編譯為當(dāng)前受到廣泛支持的 require。

      CommonJs 和 ES6 模塊化的區(qū)別:

    • CommonJS 模塊輸出的是一個(gè)值的拷貝,ES6 模塊輸出的是值的引用。

    • CommonJS 模塊是運(yùn)行時(shí)加載,ES6 模塊是編譯時(shí)輸出接口。

    • 前端模塊化:CommonJS,AMD,CMD,ES6

      import 和 require 導(dǎo)入的區(qū)別

      import 的ES6 標(biāo)準(zhǔn)模塊;require 是 AMD規(guī)范引入方式;

      import是編譯時(shí)調(diào)用,所以必須放在文件開頭;是解構(gòu)過程 require是運(yùn)行時(shí)調(diào)用,所以require理論上可以運(yùn)用在代碼的任何地方;是賦值過程。其實(shí)require的結(jié)果就是對(duì)象、數(shù)字、字符串、函數(shù)等,再把require的結(jié)果賦值給某個(gè)變量

      異步加載JS方式

    • 匿名函數(shù)自調(diào)動(dòng)態(tài)創(chuàng)建script標(biāo)簽加載js

    • (function(){var?scriptEle?=?document.createElement("script");scriptEle.type?=?"text/javasctipt";scriptEle.async?=?true;scriptEle.src?=?"http://cdn.bootcss.com/jquery/3.0.0-beta1/jquery.min.js";var?x?=?document.getElementsByTagName("head")[0];x.insertBefore(scriptEle,?x.firstChild);??})();
    • async屬性

    • //?async屬性規(guī)定一旦加載腳本可用,則會(huì)異步執(zhí)行 <script?type="text/javascript"?src="xxx.js"?async="async"></script>
    • defer屬性

    • //?defer屬性規(guī)定是否對(duì)腳本執(zhí)行進(jìn)行延遲,直到頁面加載為止 <script?type="text/javascript"?src="xxx.js"?defer="defer"></script>

      Set、Map、WeakSet、WeakMap

      Set對(duì)象可以存儲(chǔ)任何類型的數(shù)據(jù)。值是唯一的,沒有重復(fù)的值。

      Map對(duì)象保存鍵值對(duì),任意值都可以成為它的鍵或值。

      WeakSet 結(jié)構(gòu)與 Set 類似,也是不重復(fù)的值的集合 . WeakMap 對(duì)象是一組鍵值對(duì)的集合

      不同:WeakSet 的成員只能是對(duì)象,而不能是其他類型的值。WeakSet 不可遍歷

      WeakMap只接受對(duì)象作為鍵名(null除外),不接受其他類型的值作為鍵名。

      WeakMap的鍵名所指向的對(duì)象,不計(jì)入垃圾回收機(jī)制。

      call、apply

      call( this,a,b,c ) 在第一個(gè)參數(shù)之后的,后續(xù)所有參數(shù)就是傳入該函數(shù)的值。apply( this,[a,b,c] ) 只有兩個(gè)參數(shù),第一個(gè)是對(duì)象,第二個(gè)是數(shù)組,這個(gè)數(shù)組就是該函數(shù)的參數(shù)。

      共同之處:都可以用來代替另一個(gè)對(duì)象調(diào)用一個(gè)方法,將一個(gè)函數(shù)的對(duì)象上下文從初始的上下文改變?yōu)橛蓆hisObj指定的新對(duì)象。

      所謂防抖,就是指觸發(fā)事件后在 n 秒內(nèi)函數(shù)只能執(zhí)行一次所謂節(jié)流,就是指連續(xù)觸發(fā)事件但是在 n 秒中只執(zhí)行一次函數(shù)。

      addEventListener的第三個(gè)參數(shù)干嘛的,為true時(shí)捕獲,false時(shí)冒泡

      Object.prototype.toString.call() 判斷對(duì)象類型

      //?new?Set是實(shí)現(xiàn)數(shù)組去重, //?Array.from()把去重之后轉(zhuǎn)換成數(shù)組 let?arr2?=?Array.from(new?Set(arr));

      詞法作用域與作用域鏈

      作用域規(guī)定了如何查找變量,也就是確定當(dāng)前執(zhí)行代碼對(duì)變量的訪問權(quán)限。

      ES5只有全局作用域沒和函數(shù)作用域,ES6增加塊級(jí)作用域

      暫時(shí)性死區(qū):在代碼塊內(nèi),使用 letconst 命令聲明變量之前,該變量都是不可用的,語法上被稱為暫時(shí)性死區(qū)。

      JavaScript 采用詞法作用域(lexical scoping),也就是靜態(tài)作用域。

      函數(shù)的作用域在函數(shù)定義的時(shí)候就決定了。

      當(dāng)查找變量的時(shí)候,會(huì)先從當(dāng)前上下文的變量對(duì)象中查找,如果沒有找到,就會(huì)從父級(jí)(詞法層面上的父級(jí)執(zhí)行上下文的變量對(duì)象中查找,一直找到全局上下文的變量對(duì)象,也就是全局對(duì)象。這樣由多個(gè)執(zhí)行上下文的變量對(duì)象構(gòu)成的鏈表就叫做作用域鏈

      new關(guān)鍵字做了4件事:

      function?_new(constructor,?...arg)?{ //?創(chuàng)建一個(gè)空對(duì)象var?obj?=?{};//?空對(duì)象的`__proto__`指向構(gòu)造函數(shù)的`prototype`,?為這個(gè)新對(duì)象添加屬性?obj.__proto__?=?constructor.prototype;?//?構(gòu)造函數(shù)的作用域賦給新對(duì)象var?res?=?constructor.apply(obj,?arg);?//?返回新對(duì)象.如果沒有顯式return語句,則返回thisreturn?Object.prototype.toString.call(res)?===?'[object?Object]'???res?:?obj;? }

      不應(yīng)該使用箭頭函數(shù)一些情況:

      • 當(dāng)想要函數(shù)被提升時(shí)(箭頭函數(shù)是匿名的)

      • 要在函數(shù)中使用this/arguments時(shí),由于箭頭函數(shù)本身不具有this/arguments,因此它們?nèi)Q于外部上下文

      • 使用命名函數(shù)(箭頭函數(shù)是匿名的)

      • 使用函數(shù)作為構(gòu)造函數(shù)時(shí)(箭頭函數(shù)沒有構(gòu)造函數(shù))

      • 當(dāng)想在對(duì)象字面是以將函數(shù)作為屬性添加并在其中使用對(duì)象時(shí),因?yàn)樵蹅儫o法訪問 this 即對(duì)象本身。

      判斷數(shù)組的四種方法

    • Array.isArray() 判斷

    • instanceof 判斷: 檢驗(yàn)構(gòu)造函數(shù)的prototype屬性是否出現(xiàn)在對(duì)象的原型鏈中,返回一個(gè)布爾值。let a = []; a instanceof Array; //true

    • constructor判斷: 實(shí)例的構(gòu)造函數(shù)屬性constructor指向構(gòu)造函數(shù)let a = [1,3,4]; a.constructor === Array;//true

    • Object.prototype.toString.call() 判斷l(xiāng)et a = [1,2,3]; Object.prototype.toString.call(a) === '[object Array]';//true

    • TS有什么優(yōu)勢(shì)

    • 靜態(tài)輸入:靜態(tài)類型化是一種功能,可以在開發(fā)人員編寫腳本時(shí)檢測(cè)錯(cuò)誤。

    • 大型的開發(fā)項(xiàng)目:使用TypeScript工具來進(jìn)行重構(gòu)更變的容易、快捷。

    • 更好的協(xié)作:類型安全是在編碼期間檢測(cè)錯(cuò)誤,而不是在編譯項(xiàng)目時(shí)檢測(cè)錯(cuò)誤。

    • 更強(qiáng)的生產(chǎn)力:干凈的 ECMAScript 6 代碼,自動(dòng)完成和動(dòng)態(tài)輸入等因素有助于提高開發(fā)人員的工作效率。

    • interface 和 type的區(qū)別

      • interface 只能定義對(duì)象類型。type聲明可以聲明任何類型。

      • interface 能夠聲明合并,兩個(gè)相同接口會(huì)合并。Type聲明合并會(huì)報(bào)錯(cuò)

      • type可以類型推導(dǎo)

      框架 Vue | React

      Vue3.0 新特性

      雙向數(shù)據(jù)綁定 Proxy

      代理,可以理解為在對(duì)象之前設(shè)置一個(gè)“攔截”,當(dāng)該對(duì)象被訪問的時(shí)候,都必須經(jīng)過這層攔截。意味著你可以在這層攔截中進(jìn)行各種操作。比如你可以在這層攔截中對(duì)原對(duì)象進(jìn)行處理,返回你想返回的數(shù)據(jù)結(jié)構(gòu)。

      ES6 原生提供 Proxy 構(gòu)造函數(shù),MDN上的解釋為:Proxy 對(duì)象用于定義基本操作的自定義行為(如屬性查找,賦值,枚舉,函數(shù)調(diào)用等)。

      const?p?=?new?Proxy(target,?handler); //target:?所要攔截的目標(biāo)對(duì)象(可以是任何類型的對(duì)象,包括原生數(shù)組,函數(shù),甚至另一個(gè)代理) //handler:一個(gè)對(duì)象,定義要攔截的行為const?p?=?new?Proxy({},?{get(target,?propKey)?{return?'哈哈,你被我攔截了';} });console.log(p.name);

      新增的屬性,并不需要重新添加響應(yīng)式處理,因?yàn)?Proxy 是對(duì)對(duì)象的操作,只要你訪問對(duì)象,就會(huì)走到 Proxy 的邏輯中。

      Vue3 Composition API

      Vue3.x 推出了Composition API。setup 是組件內(nèi)使用 Composition API的入口。setup 執(zhí)行時(shí)機(jī)是在 beforeCreate 之前執(zhí)行.

      reactive、ref 與 toRefs、isRef

      Vue3.x 可以使用reactive和ref來進(jìn)行數(shù)據(jù)定義。

      //?props?傳入組件對(duì)屬性 //?context?一個(gè)上下文對(duì)象,包含了一些有用的屬性:attrs,parent,refs setup(props,?context)?{//?ref?定義數(shù)據(jù)const?year?=?ref(0);//?reactive?處理對(duì)象的雙向綁定const?user?=?reactive({?nickname:?"xiaofan",?age:?26,?gender:?"女"?});setInterval(()?=>?{year.value++;user.age++;},?1000);return?{year,//?使用toRefs,結(jié)構(gòu)解構(gòu)...toRefs(user),}; }, //?提供isRef,用于檢查一個(gè)對(duì)象是否是ref對(duì)象

      watchEffect 監(jiān)聽函數(shù)

      • watchEffect 不需要手動(dòng)傳入依賴

      • watchEffect 會(huì)先執(zhí)行一次用來自動(dòng)收集依賴

      • watchEffect 無法獲取到變化前的值, 只能獲取變化后的值

      computed可傳入get和set

      用于定義可更改的計(jì)算屬性

      const?plusOne?=?computed({get:?()?=>?count.value?+?1,set:?val?=>?{?count.value?=?val?-?1?} });

      使用TypeScript和JSX

      setup現(xiàn)在支持返回一個(gè)渲染函數(shù),這個(gè)函數(shù)返回一個(gè)JSX,JSX可以直接使用聲明在setup作用域的響應(yīng)式狀態(tài):

      export?default?{setup()?{const?count?=?ref(0);return?()?=>?(<div>{count.value}</div>);}, };

      Vue 跟React 對(duì)比?

      相同點(diǎn):

    • 都有虛擬DOM(Virtual DOM 是一個(gè)映射真實(shí)DOM的JavaScript對(duì)象)

    • 都提供了響應(yīng)式和組件化的視圖組件。

    • 不同點(diǎn):Vue 是MVVM框架,雙向數(shù)據(jù)綁定,當(dāng)ViewModel對(duì)Model進(jìn)行更新時(shí),通過數(shù)據(jù)綁定更新到View。

      React是一個(gè)單向數(shù)據(jù)流的庫,狀態(tài)驅(qū)動(dòng)視圖。State --> View --> New State --> New View ui = render (data)

      模板渲染方式不同。React是通過JSX來渲染模板,而Vue是通過擴(kuò)展的HTML來進(jìn)行模板的渲染。

      組件形式不同,Vue文件里將HTML,JS,CSS組合在一起。react提供class組件和function組

      Vue封裝好了一些v-if,v-for,React什么都是自己實(shí)現(xiàn),自由度更高

      Vue 初始化過程,雙向數(shù)據(jù)綁定原理

      vue.js 則是采用數(shù)據(jù)劫持結(jié)合發(fā)布者-訂閱者模式的方式,通過Object.defineProperty()來劫持各個(gè)屬性的setter,getter,dep.addSub來收集訂閱的依賴,watcher監(jiān)聽數(shù)據(jù)的變化,在數(shù)據(jù)變動(dòng)時(shí)發(fā)布消息給訂閱者,觸發(fā)相應(yīng)的監(jiān)聽回調(diào)。

      監(jiān)聽器Observer,用來劫持并監(jiān)聽所有屬性,如果有變動(dòng)的,就通知訂閱者。訂閱者Watcher,可以收到屬性的變化通知并執(zhí)行相應(yīng)的函數(shù),從而調(diào)用對(duì)應(yīng)update更新視圖。

      v-model 指令,它能輕松實(shí)現(xiàn)表單輸入和應(yīng)用狀態(tài)之間的雙向綁定。

      computed: 支持緩存,只有依賴數(shù)據(jù)結(jié)果發(fā)生改變,才會(huì)重新進(jìn)行計(jì)算,不支持異步操作,如果一個(gè)屬性依賴其他屬性,多對(duì)一,一般用computed

      watch: 數(shù)據(jù)變,直接觸發(fā)相應(yīng)操作,支持異步,監(jiān)聽數(shù)據(jù)必須data中聲明過或者父組件傳遞過來的props中的數(shù)據(jù),當(dāng)數(shù)據(jù)變化時(shí),觸發(fā)其他操作,函數(shù)有兩個(gè)參數(shù)

      vue-router實(shí)現(xiàn)原理

      端路由簡(jiǎn)介以及vue-router實(shí)現(xiàn)原理原理核心就是 更新視圖但不重新請(qǐng)求頁面。路徑之間的切換,也就是組件的切換。vue-router實(shí)現(xiàn)單頁面路由跳轉(zhuǎn)模式:hash模式、history模式。根據(jù)設(shè)置mode參數(shù)

      hash模式:通過錨點(diǎn)值的改變,根據(jù)不同的值,渲染指定DOM位置的不同數(shù)據(jù)。每一次改變#后的部分,都會(huì)在瀏覽器的訪問歷史中增加一個(gè)記錄,使用”后退”按鈕,就可以回到上一個(gè)位置。history模式:利用 window.history.pushState API 來完成 URL 跳轉(zhuǎn)而無須重新加載頁面。

      vuex實(shí)現(xiàn)原理:

      Vue.use(vuex)會(huì)調(diào)用vuex的install方法

      在beforeCreate鉤子前混入vuexInit方法,vuexInit方法實(shí)現(xiàn)了store注入vue組件實(shí)例,并注冊(cè)了vuex store的引用屬性$store。

      Vuex的state狀態(tài)是響應(yīng)式,是借助vue的data是響應(yīng)式,將state存入vue實(shí)例組件的data中;

      Vuex的getters則是借助vue的計(jì)算屬性computed實(shí)現(xiàn)數(shù)據(jù)實(shí)時(shí)監(jiān)聽。

      nextTick 的原理以及運(yùn)行機(jī)制?

      nextTick的源碼分析

      vue進(jìn)行DOM更新內(nèi)部也是調(diào)用nextTick來做異步隊(duì)列控制。只要觀察到數(shù)據(jù)變化,Vue 將開啟一個(gè)隊(duì)列,并緩沖在同一事件循環(huán)中發(fā)生的所有數(shù)據(jù)改變。如果同一個(gè) watcher 被多次觸發(fā),只會(huì)被推入到隊(duì)列中一次。

      DOM至少會(huì)在當(dāng)前事件循環(huán)里面的所有數(shù)據(jù)變化完成之后,再統(tǒng)一更新視圖。而當(dāng)我們自己調(diào)用nextTick的時(shí)候,它就在更新DOM的microtask(微任務(wù)隊(duì)列)后追加了我們自己的回調(diào)函數(shù)

      從而確保我們的代碼在DOM更新后執(zhí)行,同時(shí)也避免了setTimeout可能存在的多次執(zhí)行問題。確保隊(duì)列中的微任務(wù)在一次事件循環(huán)前被執(zhí)行完畢。

      Vue 實(shí)現(xiàn)一個(gè)高階組件

      高階組件就是一個(gè)函數(shù),且該函數(shù)接受一個(gè)組件作為參數(shù),并返回一個(gè)新的組件。在不改變對(duì)象自身的前提下在程序運(yùn)行期間動(dòng)態(tài)的給對(duì)象添加一些額外的屬性或行為

      //?高階組件(HOC)接收到的?props?應(yīng)該透?jìng)鹘o被包裝組件即直接將原組件prop傳給包裝組件 //?高階組件完全可以添加、刪除、修改?props export?default?function?Console(BaseComponent)?{return?{props:?BaseComponent.props,mounted()?{console.log("高階組件");},render(h)?{console.log(this);//?將?this.$slots?格式化為數(shù)組,因?yàn)?h?函數(shù)第三個(gè)參數(shù)是子節(jié)點(diǎn),是一個(gè)數(shù)組const?slots?=?Object.keys(this.$slots).reduce((arr,?key)?=>?arr.concat(this.$slots[key]),?[]).map((vnode)?=>?{vnode.context?=?this._self;?//?綁定到高階組件上,vm:解決具名插槽被作為默認(rèn)插槽進(jìn)行渲染return?vnode;});//?透?jìng)鱬rops、透?jìng)魇录⑼競(jìng)鱯lotsreturn?h(BaseComponent,{on:?this.$listeners,attrs:?this.$attrs,?//?attrs?指的是那些沒有被聲明為?props?的屬性props:?this.$props,},slots);},}; }

      Vue.component()、Vue.use()、this.$xxx()

      Vue.component()方法注冊(cè)全局組件。

      • 第一個(gè)參數(shù)是自定義元素名稱,也就是將來在別的組件中使用這個(gè)組件的標(biāo)簽名稱。

      • 第二個(gè)參數(shù)是將要注冊(cè)的Vue組件。

      import?Vue?from?'vue'; //?引入loading組件? import?Loading?from?'./loading.vue'; //?將loading注冊(cè)為全局組件,在別的組件中通過<loading>標(biāo)簽使用Loading組件 Vue.component('loading',?Loading);

      Vue.use注冊(cè)插件,這接收一個(gè)參數(shù)。這個(gè)參數(shù)必須具有install方法。Vue.use函數(shù)內(nèi)部會(huì)調(diào)用參數(shù)的install方法。

      • 如果插件沒有被注冊(cè)過,那么注冊(cè)成功之后會(huì)給插件添加一個(gè)installed的屬性值為true。Vue.use方法內(nèi)部會(huì)檢測(cè)插件的installed屬性,從而避免重復(fù)注冊(cè)插件。

      • 插件的install方法將接收兩個(gè)參數(shù),第一個(gè)是參數(shù)是Vue,第二個(gè)參數(shù)是配置項(xiàng)options。

      • 在install方法內(nèi)部可以添加全局方法或者屬性

      import?Vue?from?'vue';//?這個(gè)插件必須具有install方法 const?plugin?=?{install?(Vue,?options)?{//?添加全局方法或者屬性Vue.myGlobMethod?=?function?()?{};//?添加全局指令Vue.directive();//?添加混入Vue.mixin();//?添加實(shí)例方法Vue.prototype.$xxx?=?function?()?{};//?注冊(cè)全局組件Vue.component()} }//?Vue.use內(nèi)部會(huì)調(diào)用plugin的install方法 Vue.use(plugin);

      將Hello方法掛載到Vue的prototype上.

      import?Vue?from?'vue'; import?Hello?from?'./hello.js'; Vue.prototype.$hello?=?Hello;

      vue組件中就可以this.$hello('hello world')

      Vue父組件傳遞props數(shù)據(jù),子組件修改參數(shù)

      • 父子組件傳值時(shí),父組件傳遞的參數(shù),數(shù)組和對(duì)象,子組件接受之后可以直接進(jìn)行修改,并且父組件相應(yīng)的值也會(huì)修改。控制臺(tái)中發(fā)出警告。

      • 如果傳遞的值是字符串,直接修改會(huì)報(bào)錯(cuò)。單向數(shù)據(jù)流,每次父級(jí)組件發(fā)生更新時(shí),子組件中所有的 prop 都將會(huì)刷新為最新的值。

      如果子組件想修改prop中數(shù)據(jù):

    • 定義一個(gè)局部變量,使用prop的值賦值

    • 定義一個(gè)計(jì)算屬性,處理prop的值并返回

    • Vue父子組件生命周期執(zhí)行順序

      加載渲染過程

      父beforeCreate -> 父created -> 父beforeMount-> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted

      子組件更新過程

      父beforeUpdate -> 子beforeUpdate -> 子updated -> 父updated

      父組件更新過程

      父beforeUpdate -> 父updated

      銷毀過程

      父beforeDestroy -> 子beforeDestroy -> 子destroyed -> 父destroyed

      Vue 自定義指令

      自定義指令提供了幾個(gè)鉤子函數(shù):bind:指令第一次綁定到元素時(shí)調(diào)用inserted:被綁定元素插入父節(jié)點(diǎn)時(shí)調(diào)用update:所在組件的 VNode 更新時(shí)調(diào)用

      使用slot后可以在子組件內(nèi)顯示插入的新標(biāo)簽

      webpack 及工程化

      webpack的生命周期,及鉤子

      compiler(整個(gè)生命周期 [k?m?pa?l?r]) 鉤子 https://webpack.docschina.org/api/compiler-hooks/compilation(編譯 [?kɑ?mp??le??n]) 鉤子

      compiler對(duì)象包含了Webpack 環(huán)境所有的的配置信息。這個(gè)對(duì)象在啟動(dòng) webpack 時(shí)被一次性建立,并配置好所有可操作的設(shè)置,包括 options,loader 和 plugin。當(dāng)在 webpack 環(huán)境中應(yīng)用一個(gè)插件時(shí),插件將收到此 compiler 對(duì)象的引用。可以使用它來訪問 webpack 的主環(huán)境。

      compilation對(duì)象包含了當(dāng)前的模塊資源、編譯生成資源、變化的文件等。當(dāng)運(yùn)行webpack 開發(fā)環(huán)境中間件時(shí),每當(dāng)檢測(cè)到一個(gè)文件變化,就會(huì)創(chuàng)建一個(gè)新的 compilation,從而生成一組新的編譯資源。compilation 對(duì)象也提供了很多關(guān)鍵時(shí)機(jī)的回調(diào),以供插件做自定義處理時(shí)選擇使用。

      compiler代表了整個(gè)webpack從啟動(dòng)到關(guān)閉的生命周期,而compilation 只是代表了一次新的編譯過程

      webpack 編譯過程

      Webpack 的編譯流程是一個(gè)串行的過程,從啟動(dòng)到結(jié)束會(huì)依次執(zhí)行以下流程:

    • 初始化參數(shù):從配置文件和 Shell 語句中讀取與合并參數(shù),得出最終的參數(shù);

    • 開始編譯:用上一步得到的參數(shù)初始化 Compiler 對(duì)象,加載所有配置的插件,執(zhí)行對(duì)象的 run方法開始執(zhí)行編譯;

    • 確定入口:根據(jù)配置中的 entry 找出所有的入口文件;

    • 編譯模塊:從入口文件出發(fā),調(diào)用所有配置的 Loader 對(duì)模塊進(jìn)行翻譯,再找出該模塊依賴的模塊,再遞歸本步驟直到所有入口依賴的文件都經(jīng)過了本步驟的處理;

    • 完成模塊編譯:在經(jīng)過第4步使用 Loader 翻譯完所有模塊后,得到了每個(gè)模塊被翻譯后的最終內(nèi)容以及它們之間的依賴關(guān)系;

    • 輸出資源:根據(jù)入口和模塊之間的依賴關(guān)系,組裝成一個(gè)個(gè)包含多個(gè)模塊的Chunk,再把每個(gè) Chunk 轉(zhuǎn)換成一個(gè)單獨(dú)的文件加入到輸出列表,這步是可以修改輸出內(nèi)容的最后機(jī)會(huì);

    • 輸出完成:在確定好輸出內(nèi)容后,根據(jù)配置確定輸出的路徑和文件名,把文件內(nèi)容寫入到文件系統(tǒng)。

    • 優(yōu)化項(xiàng)目的webpack打包編譯過程

      1.構(gòu)建打點(diǎn):構(gòu)建過程中,每一個(gè)Loader 和 Plugin 的執(zhí)行時(shí)長(zhǎng),在編譯 JS、CSS 的 Loader 以及對(duì)這兩類代碼執(zhí)行壓縮操作的 Plugin上消耗時(shí)長(zhǎng) 。一款工具:speed-measure-webpack-plugin

      2.緩存:大部分 Loader 都提供了cache 配置項(xiàng)。cache-loader ,將 loader 的編譯結(jié)果寫入硬盤緩存

      3.多核編譯,happypack項(xiàng)目接入多核編譯,理解為happypack 將編譯工作灌滿所有線程

      4.抽離,webpack-dll-plugin 將這些靜態(tài)依賴從每一次的構(gòu)建邏輯中抽離出去,靜態(tài)依賴單獨(dú)打包,Externals將不需要打包的靜態(tài)資源從構(gòu)建邏輯中剔除出去,使用CDN 引用

      5.tree-shaking,雖然依賴了某個(gè)模塊,但其實(shí)只使用其中的某些功能。通過 tree-shaking,將沒有使用的模塊剔除,來達(dá)到刪除無用代碼的目的。

      首屏加載優(yōu)化

      路由懶加載:改為用import引用,以函數(shù)的形式動(dòng)態(tài)引入,可以把各自的路由文件分別打包,只有在解析給定的路由時(shí),才會(huì)下載路由組件;

      element-ui按需加載:引用實(shí)際上用到的組件 ;

      組件重復(fù)打包:CommonsChunkPlugin配置來拆包,把使用2次及以上的包抽離出來,放進(jìn)公共依賴文件,首頁也有復(fù)用的組件,也會(huì)下載這個(gè)公共依賴文件;

      gzip: 拆完包之后,再用gzip做一下壓縮,關(guān)閉sourcemap。

      UglifyJsPlugin: ?生產(chǎn)環(huán)境,壓縮混淆代碼,移除console代碼

      CDN部署靜態(tài)資源:靜態(tài)請(qǐng)求打在nginx時(shí),將獲取靜態(tài)資源的地址進(jìn)行重定向CDN內(nèi)容分發(fā)網(wǎng)絡(luò)

      移動(dòng)端首屏加載可以使用骨架屏,自定義loading,首頁單獨(dú)做服務(wù)端渲染

      如何進(jìn)行前端性能優(yōu)化(21種優(yōu)化+7種定位方式)

      webpack 熱更新機(jī)制

      熱更新流程總結(jié):

      • 啟動(dòng)本地server,讓瀏覽器可以請(qǐng)求本地的靜態(tài)資源

      • 頁面首次打開后,服務(wù)端與客戶端通過 websocket建立通信渠道,把下一次的 hash 返回前端

      • 客戶端獲取到hash,這個(gè)hash將作為下一次請(qǐng)求服務(wù)端 hot-update.js 和 hot-update.json的hash

      • 修改頁面代碼后,Webpack 監(jiān)聽到文件修改后,開始編譯,編譯完成后,發(fā)送 build 消息給客戶端

      • 客戶端獲取到hash,成功后客戶端構(gòu)造hot-update.js script鏈接,然后插入主文檔

      • hot-update.js 插入成功后,執(zhí)行hotAPI 的 createRecord 和 reload方法,獲取到 Vue 組件的 render方法,重新 render 組件, 繼而實(shí)現(xiàn) UI 無刷新更新。

      webpack的 loader和plugin介紹,css-loader,style-loader的區(qū)別

      loader 它就是一個(gè)轉(zhuǎn)換器,將A文件進(jìn)行編譯形成B文件,

      plugin ,它就是一個(gè)擴(kuò)展器,來操作的是文件,針對(duì)是loader結(jié)束后,webpack打包的整個(gè)過程,它并不直接操作文件,會(huì)監(jiān)聽webpack打包過程中的某些節(jié)點(diǎn)(run, build-module, program)

      Babel 能把ES6/ES7的代碼轉(zhuǎn)化成指定瀏覽器能支持的代碼。

      css-loader 的作用是把 css文件進(jìn)行轉(zhuǎn)碼style-loader: 使用<style>將css-loader內(nèi)部樣式注入到我們的HTML頁面

      先使用 css-loader轉(zhuǎn)碼,然后再使用 style-loader插入到文件

      如何編寫一個(gè)webpack的plugin?

      https://segmentfault.com/a/1190000037513682

      webpack 插件的組成:

      • 一個(gè) JS 命名函數(shù)或一個(gè)類(可以想下我們平時(shí)使用插件就是 new XXXPlugin()的方式)

      • 在插件類/函數(shù)的 (prototype) 上定義一個(gè) apply 方法。

      • 通過 apply 函數(shù)中傳入 compiler 并插入指定的事件鉤子,在鉤子回調(diào)中取到 compilation 對(duì)象

      • 通過 compilation 處理 webpack 內(nèi)部特定的實(shí)例數(shù)據(jù)

      • 如果是插件是異步的,在插件的邏輯編寫完后調(diào)用 webpack 提供的 callback

      為什么 Vite 啟動(dòng)這么快

      Webpack 會(huì)先打包,然后啟動(dòng)開發(fā)服務(wù)器,請(qǐng)求服務(wù)器時(shí)直接給予打包結(jié)果。

      而 Vite 是直接啟動(dòng)開發(fā)服務(wù)器,請(qǐng)求哪個(gè)模塊再對(duì)該模塊進(jìn)行實(shí)時(shí)編譯。

      Vite 將開發(fā)環(huán)境下的模塊文件,就作為瀏覽器要執(zhí)行的文件,而不是像 Webpack 那樣進(jìn)行打包合并。

      由于 Vite 在啟動(dòng)的時(shí)候不需要打包,也就意味著不需要分析模塊的依賴、不需要編譯。因此啟動(dòng)速度非常快。當(dāng)瀏覽器請(qǐng)求某個(gè)模塊時(shí),再根據(jù)需要對(duì)模塊內(nèi)容進(jìn)行編譯。

      你的腳手架是怎么做的

      使用 download-git-repo 下載倉庫代碼democommander:完整的 node.js 命令行解決方案。聲明program,使用.option() 方法來定義選項(xiàng)Inquirer.js:命令行用戶界面的集合。

      前端監(jiān)控

      前端監(jiān)控通常包括行為監(jiān)控(PV/UV,埋點(diǎn)接口統(tǒng)計(jì))、異常監(jiān)控性能監(jiān)控

      一個(gè)監(jiān)控系統(tǒng),大致可以分為四個(gè)階段:日志采集日志存儲(chǔ)統(tǒng)計(jì)與分析報(bào)告和警告

      錯(cuò)誤監(jiān)控

      Vue專門的錯(cuò)誤警告的方法 Vue.config.errorHandler,(Vue提供只能捕獲其頁面生命周期內(nèi)的函數(shù),比如created,mounted)

      Vue.config.errorHandler?=?function?(err)?{ console.error(‘Vue.error’,err.stack) //?邏輯處理 };

      框架:betterjsfundebug(收費(fèi)) 捕獲錯(cuò)誤的腳本要放置在最前面,確保可以收集到錯(cuò)誤信息 方法:

    • window.onerror()當(dāng)有js運(yùn)行時(shí)錯(cuò)誤觸發(fā)時(shí),onerror可以接受多個(gè)參數(shù)(message, source, lineno, colno, error)。

    • window.addEventListener('error'), function(e) {}, true 會(huì)比window.onerror先觸發(fā),不能阻止默認(rèn)事件處理函數(shù)的執(zhí)行,但可以全局捕獲資源加載異常的錯(cuò)誤

    • 前端JS錯(cuò)誤捕獲--sourceMap

      如何監(jiān)控網(wǎng)頁崩潰?**崩潰和卡頓有何差別?**監(jiān)控錯(cuò)誤

    • Service Worker 有自己獨(dú)立的工作線程,與網(wǎng)頁區(qū)分開,網(wǎng)頁崩潰了,Service Worker 一般情況下不會(huì)崩潰;

    • Service Worker 生命周期一般要比網(wǎng)頁還要長(zhǎng),可以用來監(jiān)控網(wǎng)頁的狀態(tài);

      卡頓:加載中,渲染遇到阻塞

    • 性能監(jiān)控 && 性能優(yōu)化

      性能指標(biāo):

      • FP(首次繪制)

      • FCP(首次內(nèi)容繪制 First contentful paint)

      • LCP(最大內(nèi)容繪制時(shí)間 Largest contentful paint)

      • FPS(每秒傳輸幀數(shù))

      • TTI(頁面可交互時(shí)間 Time to Interactive)

      • HTTP 請(qǐng)求響應(yīng)時(shí)間

      • DNS 解析時(shí)間

      • TCP 連接時(shí)間

      性能數(shù)據(jù)采集需要使用 window.performance API , ? JS庫 web-vitals:import {getLCP} from 'web-vitals';

      ????//?重定向耗時(shí)redirect:?timing.redirectEnd?-?timing.redirectStart,//?DOM?渲染耗時(shí)dom:?timing.domComplete?-?timing.domLoading,//?頁面加載耗時(shí)load:?timing.loadEventEnd?-?timing.navigationStart,//?頁面卸載耗時(shí)unload:?timing.unloadEventEnd?-?timing.unloadEventStart,//?請(qǐng)求耗時(shí)request:?timing.responseEnd?-?timing.requestStart,//?獲取性能信息時(shí)當(dāng)前時(shí)間time:?new?Date().getTime(),//?DNS查詢耗時(shí)domainLookupEnd?-?domainLookupStart//?TCP鏈接耗時(shí)connectEnd?-?connectStart//?request請(qǐng)求耗時(shí)responseEnd?-?responseStart//?解析dom樹耗時(shí)domComplete?-?domInteractive//?白屏?xí)r間domloadng?-?fetchStart//?onload時(shí)間loadEventEnd?-?fetchStart

      性能優(yōu)化常用手段:緩存技術(shù)、 ? 預(yù)加載技術(shù)、 ? 渲染方案。

    • 緩存 :主要有 cdn、瀏覽器緩存、本地緩存以及應(yīng)用離線包

    • 預(yù)加載 :資源預(yù)拉取(prefetch)則是另一種性能優(yōu)化的技術(shù)。通過預(yù)拉取可以告訴瀏覽器用戶在未來可能用到哪些資源。

      • prefetch支持預(yù)拉取圖片、腳本或者任何可以被瀏覽器緩存的資源。

        在head里 添加 <linkrel="prefetch"href="image.png">

      • prerender是一個(gè)重量級(jí)的選項(xiàng),它可以讓瀏覽器提前加載指定頁面的所有資源。

      • subresource可以用來指定資源是最高優(yōu)先級(jí)的。當(dāng)前頁面需要,或者馬上就會(huì)用到時(shí)。

    • 渲染方案

      • 靜態(tài)渲染(SR)

      • 前端渲染(CSR)

      • 服務(wù)端渲染(SSR)

      • 客戶端渲染(NSR):NSR 數(shù)據(jù)請(qǐng)求,首屏數(shù)據(jù)請(qǐng)求和數(shù)據(jù)線上與 webview 的一個(gè)初始化和框架 JS 初始化并行了起來,大大縮短了首屏?xí)r間。

      640.png

      常見的六種設(shè)計(jì)模式以及應(yīng)用場(chǎng)景

      https://www.cnblogs.com/whu-2017/p/9471670.html

      觀察者模式的概念

      觀察者模式模式,屬于行為型模式的一種,它定義了一種一對(duì)多的依賴關(guān)系,讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽某一個(gè)主題對(duì)象。這個(gè)主體對(duì)象在狀態(tài)變化時(shí),會(huì)通知所有的觀察者對(duì)象。

      發(fā)布訂閱者模式的概念

      發(fā)布-訂閱模式,消息的發(fā)送方,叫做發(fā)布者(publishers),消息不會(huì)直接發(fā)送給特定的接收者,叫做訂閱者。意思就是發(fā)布者和訂閱者不知道對(duì)方的存在。需要一個(gè)第三方組件,叫做信息中介,它將訂閱者和發(fā)布者串聯(lián)起來,它過濾和分配所有輸入的消息。換句話說,發(fā)布-訂閱模式用來處理不同系統(tǒng)組件的信息交流,即使這些組件不知道對(duì)方的存在。

      需要一個(gè)第三方組件,叫做信息中介,它將訂閱者和發(fā)布者串聯(lián)起來

      工廠模式 ?主要是為創(chuàng)建對(duì)象提供了接口。場(chǎng)景:在編碼時(shí)不能預(yù)見需要?jiǎng)?chuàng)建哪種類的實(shí)例。

      代理模式 命令模式

      單例模式

      保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問它的全局訪問點(diǎn)。(window)

      Http 及瀏覽器相關(guān)

      七層網(wǎng)絡(luò)模型

      應(yīng)用層、表示層、會(huì)話層、傳輸層、網(wǎng)絡(luò)層、數(shù)據(jù)鏈路層、物理層

      TCP:面向連接、傳輸可靠(保證數(shù)據(jù)正確性,保證數(shù)據(jù)順序)、用于傳輸大量數(shù)據(jù)(流模式)、速度慢,建立連接需要開銷較多(時(shí)間,系統(tǒng)資源) 。(應(yīng)用場(chǎng)景:HTP,HTTP,郵件)

      UDP:面向非連接、傳輸不可靠、用于傳輸少量數(shù)據(jù)(數(shù)據(jù)包模式)、速度快 ,可能丟包(應(yīng)用場(chǎng)景:即時(shí)通訊)

      是否連接?????面向連接?????面向非連接 傳輸可靠性???可靠????????不可靠 應(yīng)用場(chǎng)合????少量數(shù)據(jù)????傳輸大量數(shù)據(jù)

      https

      客戶端先向服務(wù)器端索要公鑰,然后用公鑰加密信息,服務(wù)器收到密文后,用自己的私鑰解密。服務(wù)器公鑰放在數(shù)字證書中。

      url到加載渲染全過程

    • DNS域名解析。

    • TCP三次握手,建立接連。

    • 發(fā)送HTTP請(qǐng)求報(bào)文。

    • 服務(wù)器處理請(qǐng)求返回響應(yīng)報(bào)文。

    • 瀏覽器解析渲染頁面。

    • 四次揮手,斷開連接。

    • DNS 協(xié)議提供通過域名查找 IP地址,或逆向從 IP地址反查域名的服務(wù)。DNS 是一個(gè)網(wǎng)絡(luò)服務(wù)器,我們的域名解析簡(jiǎn)單來說就是在 DNS 上記錄一條信息記錄。

      TCP 三次握手,四次揮手:握手揮手都是客戶端發(fā)起,客戶端結(jié)束。三次握手與四次揮手詳解

      負(fù)載均衡:請(qǐng)求在進(jìn)入到真正的應(yīng)用服務(wù)器前,可能還會(huì)先經(jīng)過負(fù)責(zé)負(fù)載均衡的機(jī)器,它的作用是將請(qǐng)求合理地分配到多個(gè)服務(wù)器上,轉(zhuǎn)發(fā)HTTP請(qǐng)求;同時(shí)具備具備防攻擊等功能。可分為DNS負(fù)載均衡,HTTP負(fù)載均衡,IP負(fù)載均衡,鏈路層負(fù)載均衡等。

      Web Server:請(qǐng)求經(jīng)過前面的負(fù)載均衡后,將進(jìn)入到對(duì)應(yīng)服務(wù)器上的 Web Server,比如 Apache、Tomcat

      反向代理是工作在 HTTP 上的,一般都是 Nginx。全國各地訪問baidu.com就肯定要通過代理訪問,不可能都訪問百度的那臺(tái)服務(wù)器。?(VPN正向代理,代理客戶端)

      瀏覽器解析渲染過程:返回的html傳遞到瀏覽器后,如果有g(shù)zip會(huì)先解壓,找出文件編碼格式,外鏈資源的加載 html從上往下解析,遇到j(luò)s,css停止解析渲染,直到j(luò)s執(zhí)行完成。解析HTML,構(gòu)建DOM樹 解析CSS,生成CSS規(guī)則樹 合并DOM樹和CSS規(guī)則,生成render樹去渲染

      不會(huì)引起DOM樹變化,頁面布局變化,改變?cè)貥邮降男袨榻?strong>重繪

      引起DOM樹結(jié)構(gòu)變化,頁面布局變化的行為叫回流

      GUI渲染線程負(fù)責(zé)渲染瀏覽器界面HTML元素,當(dāng)界面需要 重繪(Repaint) 或由于某種操作引發(fā) 回流(reflow) 時(shí),該線程就會(huì)執(zhí)行。在Javascript引擎運(yùn)行腳本期間,GUI渲染線程都是處于掛起狀態(tài)的,也就是說被”凍結(jié)”了. 直到JS程序執(zhí)行完成,才會(huì)接著執(zhí)行。因此如果JS執(zhí)行的時(shí)間過長(zhǎng),這樣就會(huì)造成頁面的渲染不連貫,導(dǎo)致頁面渲染加載阻塞的感覺。JavaScript是可操縱DOM的,如果在修改這些元素屬性同時(shí)渲染界面,渲染前后元素?cái)?shù)據(jù)可能不一致

      GPU繪制多進(jìn)程的瀏覽器:主控進(jìn)程,插件進(jìn)程,GPU,tab頁(瀏覽器內(nèi)核)多線程的瀏覽器內(nèi)核:每一個(gè)tab頁面可以看作是瀏覽器內(nèi)核進(jìn)程,然后這個(gè)進(jìn)程是多線程的。

      它有幾大類子線程:

      • GUI線程

      • JS引擎線程

      • 事件觸發(fā)線程

      • 定時(shí)器線程

      • HTTP請(qǐng)求線程

      http1 跟HTTP2

      http2

      多路復(fù)用:相同域名多個(gè)請(qǐng)求,共享同一個(gè)TCP連接,降低了延遲

      請(qǐng)求優(yōu)先級(jí):給每個(gè)request設(shè)置優(yōu)先級(jí)

      二進(jìn)制傳輸;之前是用純文本傳輸

      數(shù)據(jù)流:數(shù)據(jù)包不是按順序發(fā)送,對(duì)數(shù)據(jù)包做標(biāo)記。每個(gè)請(qǐng)求或回應(yīng)的所有數(shù)據(jù)包成為一個(gè)數(shù)據(jù)流,

      服務(wù)端推送:可以主動(dòng)向客戶端發(fā)送消息。

      頭部壓縮:減少包的大小跟數(shù)量

      HTTP/1.1 中的管道( pipeline)傳輸中如果有一個(gè)請(qǐng)求阻塞了,那么隊(duì)列后請(qǐng)求也統(tǒng)統(tǒng)被阻塞住了 HTTP/2 多請(qǐng)求復(fù)用一個(gè)TCP連接,一旦發(fā)生丟包,就會(huì)阻塞住所有的 HTTP 請(qǐng)求。HTTP/3 把 HTTP 下層的 TCP 協(xié)議改成了 UDP!http1 keep alive 串行傳輸

      http 中的 keep-alive 有什么作用

      響應(yīng)頭中設(shè)置?keep-alive?可以在一個(gè) TCP 連接上發(fā)送多個(gè) http 請(qǐng)求

      瀏覽器緩存策略

      強(qiáng)緩存:cache-control;no-cache max-age=<10000000>;expires;其中Cache-Conctrol的優(yōu)先級(jí)比Expires高;

      控制強(qiáng)制緩存的字段分別是Expires和Cache-Control,如果客戶端的時(shí)間小于Expires的值時(shí),直接使用緩存結(jié)果。

      協(xié)商緩存:Last-Modified / If-Modified-Since和Etag / If-None-Match,其中Etag / If-None-Match的優(yōu)先級(jí)比Last-Modified / 首次請(qǐng)求,服務(wù)器會(huì)在返回的響應(yīng)頭中加上Last-Modified字段,表示資源最后修改的時(shí)間。

      瀏覽器再次請(qǐng)求時(shí),請(qǐng)求頭中會(huì)帶上If-Modified-Since字段,比較兩個(gè)字段,一樣則證明資源未修改,返回304,否則重新返回資源,狀態(tài)碼為200;

      垃圾回收機(jī)制:

      標(biāo)記清除:進(jìn)入執(zhí)行環(huán)境的變量都被標(biāo)記,然后執(zhí)行完,清除這些標(biāo)記跟變量。查看變量是否被引用。

      引用計(jì)數(shù):會(huì)記錄每個(gè)值被引用的次數(shù),當(dāng)引用次數(shù)變成0后,就會(huì)被釋放掉。

      前端安全

      同源策略:如果兩個(gè) URL 的協(xié)議、域名和端口都相同,我們就稱這兩個(gè) URL 同源。因?yàn)闉g覽器有cookies。

      • XSS:跨站腳本攻擊(Cross Site Scripting) input, textarea等所有可能輸入文本信息的區(qū)域,輸入<script src="http://惡意網(wǎng)站"></script>等,提交后信息會(huì)存在服務(wù)器中 。

      • CSRF:跨站請(qǐng)求偽造 。引誘用戶打開黑客的網(wǎng)站,在黑客的網(wǎng)站中,利用用戶的登錄狀態(tài)發(fā)起的跨站請(qǐng)求。

        A站點(diǎn)img的src=B站點(diǎn)的請(qǐng)求接口,可以訪問;解決:referer攜帶請(qǐng)求來源

        訪問該頁面后,表單自動(dòng)提交, 模擬完成了一次POST操作,發(fā)送post請(qǐng)求

        解決:后端注入一個(gè)隨機(jī)串到Cookie,前端請(qǐng)求取出隨機(jī)串添加傳給后端。

      • http 劫持:電信運(yùn)營(yíng)商劫持

      • SQL注入

      • 點(diǎn)擊劫持:誘使用戶點(diǎn)擊看似無害的按鈕(實(shí)則點(diǎn)擊了透明 iframe中的按鈕) ,解決后端請(qǐng)求頭加一個(gè)字段 X-Frame-Options

      • 文件上傳漏洞 :服務(wù)器未校驗(yàn)上傳的文件

      CSS 及 HTML

      什么是BFC(塊級(jí)格式化上下文)、IFC(內(nèi)聯(lián)格式化上下文 )、FFC(彈性盒模型)

      BFC(Block formatting context),即塊級(jí)格式化上下文,它作為HTML頁面上的一個(gè)獨(dú)立渲染區(qū)域,只有區(qū)域內(nèi)元素參與渲染,且不會(huì)影響其外部元素。簡(jiǎn)單來說,可以將 BFC 看做是一個(gè)“圍城”,外面的元素進(jìn)不來,里面的元素出不去(互不干擾)。

      一個(gè)決定如何渲染元素的容器 ,渲染規(guī)則 :

      • 1、內(nèi)部的塊級(jí)元素會(huì)在垂直方向,一個(gè)接一個(gè)地放置。

      • 2、塊級(jí)元素垂直方向的距離由margin決定。屬于同一個(gè)BFC的兩個(gè)相鄰塊級(jí)元素的margin會(huì)發(fā)生重疊。

      • 3、對(duì)于從左往右的格式化,每個(gè)元素(塊級(jí)元素與行內(nèi)元素)的左邊緣,與包含塊的左邊緣相接觸,(對(duì)于從右往左的格式化則相反)。即使包含塊中的元素存在浮動(dòng)也是如此,除非其中元素再生成一個(gè)BFC。

      • 4、BFC的區(qū)域不會(huì)與浮動(dòng)元素重疊。

      • 5、BFC是一個(gè)隔離的獨(dú)立容器,容器里面的子元素和外面的元素互不影響。

      • 6、計(jì)算BFC容器的高度時(shí),浮動(dòng)元素也參與計(jì)算。

      形成BFC的條件:

      1、浮動(dòng)元素,float 除 none 以外的值;

      2、定位元素,position(absolute,fixed);

      3、display 為以下其中之一的值 inline-block,table-cell,table-caption;

      4、overflow 除了 visible 以外的值(hidden,auto,scroll);

      BFC 一般用來解決以下幾個(gè)問題

      • 邊距重疊問題

      • 消除浮動(dòng)問題

      • 自適應(yīng)布局問題

      flex: 0 1 auto;?是什么意思?

      元素會(huì)根據(jù)自身寬高設(shè)置尺寸。它會(huì)縮短自身以適應(yīng) flex 容器,但不會(huì)伸長(zhǎng)并吸收 flex 容器中的額外自由空間來適應(yīng) flex 容器?。水平的主軸(main axis)和垂直的交叉軸(cross axis)幾個(gè)屬性決定按哪個(gè)軸的排列方向

      • flex-grow: 0 ?一個(gè)無單位數(shù)(): 它會(huì)被當(dāng)作<flex-grow>的值。

      • flex-shrink: 1 ?一個(gè)有效的**寬度(width)**值: 它會(huì)被當(dāng)作 <flex-basis>的值。

      • flex-basis: auto ?關(guān)鍵字none,auto或initial.

      放大比例、縮小比例、分配多余空間之前占據(jù)的主軸空間。

      避免CSS全局污染

    • scoped 屬性

    • css in js

    • const?styles?=?{bar:?{backgroundColor:?'#000'} } const?example?=?(props)=>{<div?style={styles.bar}?/> }
    • CSS Modules

    • 使用less,盡量少使用全局對(duì)選擇器

    • //?選擇器上>要記得寫,免得污染所有ul下面的li ul{>li{color:red;} }

      CSS Modules

      阮一峰 CSS Modules

      CSS Modules是一種構(gòu)建步驟中的一個(gè)進(jìn)程。通過構(gòu)建工具來使指定class達(dá)到scope的過程。

      CSS Modules 允許使用::global(.className)的語法,聲明一個(gè)全局規(guī)則。凡是這樣聲明的class,都不會(huì)被編譯成哈希字符串。:local(className): 做 localIdentName 規(guī)則處理,編譯唯一哈希類名。

      CSS Modules使用特點(diǎn):

      • 不使用選擇器,只使用 class 名來定義樣式

      • 不層疊多個(gè) class,只使用一個(gè) class 把所有樣式定義好

      • 不嵌套class

      盒子模型和?box-sizing?屬性

      width: 160px; padding: 20px; border: 8px solid orange;標(biāo)準(zhǔn) box-sizing: content-box; 元素的總寬度 = 160 + 202 + 82; IE的 border-box:總寬度160

      margin/padding取百分比的值時(shí) ,基于父元素的寬度和高度的。

      css繪制三角形

    • 通過border 處理

    • //?border?處理 .class?{width:?0;height:?0;border-left:?50px?solid?transparent;border-right:?50px?solid?transparent;border-bottom:?100px?solid?red; } //?寬高+border div?{width:?50px;height:?50px;border:?2px?solid?orange; }
    • clip-path裁剪獲得

    • div{clip-path:?polygon(0?100%,?50%?0,?100%?100%); }
    • 漸變linear-gradient 實(shí)現(xiàn)

    • div?{width:?200px;height:?200px;background:linear-gradient(to?bottom?right,?#fff?0%,?#fff?49.9%,?rgba(148,88,255,1)?50%,rgba(185,88,255,1)?100%); }

      CSS實(shí)現(xiàn)了三角形后如何給三角形添加陰影

      ???

      CSS兩列布局的N種實(shí)現(xiàn)

      兩列布局分為兩種,一種是左側(cè)定寬、右側(cè)自適應(yīng),另一種是兩列都自適應(yīng)(即左側(cè)寬度由子元素決定,右側(cè)補(bǔ)齊剩余空間)。

    • 左側(cè)定寬、右側(cè)自適應(yīng)如何實(shí)現(xiàn)

    • //?兩個(gè)元素都設(shè)置dislpay:inline-block .left?{display:?inline-block;width:?100px;height:?200px;background-color:?red;vertical-align:?top; } .right?{display:?inline-block;width:?calc(100%?-?100px);height:?400px;background-color:?blue;vertical-align:?top; } //?兩個(gè)元素設(shè)置浮動(dòng),右側(cè)自適應(yīng)元素寬度使用calc函數(shù)計(jì)算 .left{float:?left;width:?100px;height:?200px;background-color:?red; } .right{float:?left;width:?calc(100%?-?100px);height:?400px;background-color:?blue; } //?父元素設(shè)置display:flex,自適應(yīng)元素設(shè)置flex:1 .box{height:?600px;width:?100%;display:?flex; } .left{width:?100px;height:?200px;background-color:?red; } .right{flex:?1;height:?400px;background-color:?blue; } //?父元素相對(duì)定位,左側(cè)元素絕對(duì)定位,右側(cè)自適應(yīng)元素設(shè)置margin-left的值大于定寬元素的寬度 .left{position:?absolute;width:?100px;height:?200px;background-color:?red; } .right{margin-left:?100px;height:?400px;background-color:?blue; }
    • 左右兩側(cè)元素都自適應(yīng)

    • //?flex布局?同上 //?父元素設(shè)置display:grid;?grid-template-columns:auto?1fr;(這個(gè)屬性定義列寬,auto關(guān)鍵字表示由瀏覽器自己決定長(zhǎng)度。fr是一個(gè)相對(duì)尺寸單位,表示剩余空間做等分)grid-gap:20px(行間距) .parent{display:grid;grid-template-columns:auto?1fr;grid-gap:20px }? .left{background-color:?red;height:?200px; } .right{height:300px;background-color:?blue; } //?浮動(dòng)+BFC???父元素設(shè)置overflow:hidden,左側(cè)定寬元素浮動(dòng),右側(cè)自適應(yīng)元素設(shè)置overflow:auto創(chuàng)建BFC .box{height:?600px;width:?100%;overflow:?hidden; } .left{float:?left;width:?100px;height:?200px;background-color:?red; } .right{overflow:?auto;height:?400px;background-color:?blue; }

      CSS三列布局

    • float布局:左邊左浮動(dòng),右邊右浮動(dòng),中間margin:0 100px;

    • Position布局: 左邊left:0; 右邊right:0; 中間left: 100px; right: 100px;

    • table布局: 父元素 display: table; 左右 width: 100px; 三個(gè)元素display: table-cell;

    • 彈性(flex)布局:父元素 display: flex; 左右 width: 100px;

    • 網(wǎng)格(gird)布局:

    • //?gird提供了?gird-template-columns、grid-template-rows屬性讓我們?cè)O(shè)置行和列的高、寬 .div{width:?100%;display:?grid;grid-template-rows:?100px;grid-template-columns:?300px?auto?300px; }

      常見場(chǎng)景及問題

      app與H5 如何通訊交互的?

      //?兼容IOS和安卓 callMobile(parameters,messageHandlerName)?{//handlerInterface由iOS addScriptMessageHandler與andorid addJavascriptInterface 代碼注入而來。if?(/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent))?{//?alert('ios')window.webkit.messageHandlers[messageHandlerName].postMessage(JSON.stringify(parameters))}?else?{//?alert('安卓')//安卓傳輸不了js?json對(duì)象,只能傳輸stringwindow.webkit[messageHandlerName](JSON.stringify(parameters))} }

      由app將原生方法注入到window上供js調(diào)用

      messageHandlerName 約定的通信方法parameters 需要傳入的參數(shù)

      移動(dòng)端適配方案

      rem是相對(duì)于HTML的根元素em相對(duì)于父級(jí)元素的字體大小。VW,VH 屏幕寬度高度的高分比

      //按照寬度375圖算,?1rem?=?100px; (function?(win,?doc)?{function?changeSize()?{doc.documentElement.style.fontSize?=?doc.documentElement.clientWidth?/?3.75?+?'px';console.log(100?*?doc.documentElement.clientWidht?/?3.75)}changeSize();win.addEventListener('resize',?changeSize,?false);})(window,?document);

      代碼編程相關(guān)

      實(shí)現(xiàn)發(fā)布訂閱

      /*?Pubsub?*/ function?Pubsub(){//存放事件和對(duì)應(yīng)的處理方法this.handles?=?{}; }Pubsub.prototype?=?{//傳入事件類型type和事件處理handleon:?function?(type,?handle)?{if(!this.handles[type]){this.handles[type]?=?[];}this.handles[type].push(handle);},emit:?function?()?{//通過傳入?yún)?shù)獲取事件類型//將arguments轉(zhuǎn)為真數(shù)組var?type?=?Array.prototype.shift.call(arguments);if(!this.handles[type]){return?false;}for?(var?i?=?0;?i?<?this.handles[type].length;?i++)?{var?handle?=?this.handles[type][i];//執(zhí)行事件handle.apply(this,?arguments);}},off:?function?(type,?handle)?{handles?=?this.handles[type];if(handles){if(!handle){handles.length?=?0;//清空數(shù)組}else{for?(var?i?=?0;?i?<?handles.length;?i++)?{var?_handle?=?handles[i];if(_handle?===?handle){//從數(shù)組中刪除handles.splice(i,1);}}}}?? }

      promise怎么實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用跟返回不同的狀態(tài)

      //?MyPromise.js//?先定義三個(gè)常量表示狀態(tài) const?PENDING?=?'pending'; const?FULFILLED?=?'fulfilled'; const?REJECTED?=?'rejected';//?新建?MyPromise?類 class?MyPromise?{constructor(executor){//?executor?是一個(gè)執(zhí)行器,進(jìn)入會(huì)立即執(zhí)行//?并傳入resolve和reject方法executor(this.resolve,?this.reject)}//?儲(chǔ)存狀態(tài)的變量,初始值是?pendingstatus?=?PENDING;// resolve和reject為什么要用箭頭函數(shù)?//?如果直接調(diào)用的話,普通函數(shù)this指向的是window或者undefined//?用箭頭函數(shù)就可以讓this指向當(dāng)前實(shí)例對(duì)象//?成功之后的值value?=?null;//?失敗之后的原因reason?=?null;//?更改成功后的狀態(tài)resolve?=?(value)?=>?{//?只有狀態(tài)是等待,才執(zhí)行狀態(tài)修改if?(this.status?===?PENDING)?{//?狀態(tài)修改為成功this.status?=?FULFILLED;//?保存成功之后的值this.value?=?value;}}//?更改失敗后的狀態(tài)reject?=?(reason)?=>?{//?只有狀態(tài)是等待,才執(zhí)行狀態(tài)修改if?(this.status?===?PENDING)?{//?狀態(tài)成功為失敗this.status?=?REJECTED;//?保存失敗后的原因this.reason?=?reason;}}then(onFulfilled,?onRejected)?{//?判斷狀態(tài)if?(this.status?===?FULFILLED)?{//?調(diào)用成功回調(diào),并且把值返回onFulfilled(this.value);}?else?if?(this.status?===?REJECTED)?{//?調(diào)用失敗回調(diào),并且把原因返回onRejected(this.reason);}}}

      實(shí)現(xiàn)Promise.all

      //?Promise.all function?all(promises)?{let?len?=?promises.length,?res?=?[]if?(len)?{return?new?Promise(function?(resolve,?reject)?{for(let?i=0;?i?<?len;?i++){let?promise?=?promises[i];promise.then(response?=>?{res[i]?=?response//?當(dāng)返回結(jié)果為最后一個(gè)時(shí)if?(res.length?===?len)?{resolve(res)}},?error?=>?{reject(error)})}}) }

      對(duì)象數(shù)組轉(zhuǎn)換成tree數(shù)組

      >?將entries?按照?level?轉(zhuǎn)換成?result?數(shù)據(jù)結(jié)構(gòu)const?entries?=?[{"province":?"浙江",?"city":?"杭州",?"name":?"西湖"},?{"province":?"四川",?"city":?"成都",?"name":?"錦里"},?{"province":?"四川",?"city":?"成都",?"name":?"方所"},?{"province":?"四川",?"city":?"阿壩",?"name":?"九寨溝"} ];const?level?=?["province",?"city",?"name"];const??result?=?[{value:'浙江',children:[{value:'杭州',children:[{value:'西湖'}]}]},{value:'四川',children:[{value:'成都',children:[{value:'錦里'},{value:'方所'}]},{value:'阿壩',children:[{value:'九寨溝'}]}]}, ]

      思路:涉及到樹形數(shù)組,采用遞歸遍歷的方式

      function?transfrom(list,?level)?{const?res?=?[];list.forEach(item?=>?{pushItem(res,?item,?0);});function?pushItem(arr,?obj,?i)?{const?o?=?{value:?obj[level[i]],children:?[],};//?判斷傳入數(shù)組里是否有value等于要傳入的項(xiàng)const?hasItem?=?arr.find(el?=>?el.value?===?obj[level[i]]);let?nowArr;if(hasItem)?{//?存在,則下一次遍歷傳入存在項(xiàng)的childrennowArr?=?hasItem.children;}else{//?不存在?壓入arr,下一次遍歷傳入此項(xiàng)的childrenarr.push(o);nowArr?=?o.children;}if(i?===?level.length?-?1)?delete?o.children;i++;if(i?<?level.length)?{//?遞歸進(jìn)行層級(jí)的遍歷pushItem(nowArr,?obj,?i);}} }transfrom(entries,?level);

      JS instanceof 方法原生實(shí)現(xiàn)

      簡(jiǎn)單用法

      function?Fn?()?{} const?fn?=?new?Fn() fn?instanceof?Fn??//?true

      實(shí)現(xiàn)如下:

      //?left?instanceof?right function?_instanceof(left,?right)?{//?構(gòu)造函數(shù)原型const?prototype?=?right.prototype//?實(shí)列對(duì)象屬性,指向其構(gòu)造函數(shù)原型left?=?left.__proto__//?查實(shí)原型鏈while?(true)?{//?如果為null,說明原型鏈已經(jīng)查找到最頂層了,真接返回falseif?(left?===?null)?{return?false}//?查找到原型if?(prototype?===?left){return?true}//?繼續(xù)向上查找left?=?left.__proto__} }const?str?=?"abc" _instanceof(str,?String)?//?true

      編程題

      將有同樣元素的數(shù)組進(jìn)行合并

      //?例如: const?arr?=?[['a',?'b',?'c'],['a',?'d'],['d',?'e'],['f',?'g'],['h',?'g'],['i'] ] //?運(yùn)行后的返回結(jié)果是: [['a',?'b',?'c',?'d',?'e'],['f',?'g',?'h'],['i'] ] //?思路一: const?arr?=?[['a',?'b',?'c'],?['a',?'d'],?['d',?'e'],?['f',?'g'],?['h',?'g'],?['i']] function?transform(arr){let?res?=?[]arr?=?arr.map(el?=>?el.sort()).sort()const?item?=?arr.reduce((pre,?cur)?=>?{if?(cur.some(el?=>?pre?&&?pre.includes(el)))?{pre?=?pre.concat(cur)}?else?{res.push(pre)pre?=?cur}return?[...new?Set(pre)]})res.push(item)return?res; } transform(arr) //?console.log(transform(arr));//?思路二:?function?r?(arr)?{const?map?=?new?Map()arr.forEach((array,?index)?=>?{const?findAlp?=?array.find((v)?=>?map.get(v))if?(findAlp)?{const?set?=?map.get(findAlp)array.forEach((alp)?=>?{set.add(alp)const?findAlp2?=?map.get(alp)if?(findAlp2?&&?findAlp2?!==?set)?{for(const?v?of?findAlp2.values()){set.add(v)map.set(v,?set)}}map.set(alp,?set)})}?else?{const?set?=?new?Set(arr[index])array.forEach((alp)?=>?map.set(alp,?set))}})const?set?=?new?Set()const?ret?=?[]for?(const?[key,?value]?of?map.entries())?{if?(set.has(value))?continueset.add(value)ret.push([...value])}return?ret }

      最近組建了一個(gè)江西人的前端交流群,如果你是江西人可以加我微信?ruochuan12?私信 江西?拉你進(jìn)群。

      推薦閱讀

      我在阿里招前端,該怎么幫你(可進(jìn)面試群)
      我讀源碼的經(jīng)歷

      在字節(jié)做前端一年后,有啥收獲~
      老姚淺談:怎么學(xué)JavaScript?

      ·················?若川簡(jiǎn)介?·················

      你好,我是若川,畢業(yè)于江西高校。現(xiàn)在是一名前端開發(fā)“工程師”。寫有《學(xué)習(xí)源碼整體架構(gòu)系列》多篇,在知乎、掘金收獲超百萬閱讀。
      從2014年起,每年都會(huì)寫一篇年度總結(jié),已經(jīng)寫了7篇,點(diǎn)擊查看年度總結(jié)。
      同時(shí),活躍在知乎@若川,掘金@若川。致力于分享前端開發(fā)經(jīng)驗(yàn),愿景:幫助5年內(nèi)前端人走向前列。

      識(shí)別方二維碼加我微信、長(zhǎng)期交流學(xué)習(xí)

      今日話題

      略。歡迎分享、收藏、點(diǎn)贊、在看我的公眾號(hào)文章~

    總結(jié)

    以上是生活随笔為你收集整理的2021年7月 虾皮、货拉拉、有赞等面经总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。