摘要:最近的一次更新的變量有效,并且會作用于全部的引用的處理方式和相同,變量值輸出時根據(jù)之前最近的一次定義計算,每次引用最近的定義有效嵌套三種預(yù)編譯器的選擇器嵌套在使用上來說沒有任何區(qū)別,甚至連引用父級選擇器的標(biāo)記也相同。
面試匯總一:2018大廠高級前端面試題匯總
高級面試:【半月刊】前端高頻面試題及答案匯總
css內(nèi)容 響應(yīng)式布局 當(dāng)前主流的三種預(yù)編譯器比較CSS預(yù)處理器用一種專門的編程語言,進行Web頁面樣式設(shè)計,然后再編譯成正常的CSS文件,以供項目使用;
讓你的CSS更加簡潔、適應(yīng)性更強、可讀性更佳,更易于代碼的維護等諸多好處。
1.變量:
Sass聲明變量必須是『$』開頭,后面緊跟變量名和變量值,而且變量名和變量值需要使用冒號:分隔開。
Less 聲明變量用『@』開頭,其余等同 Sass。
Stylus 中聲明變量沒有任何限定,結(jié)尾的分號可有可無,但變量名和變量值之間必須要有『等號』。
2.作用域:
Sass:三者最差,不存在全局變量的概念。也就是說在 Sass 中定義了相同名字的變量時你就要小心蛋疼了。
Less:最近的一次更新的變量有效,并且會作用于全部的引用!
Stylus:Sass 的處理方式和 Stylus 相同,變量值輸出時根據(jù)之前最近的一次定義計算,每次引用最近的定義有效;
3.嵌套:
三種 css 預(yù)編譯器的「選擇器嵌套」在使用上來說沒有任何區(qū)別,甚至連引用父級選擇器的標(biāo)記 & 也相同。
4.繼承:
Sass和Stylus的繼承非常像,能把一個選擇器的所有樣式繼承到另一個選擇器上。使用『@extend』開始,后面接被繼承的選擇器。Stylus 的繼承方式來自 Sass,兩者如出一轍。
Less 則又「獨樹一幟」地用偽類來描述繼承關(guān)系;
5.導(dǎo)入@Import:
Sass 中只能在使用 url() 表達(dá)式引入時進行變量插值:
$device: mobile;
@import url(styles.#{$device}.css);
Less 中可以在字符串中進行插值:
@device: mobile;
@import "styles.@{device}.css";
Stylus 中在這里插值不管用,但是可以利用其字符串拼接的功能實現(xiàn):
device = "mobile"
@import "styles." + device + ".css"
總結(jié)
1.Sass和Less語法嚴(yán)謹(jǐn)、Stylus相對自由。因為Less長得更像 css,所以它可能學(xué)習(xí)起來更容易。
2.Sass 和 Compass、Stylus 和 Nib 都是好基友。
3.Sass 和 Stylus 都具有類語言的邏輯方式處理:條件、循環(huán)等,而 Less 需要通過When等關(guān)鍵詞模擬這些功能,這方面 Less 比不上 Sass 和 Stylus。
4.Less 在豐富性以及特色上都不及 Sass 和 Stylus,若不是因為 Bootstrap 引入了 Less,可能它不會像現(xiàn)在這樣被廣泛應(yīng)用(個人愚見)。
link與@import區(qū)別與選擇
"CSSurl路徑" rel="stylesheet" type="text/css" /
link功能較多,可以定義 RSS,定義 Rel 等作用,而@import只能用于加載 css;
當(dāng)解析到link時,頁面會同步加載所引的 css,而@import所引用的 css 會等到頁面加載完才被加載;
@import需要 IE5 以上才能使用;
link可以使用 js 動態(tài)引入,@import不行;
垂直居中布局css經(jīng)典布局系列一——垂直居中布局
css3的高級特性舉例 h5新增了哪些內(nèi)容或者API,使用過哪些? 1像素邊框問題 什么是BFCBFC 英文解釋: block formatting context。中文意思:塊級格式化上下文;
formatting context 意思是:頁面中一個渲染區(qū)域,有自己的一套渲染規(guī)則,決定其子元素如何定位,以及和其他兄弟元素的關(guān)系和作用。
BEC有如下特性
內(nèi)部的box會在垂直方向,從頂部開始一個接一個地放置;
box垂直方向的距離由margin決定。屬于同一個BFC的兩個相鄰的box的margin會發(fā)生折疊;
每一個元素的margin box的左遍,與包含塊border box的左邊相接觸。即使浮動元素也是如此;
BFC區(qū)域不會與float box疊加;
計算 BFC 的高度時,浮動子元素也參與計算;
文字層不會被浮動層覆蓋,環(huán)繞于周圍
float 除了none以外的值;
overflow 除了visible 以外的值(hidden,auto,scroll );
display (table-cell,table-caption,inline-block, flex, inline-flex);
position值為(absolute,fixed) 這些屬性值得元素都會自動創(chuàng)建 BFC;
BFC 最大的一個作用就是:在頁面上有一個獨立隔離容器,容器內(nèi)的元素 和 容器 外的元素布局不會相互影響。
解決上外邊距重疊;重疊的兩個box都開啟bfc;
解決浮動引起高度塌陷;容器盒子開啟bfc;
解決文字環(huán)繞圖片;左邊圖片div,右邊文本容器p,將p容器開啟bfc;
js基礎(chǔ) for...in和for...of區(qū)別for...in
1.循環(huán)出來的是index索引,是字符串型的數(shù)字;
2.遍歷順序有可能不是按照實際數(shù)組的內(nèi)部順序;
3.使用for in會遍歷數(shù)組所有的可枚舉屬性,包括原型上的以及數(shù)組自定義的屬性;
所以for in更適合遍歷對象,不要使用for in遍歷數(shù)組。
推薦在循環(huán)對象屬性的時候,使用for...in,在遍歷數(shù)組的時候的時候使用for...of;
for...in循環(huán)出的是key,for...of循環(huán)出的是value;
注意,for...of是ES6新引入的特性。修復(fù)了ES5引入的for...in的不足;
for...of不能循環(huán)普通的對象,需要通過和Object.keys()搭配使用;
Object.prototype.objCustom = function () {};
Array.prototype.arrCustom = function () {};
let iterable = [3, 5, 7];
iterable.foo = "hello";
for (let i in iterable) {
console.log(i); // logs 0, 1, 2, "foo", "arrCustom", "objCustom"
}
for (let i of iterable) {
console.log(i); // logs 3, 5, 7
}
script 引入方式:
html 靜態(tài)",則只是在dom中插入了一行字符串,就更不會管字符串里引入的js了,所以不能用這個方法插入script!!!
2.各個js文件的加載時機(script標(biāo)簽插入文檔的時機順序)
比如: 1.js 依賴 2.js,2.js 依賴 3.js;實際的加載順序是為 1.js,2.js,3.js
注意: 而實際模塊運行的順序,才是 3.js,2.js,1.js。所以,文件的加載、加載后文件的運行、模塊的運行,這是 3 個東西啊,別混了。
3.文件模塊的執(zhí)行時機
// 1.js 中的代碼
require([], functionA() {
// 主要邏輯代碼
})
文件的加載:將節(jié)點插入dom中,之后,下載 1.js 文件;
加載后文件的運行:1.js 文件加載完后,執(zhí)行 1.js 中的代碼,即執(zhí)行 require() 函數(shù)!!!
模塊的運行: require回調(diào)函數(shù),上方的,主要邏輯代碼,所在的函數(shù),functionA,的運行!!!
文件加載/文件運行 順序: 1.js , 2.js , 3.js;
模塊運行 順序:3.js , 2.js , 1.js;
webpack對比requirejswebpack在管理模塊的時候不需要再封裝一層像requireJS如下的東西
define(["jquery"], function(jquery){})
它實現(xiàn)了前端代碼模塊化,提高了代碼的復(fù)用性,從而提供公共模塊的緩存功能。
webpack通過打包,不同頁面多帶帶加載自己的模塊的javascript 和 common javascript,而requireJS將所有的javascript文件打包成一個文件,使得一個站點中多個頁面之間公用的JS模塊無法緩存。
Webpack 引入了切分點(split point)與代碼塊(Chunk),切分點定義了所有依賴的模塊,合起來就是一個代碼塊,從而實現(xiàn)一個頁面引用一個代碼塊。
主流框架Vue vue2中的diff算法是怎樣實現(xiàn)的?參考:讓虛擬DOM和DOM-diff不再成為你的絆腳石
當(dāng)數(shù)據(jù)發(fā)生改變時,set方法會讓調(diào)用Dep.notify通知所有訂閱者Watcher,訂閱者就會調(diào)用patch給真實的DOM打補丁,更新相應(yīng)的視圖。
patch函數(shù)接收兩個參數(shù)oldVnode和Vnode分別代表新的節(jié)點和之前的舊節(jié)點
判斷兩節(jié)點是否值得比較,值得比較則執(zhí)行patchVnode;
不值得比較則用Vnode替換oldVnode;
patchVnode:當(dāng)我們確定兩個節(jié)點值得比較之后我們會對兩個節(jié)點指定patchVnode方法;
找到對應(yīng)的真實dom,稱為el;
判斷Vnode和oldVnode是否指向同一個對象,如果是,那么直接return;
如果他們都有文本節(jié)點并且不相等,那么將el的文本節(jié)點設(shè)置為Vnode的文本節(jié)點;
如果oldVnode有子節(jié)點而Vnode沒有,則刪除el的子節(jié)點;
如果oldVnode沒有子節(jié)點而Vnode有,則將Vnode的子節(jié)點真實化之后添加到el;
如果兩者都有子節(jié)點,則執(zhí)行updateChildren函數(shù)比較子節(jié)點,這一步很重要;
updateChildren函數(shù)圖解
現(xiàn)在分別對oldS、oldE、S、E兩兩做sameVnode比較,有四種比較方式,當(dāng)其中兩個能匹配上那么真實dom中的相應(yīng)節(jié)點會移到Vnode相應(yīng)的位置,這句話有點繞,打個比方:
如果是oldS和E匹配上了,那么真實dom中的第一個節(jié)點會移到最后;
如果是oldE和S匹配上了,那么真實dom中的最后一個節(jié)點會移到最前,匹配上的兩個指針向中間移動;
如果四種匹配沒有一對是成功的,那么遍歷oldChild,S挨個和他們匹配,匹配成功就在真實dom中將成功的節(jié)點移到最前面,如果依舊沒有成功的,那么將S對應(yīng)的節(jié)點插入到dom中對應(yīng)的oldS位置,oldS和S指針向中間移動。
vue雙向數(shù)據(jù)綁定vue.js 是采用數(shù)據(jù)劫持結(jié)合發(fā)布者-訂閱者模式的方式,通過Object.defineProperty()來劫持各個屬性的setter,getter,在數(shù)據(jù)變動時發(fā)布消息給訂閱者,觸發(fā)相應(yīng)的監(jiān)聽回調(diào)。
第一步:需要observe的數(shù)據(jù)對象進行遞歸遍歷,包括子屬性對象的屬性,都加上 setter和getter。這樣的話,給這個對象的某個值賦值,就會觸發(fā)setter,那么就能監(jiān)聽到了數(shù)據(jù)變化;
第二步:compile解析模板指令,將模板中的變量替換成數(shù)據(jù),然后初始化渲染頁面視圖,并將每個指令對應(yīng)的節(jié)點綁定更新函數(shù),添加監(jiān)聽數(shù)據(jù)的訂閱者,一旦數(shù)據(jù)有變動,收到通知,更新視圖;
第三步:Watcher訂閱者是Observer和Compile之間通信的橋梁,主要做的事情是:
1、在自身實例化時往屬性訂閱器(dep)里面添加自己
2、自身必須有一個update()方法
3、待屬性變動dep.notice()通知時,能調(diào)用自身的update()方法,并觸發(fā)Compile中綁定的回調(diào),則功成身退。
第四步:MVVM作為數(shù)據(jù)綁定的入口,整合Observer、Compile和Watcher三者,通過Observer來監(jiān)聽自己的model數(shù)據(jù)變化,通過Compile來解析編譯模板指令,最終利用Watcher搭起Observer和Compile之間的通信橋梁,達(dá)到數(shù)據(jù)變化 -> 視圖更新;視圖交互變化(input) -> 數(shù)據(jù)model變更的雙向綁定效果。
基于vue數(shù)據(jù)綁定,如果data中的數(shù)據(jù)進行了一秒1000次的改變,每次改變會全部顯示在頁面中嗎?
vue生命周期的執(zhí)行過程首先創(chuàng)建一個vue實例,Vue();
在創(chuàng)建Vue實例的時候,執(zhí)行了init(),在init過程中首先調(diào)用了beforeCreate。
Created之前,對data內(nèi)的數(shù)據(jù)進行了數(shù)據(jù)監(jiān)聽,并且初始化了Vue內(nèi)部事件。具體如下:
完成了數(shù)據(jù)觀測;
完成了屬性和方法的運算;
完成了watch/event事件的回調(diào);
但是此時還未掛載dom上,$el屬性是不可見的;
beforeMount之前,完成了模板的編譯。把data對象里面的數(shù)據(jù)和vue的語法寫的模板編譯成了html,但是此時還沒有將編譯出來的html渲染到頁面;
1、在實例內(nèi)部有template屬性的時候,直接用內(nèi)部的,然后調(diào)用render函數(shù)去渲染。
2、在實例內(nèi)部沒有找到template,就調(diào)用外部的html(“el”option(選項))。實例內(nèi)部的template屬性比外部的優(yōu)先級高。 render函數(shù) > template屬性 > 外部html;
3、要是前兩者都不滿足,那么就拋出錯誤。
Mounted之前執(zhí)行了render函數(shù),將渲染出來的內(nèi)容掛載到了DOM節(jié)點上。mounted是將html掛載到頁面完成后觸發(fā)的鉤子函數(shù);當(dāng)mounted執(zhí)行完畢,整個實例算是走完了流程;在整個實例過程中,mounted僅執(zhí)行一次;
beforeUpdate:數(shù)據(jù)發(fā)生變化時,會調(diào)用beforeUpdate,然后經(jīng)歷virtual DOM,最后updated更新完成;
beforeDestory是實例銷毀前鉤子函數(shù),銷毀了所有觀察者,子組件以及事件監(jiān)聽;
destoryed實例銷毀執(zhí)行的鉤子函數(shù);
beforeCreate:初始化了部分參數(shù),如果有相同的參數(shù),做了參數(shù)合并,執(zhí)行 beforeCreate;el和數(shù)據(jù)對象都為undefined,還未初始化;
created :初始化了 Inject 、Provide 、 props 、methods 、data 、computed 和 watch,執(zhí)行 created ;data有了,el還沒有;
beforeMount :檢查是否存在 el 屬性,存在的話進行渲染 dom 操作,執(zhí)行 beforeMount;$el和data都初始化了,但是dom還是虛擬節(jié)點,dom中對應(yīng)的數(shù)據(jù)還沒有替換;
mounted :實例化 Watcher ,渲染 dom,執(zhí)行 mounted ;vue實例掛載完成,dom中對應(yīng)的數(shù)據(jù)成功渲染;
beforeUpdate :在渲染 dom 后,執(zhí)行了 mounted 鉤子后,在數(shù)據(jù)更新的時候,執(zhí)行 beforeUpdate ;
updated :檢查當(dāng)前的 watcher 列表中,是否存在當(dāng)前要更新數(shù)據(jù)的 watcher ,如果存在就執(zhí)行 updated ;
beforeDestroy :檢查是否已經(jīng)被卸載,如果已經(jīng)被卸載,就直接 return 出去,否則執(zhí)行 beforeDestroy ;
destroyed :把所有有關(guān)自己痕跡的地方,都給刪除掉;
Vue.js的template編譯參考:Vue2 原理淺談
const ast = parse(template.trim(), options) // 構(gòu)建抽象語法樹
optimize(ast, options) // 優(yōu)化
const code = generate(ast, options) // 生成代碼
return {
ast,
render: code.render,
staticRenderFns: code.staticRenderFns
}
可以分成三部分
將模板轉(zhuǎn)化為抽象語法樹;
優(yōu)化抽象語法樹;
根據(jù)抽象語法樹生成代碼;
具體做了什么
第一部分其實就是各種正則了,對左右開閉標(biāo)簽的匹配以及屬性的收集,通過棧的形式,不斷出棧入棧去匹配以及更換父節(jié)點,最后生成一個對象,包含children,children又包含children的對象;
第二部分則是以第一部分為基礎(chǔ),根據(jù)節(jié)點類型找出一些靜態(tài)的節(jié)點并標(biāo)記;
第三部分就是生成render函數(shù)代碼了
簡言之,就是先轉(zhuǎn)化成AST樹,再得到的render函數(shù)返回VNode(Vue的虛擬DOM節(jié)點);
回答:
首先,通過compile編譯器把template編譯成AST語法樹(abstract syntax tree 即 源代碼的抽象語法結(jié)構(gòu)的樹狀表現(xiàn)形式),compile是createCompiler的返回值,createCompiler是用以創(chuàng)建編譯器的。另外compile還負(fù)責(zé)合并option。
然后,AST會經(jīng)過generate(將AST語法樹轉(zhuǎn)化成render funtion字符串的過程)得到render函數(shù),render的返回值是VNode,VNode是Vue的虛擬DOM節(jié)點,里面有(標(biāo)簽名、子節(jié)點、文本等等);
在組件級別,vue會執(zhí)行一個new Watcher;
new Watcher首先會有一個求值的操作,它的求值就是執(zhí)行一個函數(shù),這個函數(shù)會執(zhí)行render,其中可能會有編譯模板成render函數(shù)的操作,然后生成vnode(virtual dom),再將virtual dom應(yīng)用到視圖中;
其中將virtual dom應(yīng)用到視圖中(這里涉及到diff后文會講),一定會對其中的表達(dá)式求值(比如{{message}},我們肯定會取到它的值再去渲染的),這里會觸發(fā)到相應(yīng)的getter操作完成依賴的收集;
當(dāng)數(shù)據(jù)變化的時候,就會notify到這個組件級別的Watcher,然后它還會去求值,從而重新收集依賴,并且重新渲染視圖;
vue的computed和watch區(qū)別computed 是計算一個新的屬性,并將該屬性掛載到 vm(Vue 實例)上,而 watch 是監(jiān)聽已經(jīng)存在且已掛載到 vm 上的數(shù)據(jù),所以用 watch 同樣可以監(jiān)聽 computed 計算屬性的變化(其它還有 data、props)
computed 本質(zhì)是一個惰性求值的觀察者,具有緩存性,只有當(dāng)依賴變化后,第一次訪問 computed 屬性,才會計算新的值,而 watch 則是當(dāng)數(shù)據(jù)發(fā)生變化便會調(diào)用執(zhí)行函數(shù)
從使用場景上說,computed 適用一個數(shù)據(jù)被多個數(shù)據(jù)影響,而 watch 適用一個數(shù)據(jù)影響多個數(shù)據(jù);
computed的原理,是如何和被計算的數(shù)據(jù)聯(lián)系起來的需要考慮
如何與其他的屬性建立聯(lián)系的;
屬性改變后,如何通知計算屬性重新計算的;
初始化data時,會使用Object.defineProperty 對所有的屬性數(shù)據(jù)劫持;
初始化computed,會遍歷所有的computed,對每一個計算屬性會調(diào)用initComputed函數(shù),生成watcher實例;
watcher實例中會進行依賴收集;
computed計算時:
會將當(dāng)前的watcher實例賦給 Dep.target;
執(zhí)行計算屬性的getter方法;
去讀取被計算的屬性時,就會觸發(fā)這些被計算屬性的相應(yīng)getter方法。當(dāng)判定被計算的屬性是計算屬性的相關(guān)依賴時,就會去建立依賴關(guān)系,既將計算屬性的watcher添加到這些被計算屬性的watcher內(nèi)的消息訂閱器dep中。
完成之后將Dep.target 賦為 null 并返回求值函數(shù)結(jié)果。
vue組件間的七種交互1.props和$emit
父組件向子組件傳遞數(shù)據(jù)是通過prop傳遞的,子組件傳遞數(shù)據(jù)給父組件是通過$emit觸發(fā)事件來做到的。
2.特性綁定$attrs和$listeners
如果父組件A下面有子組件B,組件B下面有組件C,這時如果組件A想傳遞數(shù)據(jù)給組件C怎么辦呢? 如果繼續(xù)用上面的方法,會變得非常復(fù)雜,不利于維護;Vue 2.4開始提供了$attrs和$listeners來解決這個問題,能夠讓組件A之間傳遞消息給組件C。
3.中央事件總線 Events Bus
新建一個Vue事件bus對象,然后通過bus.$emit觸發(fā)事件,bus.$on監(jiān)聽觸發(fā)的事件。
4.依賴注入:provide和inject
父組件中通過provider來提供變量,然后在子組件中通過inject來注入變量。
不論子組件有多深,只要調(diào)用了inject那么就可以注入provider中的數(shù)據(jù)。而不是局限于只能從當(dāng)前父組件的prop屬性來獲取數(shù)據(jù),只要在父組件的生命周期內(nèi),子組件都可以調(diào)用。
// 父組件
name: "Parent",
provide: {
for: "demo"
},
components:{
childOne
}
// 子組件
name: "childOne",
inject: ["for"],
data() {
return {
demo: this.for
}
},
components: {
childtwo
}
5.v-model
父組件通過v-model傳遞值給子組件時,會自動傳遞一個value的prop屬性,在子組件中通過this.$emit(‘input’,val)自動修改v-model綁定的值
子組件引用:ref和$refs
7.父鏈和子索引:$parent和$children
8.vue1中boradcast和dispatch
vue1.0中提供了這種方式,但vue2.0中沒有,但很多開源軟件都自己封裝了這種方式,比如min ui、element ui和iview等。
9.vuex
組件之間通信使用的設(shè)計模式?目前還沒有答案~~~~(阿里電話面試的一個問題)
vuex原理參考:深入vuex原理(上)
參考:Vuex 源碼解析
vuex的state是借助vue的響應(yīng)式data實現(xiàn)的。
// 使用 this.$store.getters.xxx 獲取 xxx 屬性時,實際上是獲取的store._vm.data.$$state 對象上的同名屬性
get state () {
return this._vm._data.$$state
}
// 處理state 和 getter的核心函數(shù)resetStoreVM(this, state)
store._vm = new Vue({
data: {
$$state: state
}
})
// 由于vue的data是響應(yīng)式的,所以,$$state也是響應(yīng)式的,那么當(dāng)我們 在一個組件實例中 對state.xxx進行 更新時,基于vue的data的響應(yīng)式機制,所有相關(guān)組件的state.xxx的值都會自動更新,UI自然也會自動更新
getter是借助vue的計算屬性computed特性實現(xiàn)的。
// wrappedGetters方法
const computed = {};
// 處理getters
forEachValue(wrappedGetters, (fn, key) => {
computed[key] = () => fn(store) // 將getter存儲在computed上
//this.$store.getters.XXX的時候獲取的是store._vm.XXX
Object.defineProperty(store.getters, key, {
get: () => store._vm[key],
enumerable: true
})
})
其設(shè)計思想與vue中央事件總線如出一轍。中央事件總線的實現(xiàn),簡單講就是新建了一個vue對象,借助vue對象的特性(emit 與on) 作為其他組件的通信橋梁,實現(xiàn)組件間的通信 以及數(shù)據(jù)共享!
Vue-router 中hash模式和history模式的區(qū)別hash模式url里面永遠(yuǎn)帶著#號,我們在開發(fā)當(dāng)中默認(rèn)使用這個模式。那么什么時候要用history模式呢?如果用戶考慮url的規(guī)范那么就需要使用history模式,因為history模式?jīng)]有#號,是個正常的url適合推廣宣傳。
當(dāng)然其功能也有區(qū)別,比如我們在開發(fā)app的時候有分享頁面,那么這個分享出去的頁面就是用vue或是react做的,咱們把這個頁面分享到第三方的app里,有的app里面url是不允許帶有#號的,所以要將#號去除那么就要使用history模式,但是使用history模式還有一個問題就是,在訪問二級頁面的時候,做刷新操作,會出現(xiàn)404錯誤,那么就需要和后端人配合讓他配置一下apache或是nginx的url重定向,重定向到你的首頁路由上就ok啦。
路由的哈希模式其實是利用了window可以監(jiān)聽onhashchange事件,也就是說你的url中的哈希值(#后面的值)如果有變化,前端是可以做到監(jiān)聽并做一些響應(yīng)(搞點事情),這么一來,即使前端并沒有發(fā)起http請求他也能夠找到對應(yīng)頁面的代碼塊進行按需加載。
pushState與replaceState,這兩個神器的作用就是可以將url替換并且不刷新頁面,好比掛羊頭賣狗肉,http并沒有去請求服務(wù)器該路徑下的資源,一旦刷新就會暴露這個實際不存在的“羊頭”,顯示404。這就需要服務(wù)器端做點手腳,將不存在的路徑請求重定向到入口文件(index.html)。
自定義組件參考:Vue——關(guān)于自定義組件
secondDemoComponent.js
index.js:index.js文件幫我們把所有自定義的組件都通過Vue.component注冊了,最后export一個包含install方法的對象給Vue.use()使用。
統(tǒng)一導(dǎo)入
import global from "./components/global/index.js"
Vue.use(global)
計算機網(wǎng)絡(luò)
http 狀態(tài)碼的分類?什么是無狀態(tài)?
http無狀態(tài)
服務(wù)器中沒有保存客戶端的狀態(tài),客戶端必須每次帶上自己的狀態(tài)去請求服務(wù)器;
每次的請求都是獨立的,<它的執(zhí)行情況和結(jié)果>與<前面的請求>和<之后的請求>是無直接關(guān)系的
狀態(tài)碼分類
1XX指示信息,表示信息已接收,繼續(xù)處理;
2XX成功-表示請求已被成功接收;
3XX重定向,表示要完成請求進行更進一步操作;
4XX客戶端錯誤,請求依法錯誤或請求無法實現(xiàn);
5XX服務(wù)器端錯誤,服務(wù)器未能實現(xiàn)合法請求;
舉例:
200,請求成功;
302:重定向;
304:上次請求后頁面未修改;
400:客戶端請求語法錯誤;
401:權(quán)限問題;
403,服務(wù)器接受請求,但拒絕提供服務(wù);
404,請求資源未存在;
500,服務(wù)器內(nèi)部錯誤;
http 1.1 與 http 2 的區(qū)別HTTP/2采用二進制格式而非文本格式
比起像HTTP/1.x這樣的文本協(xié)議,二進制協(xié)議解析起來更高效、“線上”更緊湊,更重要的是錯誤更少。
HTTP/2是完全多路復(fù)用的,而非有序并阻塞的——只需一個連接即可實現(xiàn)并行
HTTP/1.x 有個問題叫線端阻塞(head-of-line blocking), 它是指一個連接(connection)一次只提交一個請求的效率比較高, 多了就會變慢。 HTTP/1.1 試過用流水線(pipelining)來解決這個問題, 但是效果并不理想(數(shù)據(jù)量較大或者速度較慢的響應(yīng), 會阻礙排在他后面的請求). 此外, 由于網(wǎng)絡(luò)媒介(intermediary )和服務(wù)器不能很好的支持流水線, 導(dǎo)致部署起來困難重重。而多路傳輸(Multiplexing)能很好的解決這些問題, 因為它能同時處理多個消息的請求和響應(yīng); 甚至可以在傳輸過程中將一個消息跟另外一個摻雜在一起。所以客戶端只需要一個連接就能加載一個頁面。
使用報頭壓縮,HTTP/2降低了開銷
HTTP2通過gzip和compress壓縮頭部然后再發(fā)送,同時客戶端和服務(wù)器端同時維護一張頭信息表,所有字段都記錄在這張表中,這樣后面每次傳輸只需要傳輸表里面的索引Id就行,通過索引ID就可以知道表頭的值了
HTTP/2讓服務(wù)器可以將響應(yīng)主動“推送”到客戶端緩存中
HTTP2支持在客戶端未經(jīng)請求許可的情況下,主動向客戶端推送內(nèi)容
post和get請求的區(qū)別應(yīng)用:表單的method屬性設(shè)置post時發(fā)送的是post請求,其余都是get請求(沒有考慮AJAX);
傳參方式:get請求通過url地址發(fā)送請求參數(shù),post請求通過請求體發(fā)送請求參數(shù);
安全性:get請求直接通過url地址發(fā)送請求參數(shù),參數(shù)在地址欄可見,不太安全;post請求通過請求體發(fā)送請求參數(shù),參數(shù)在地址欄不可見,相對安全;
大小限制:get請求直接通過url地址發(fā)送請求參數(shù),url地址的長度限制在255字節(jié)內(nèi),所以get請求不能發(fā)送過多的參數(shù),post請求通過請求體發(fā)送參數(shù),長度沒有限制。
Get方法提交的數(shù)據(jù)大小長度并沒有限制,而是IE瀏覽器本身對地址欄URL長度(5.7備注:是瀏覽器對請求頭有限制,不能超過多少~~~)有最大長度限制:2048個字符。
GET 的本質(zhì)是「得」,而 POST 的本質(zhì)是「給」。GET 的內(nèi)容可以被瀏覽器緩存,而 POST 的數(shù)據(jù)不可以。
1.get產(chǎn)生一個TCP數(shù)據(jù)包,一個是請求頭,一個請求體的;post產(chǎn)生兩個TCP數(shù)據(jù)包;
2.在一次請求中,get一次性完成,post在部分瀏覽器(除了火狐)需要發(fā)送兩次信息,所以get比post更快,更有效率。
什么是跨域,解決跨域的方法及原理是什么?1.不同源就是跨域
2.同源策略是瀏覽器的一種安全策略
3.協(xié)議,域名,端口號完全相同就是同源,只要有一處不一樣就是跨域
4.特例: ajax在判斷域名的時候只能解析字符串,導(dǎo)致(localhost和127.0.0.1)在它看來也是跨域請求
5.解決跨域的方式通常用cors和jsonp
6.JSONP
1.JSONP是一種技巧,不是一門新的技術(shù)
2.利用scirpt標(biāo)簽的src屬性不受跨域的限制的特點
3.解決跨域:
1.瀏覽器端:動態(tài)生成script標(biāo)簽,提前定義好回調(diào)函數(shù),在合適的時機添加src屬性指定請求的地址。
2.服務(wù)器端:后臺接收到回調(diào)函數(shù),將數(shù)據(jù)包括在回調(diào)函數(shù)調(diào)用的句柄中,一起返回。
3.只支持get請求
function jsonp({url,params,callback}){
return new Promise((resolve,reject)=>{
// 創(chuàng)建srcipt
let script = document.createElement("script")
window[callback] = function(data){
resolve(data)
document.body.removeChild(script)
}
// 參數(shù)重新格式化
params = {...params,callback} // wd=b&callback=show
let arrs = []
for(let key in params){
arrs.push(`${key}=${params[key]}`)
}
// 后臺獲取數(shù)據(jù)的接口拼接上參數(shù)
script.src = `${url}");${arrs.join("&")}`
// srcipt插入
document.body.appendChild(script)
})
}
jsonp({
url: "http://localhost:3000/say",
params: { wd: "Iloveyou" },
callback: "show"
}).then(data=>{
console.log(databufen)
})
7.CORS
1.瀏覽器端什么也不用干;
2.服務(wù)器端設(shè)置響應(yīng)頭:Access-Control-Allow-Origin
3.cors是一門技術(shù),在本質(zhì)上讓ajax引擎允許跨域
4.get和post請求都支持
和第一次發(fā)送的option請求有關(guān);
跨域時,瀏覽器會攔截Ajax請求,并在http頭中加Origin。
瀏覽器問題 瀏覽器緩存前端優(yōu)化:瀏覽器緩存技術(shù)介紹
客戶端兩種存儲生命周期:
localStorage(本地存儲)生命周期是永久,這意味著除非用戶顯示在瀏覽器提供的UI上清除localStorage信息,否則這些信息將永遠(yuǎn)存在。
sessionStorage(會話存儲)生命周期為當(dāng)前窗口或標(biāo)簽頁,一旦窗口或標(biāo)簽頁被關(guān)閉了,那么所有通過sessionStorage存儲的數(shù)據(jù)也就被清空了。
作用域不同:不同瀏覽器無法共享localStorage或sessionStorage中的信息。
相同瀏覽器的不同頁面間可以共享相同的 localStorage(頁面屬于相同域名和協(xié)議,主機和端口);
不同頁面或標(biāo)簽頁間無法共享sessionStorage的信息。
localStorage只要在相同的協(xié)議、相同的主機名、相同的端口下,就能讀取/修改到同一份localStorage數(shù)據(jù)。
sessionStorage比localStorage更嚴(yán)苛一點,除了協(xié)議、主機名、端口外,還要求在同一窗口(也就是瀏覽器的標(biāo)簽頁)下。
存儲大小:localStorage和sessionStorage的存儲數(shù)據(jù)大小一般都是:5MB;
存儲位置:localStorage和sessionStorage都保存在客戶端,不與服務(wù)器進行交互通信。
存儲內(nèi)容類型:localStorage和sessionStorage只能存儲字符串類型,對于復(fù)雜的對象可以使用ECMAScript提供的JSON對象的stringify和parse來處理;
獲取方式:localStorage:window.localStorage;sessionStorage:window.sessionStorage;
應(yīng)用場景:localStoragese:常用于長期登錄(+判斷用戶是否已登錄),適合長期保存在本地的數(shù)據(jù);sessionStorage:敏感賬號一次性登錄。
應(yīng)該是和服務(wù)端有關(guān),
cookie每次的發(fā)送請求是被默認(rèn)帶上的,但是東西存在localstorage是沒有帶上的,需要寫進去;
至今沒有詳細(xì)的答案~~當(dāng)時的回答如下:
session是服務(wù)端的;它用來和客戶端的cookie進行匹配,說它一次會話保存的意思是sessionID每次會話都是一個新的,但是session一直是有的。
localStorage與sessionStorage作為新時代的產(chǎn)物,相比舊時代的cookie有其巨大的優(yōu)越性。優(yōu)越性有三:
其一在能存儲的數(shù)據(jù)量,cookie最大能存儲4kb的數(shù)據(jù),而localStorage與sessionStorage最大能存儲5Mb,目前各大瀏覽器支持的標(biāo)準(zhǔn)都是如此;
其二在功能上,cookie只能存儲String類型的數(shù)據(jù),以往要將用戶數(shù)據(jù)存儲在本地,需要將數(shù)據(jù)拼接成字符串,再存進cookie,取數(shù)據(jù)的時候同樣麻煩,先將整個cookie對象拿到(String對象),再按拼接的規(guī)則拆分,再拿需要的數(shù)據(jù),存取都很麻煩! localStorage與sessionStorage不僅支持傳統(tǒng)的String類型,還可以將json對象存儲進去,存取數(shù)據(jù)都方便不少,json的優(yōu)越性就不贅述,localStorage與sessionStorage無疑更現(xiàn)代化;
其三是cookie是不可或缺的,cookie的作用是與服務(wù)器進行交互,作為http規(guī)范的一部分而存在;而web storage僅僅是為了在本地‘存儲’而生;
其四在語義層面上,localStorage與sessionStorage語法更優(yōu)雅、簡便。
//cookie的操作
設(shè)置cookie: document.cookie = "key=value";
獲取cookie: document.cookie;
刪除cookie: document.cookie = "key=value;max-age=0";
設(shè)置max-age存儲期限: document.cookie = "key=value;max-age=1000"; // 1000秒
//web storage操作
保存數(shù)據(jù) setItem(key,value)
讀取數(shù)據(jù) getItem(key)
刪除單個數(shù)據(jù) removeItem(key)
清空全部數(shù)據(jù) clearItem()
獲取數(shù)據(jù)索引 key(index)
瀏覽器內(nèi)核?以及常見的瀏覽器兼容問題
瀏覽器內(nèi)核
Trident(IE內(nèi)核):以IE為代表,IE6、IE7、IE8(Trident 4.0)、IE9(Trident 5.0)、IE10(Trident 6.0)。
Gecko(Firefox內(nèi)核): Gecko 內(nèi)核的瀏覽器還是Firefox (火狐) 用戶最多,所以有時也會被稱為Firefox內(nèi)核。
webkit(Safari內(nèi)核,Chrome內(nèi)核原型,開源):它是蘋果公司自己的內(nèi)核,也是蘋果的Safari瀏覽器使用的內(nèi)核。 Apple Safari也會用。
presto(Opera前內(nèi)核) (已廢棄): Opera12.17及更早版本曾經(jīng)采用的內(nèi)核,現(xiàn)已停止開發(fā)并廢棄。Opera現(xiàn)已改用Google Chrome的Blink內(nèi)核。
不同瀏覽器的標(biāo)簽?zāi)J(rèn)的外補丁和內(nèi)補丁不同;
場景:隨便寫幾個標(biāo)簽,不加樣式控制的情況下,各自的margin 和padding差異較大。
解決方法:上來先消除默認(rèn)樣式*{margin:0;padding:0;};
塊屬性標(biāo)簽float后,又有橫行的margin情況下,在IE6顯示margin比設(shè)置的大(即雙倍邊距bug);
場景:常見癥狀是IE6中后面的一塊被頂?shù)较乱恍校?/p>
解決方法:在float的標(biāo)簽樣式控制中加入 display:inline;將其轉(zhuǎn)化為行內(nèi)屬性
IE6中 z-index失效
場景:元素的父級元素設(shè)置的z-index為1,那么其子級元素再設(shè)置z-index時會失效,其層級會繼承父級元素的設(shè)置,造成某些層級調(diào)整上的BUG;
原因:z-index起作用有個小小前提,就是元素的position屬性要 是relative,absolute或是fixed。
解決方案:1.position:relative改為position:absolute;2.去除浮動;3.浮動元素添加position屬性(如relative,absolute等)。
在寫a標(biāo)簽的樣式,寫的樣式?jīng)]有效果,其實只是寫的樣式被覆蓋了
正確的a標(biāo)簽順序應(yīng)該:link/ visited/hover/active
24位的png圖片,ie6中不兼容透明底兒
解決方式:使用png透明圖片唄,但是需要注意的是24位的PNG圖片在IE6是不支持的,解決方案有兩種:
使用8位的PNG圖片;
為IE6準(zhǔn)備一套特殊的圖片
事件監(jiān)聽的兼容;
IE不支持addEventListener;
解決:給IE使用attachEvent
var addHandler = function(el, type, handler, args) {
if (el.addEventListener) {
el.addEventListener(type, handler, false);
} else if (el.attachEvent) {
el.attachEvent("on" + type, handler);
} else {
el["on" + type] = handler;
}
};
var removeHandler = function(el, type, handler, args) {
if (el.removeEventListener) {
el.removeEventListener(type, handler, false);
} else if (el.detachEvent) {
el.detachEvent("on" + type, handler);
} else {
el["on" + type] = null;
}
};
event.target的兼容,引發(fā)事件的DOM元素。
IE6789不支持event.target;
解決方法:event.srcElement;
// 以下為兼容寫法 target = event.target || event.srcElement;
阻止系統(tǒng)默認(rèn)的兼容
IE6789不支持event.preventDefault;
// 以下為兼容寫法 event.preventDefault ");false);
阻止事件冒泡的兼容
IE6789不支持event.stopPropagation;
// 以下為兼容寫法 event.stopPropagation ");false);業(yè)務(wù)問題 360搜索圖片這種的瀑布流布局 圖片懶加載
高逼格方法:getBoundingClientRect()直接獲取元素到頂部的距離。
原因:在頁面中我們往往需要放上很多張圖,性能是個大問題,一次性加載所有圖片一般都會卡很久,因此,在需要預(yù)覽的時候再加載,是一個很好的解決方案。
思路:當(dāng)圖片出現(xiàn)在瀏覽器可視區(qū)域中時,再把圖片的url傳給它,也可以在這個時候創(chuàng)建圖片,而圖片被包裹在一個容器中,比如li或div,圖片的url放在其容器的自定義屬性data-src中;
過程:
給img標(biāo)簽的元素添加一個自定義屬性,比如data-src,而真正的src設(shè)置為空;
判斷圖片距離頁面頂端的距離小于瀏覽器滾動距離加上可視區(qū)域高度,即它出現(xiàn)在可視區(qū)域時就加載他;
// h = window.innerHeight——可視區(qū)域高度
// s = document.documentElement.scrollTop || document.body.scrollTop——滾動距離;
// getTop(imgs[i])通過getBoundingClientRect()獲取當(dāng)前圖片距離頂端的高度
if (h + s > getTop(imgs[i]) && !imgs[i].getAttribute("src"))
加載圖片imgs[i].src = imgs[i].getAttribute("data-src");
最后在把頁面滾動函數(shù)賦值給元素window.onload,在所有元素加載完以后再進行操作,這一步很重要!
window.onload = window.onscroll = function () {
// 懶加載的函數(shù)
lazyLoad(imgs);
}
項目中遇見的問題
問題一. 緩存:當(dāng)每次訪問的url相同,客戶端直接讀取本地緩存里面的內(nèi)容,即使后臺數(shù)據(jù)變化前臺也不會有變化;
解決方法:在?后面鏈接一個num=【隨機數(shù)Math.random()】或者num=【時間戳new Date().getTime()】,"1.php");
性能優(yōu)化
雪碧圖
減少dom操作:事件代理,fragment;
壓縮js和css,html;
主流框架問題 vue、react和angular區(qū)別借鑒angular的模板和數(shù)據(jù)綁定技術(shù);
借鑒react的組件化和虛擬DOM技術(shù);
體積下, 運行效率高, 編碼簡潔, PC/移動端開發(fā)都合適;
它本身只關(guān)注UI, 可以輕松引入vue插件和其它第三庫開發(fā)項目;
編碼題(字節(jié)跳動的視頻面試)第一題:定義一個Queue類,第一次調(diào)用可以隔1000秒輸出1,,第二次調(diào)用可以隔2000秒輸出2...最后可以調(diào)用run();
new Queue() .task(() => { console.log(1) }, 1000) .task(() => { console.log(2) }, 2000) .task(() => { console.log(3) }, 3000) .run()
第二題:定義一個函數(shù),求和函數(shù),可以無數(shù)次調(diào)用,并且在最后調(diào)用valueOf顯示最終求和結(jié)果;
sum(1)(2)(3)(4).valueOf()
第三題:第一步Promise+axios實現(xiàn)并發(fā)請求;寫完之后,要求再在此基礎(chǔ)上實現(xiàn)每次都并發(fā)5個請求(不會~~~);
// Promise+axios實現(xiàn)并發(fā)請求
// 實現(xiàn)并發(fā)5次請求
// 第一個答案
function getRequest(){
return axios.get(url)
};
function postrequest(){
return axios.post(url)
};
axios.all([getRequest(),postrequest()])
.then()
最近面試的一個整理情況,有些是面試中被問到的,有些是看文章時遇到感覺很有可能會問到的。有的有答案,有的還沒有答案,沒答案的原因有兩種的:一種是常見的問題,希望能閑下來之后詳細(xì)整理一下更高逼格的答案;另一種是目前還沒有解決,但是會在面試告一段落之后再研究研究給出答案,也特別歡迎大家在留言上給出這些題的答案或者思路。
有同學(xué)在評論中說了感覺題比較簡單,我想說,看到好多題的時候我也是這么感覺得,但是,可能后面就會往深層次問你了。
比如:new或者instanceof的實現(xiàn)原理?第二問就是:請手寫一個new或者instanceof;再比如,cookie和session區(qū)別,第二問就是:從服務(wù)端的角度來說一下cookie和session區(qū)別把?然后:為什么session只在一次回話有效,他是服務(wù)器的一個字段嗎?還是服務(wù)器的什么?再來,了解vue組件通信嗎?第二問就是:請說出這些組件通信的設(shè)計模式用了哪些?最后,用過npm和yarn嗎?第二問:你們是如何解決npm包的版本依賴的?package-lock的原理是什么?
我想說的是,文字能呈現(xiàn)的東西很簡單,但是想深究的話,深無底線~~~ 這些很大的目的是作個記錄,可以在面試上樓前再瞜一眼~~~ 工程師們在工作中一定要時刻保持可以離開的資本啊,知其然并且知其所以然!另外,面試前一定一定要準(zhǔn)備,至少一周啦~~~~
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/6735.html
摘要:一些知識點有哪些方法方法前端從入門菜鳥到實踐老司機所需要的資料與指南合集前端掘金前端從入門菜鳥到實踐老司機所需要的資料與指南合集歸屬于筆者的前端入門與最佳實踐。 工欲善其事必先利其器-前端實習(xí)簡歷篇 - 掘金 有幸認(rèn)識很多在大廠工作的學(xué)長,在春招正式開始前為我提供很多內(nèi)部推薦的機會,非常感謝他們對我的幫助。現(xiàn)在就要去北京了,對第一份正式的實習(xí)工作也充滿期待,也希望把自己遇到的一些問題和...
TCP/IP HTTP和HTTPS有何區(qū)別? httpbin 一個簡單的HTTP請求和響應(yīng)服務(wù)。 TCP的三次握手與四次揮手 通俗易懂版,詳細(xì)版本 MySQL CHAR和VARCHAR存取的差別 《高性能MySQL》筆記 - MySQL 鎖的基本類型 MySQL中的鎖之一:鎖的必要性及分類 MySQL中的鎖之二:行鎖、頁鎖、表鎖 MySQL Like與Regexp的區(qū)別 數(shù)據(jù)結(jié)構(gòu) 數(shù)...
TCP/IP HTTP和HTTPS有何區(qū)別? httpbin 一個簡單的HTTP請求和響應(yīng)服務(wù)。 TCP的三次握手與四次揮手 通俗易懂版,詳細(xì)版本 MySQL CHAR和VARCHAR存取的差別 《高性能MySQL》筆記 - MySQL 鎖的基本類型 MySQL中的鎖之一:鎖的必要性及分類 MySQL中的鎖之二:行鎖、頁鎖、表鎖 MySQL Like與Regexp的區(qū)別 數(shù)據(jù)結(jié)構(gòu) 數(shù)...
摘要:借著產(chǎn)品層面的功能和視覺升級,我們用對它進行了一次技術(shù)重構(gòu)。前端優(yōu)化是一個讓人技術(shù)提升的,希望你也能從這里學(xué)到一些東西。年最流行的前端鏈接我們每周會給多名前端開發(fā)者發(fā)送新聞郵件。 面試 -- 網(wǎng)絡(luò) HTTP 現(xiàn)在面試門檻越來越高,很多開發(fā)者對于網(wǎng)絡(luò)知識這塊了解的不是很多,遇到這些面試題會手足無措。本篇文章知識主要集中在 HTTP 這塊。文中知識來自 《圖解 HTTP》與維基百科,若有錯...
閱讀 3563·2021-11-22 15:11
閱讀 4643·2021-11-18 13:15
閱讀 2710·2019-08-29 14:08
閱讀 3583·2019-08-26 13:49
閱讀 3100·2019-08-26 12:17
閱讀 3294·2019-08-26 11:54
閱讀 3118·2019-08-26 10:58
閱讀 2038·2019-08-26 10:21