- 面試彙總一:2018大廠高級前端面試題彙總
- 高級面試:【半月刊】前端高頻面試題及答案彙總
css內容
響應式佈局
當前主流的三種預編譯器比較
- CSS預處理器用一種專門的編程語言,進行Web頁面樣式設計,而後再編譯成正常的CSS文件,以供項目使用;
- 讓你的CSS更加簡潔、適應性更強、可讀性更佳,更易於代碼的維護等諸多好處。
less,sass,stylus三者的區別
-
1.變量:javascript
- Sass聲明變量必須是『$』開頭,後面緊跟變量名和變量值,並且變量名和變量值須要使用冒號:分隔開。
- Less 聲明變量用『@』開頭,其他等同 Sass。
- Stylus 中聲明變量沒有任何限定,結尾的分號無關緊要,但變量名和變量值之間必需要有『等號』。
-
2.做用域:php
- Sass:三者最差,不存在全局變量的概念。也就是說在 Sass 中定義了相同名字的變量時你就要當心蛋疼了。
- Less:最近的一次更新的變量有效,而且會做用於所有的引用!
- Stylus:Sass 的處理方式和 Stylus 相同,變量值輸出時根據以前最近的一次定義計算,每次引用最近的定義有效;
-
3.嵌套:css
- 三種 css 預編譯器的「選擇器嵌套」在使用上來講沒有任何區別,甚至連引用父級選擇器的標記 & 也相同。
-
4.繼承:html
- Sass和Stylus的繼承很是像,能把一個選擇器的全部樣式繼承到另外一個選擇器上。使用『@extend』開始,後面接被繼承的選擇器。Stylus 的繼承方式來自 Sass,二者一模一樣。
- Less 則又「獨樹一幟」地用僞類來描述繼承關係;
-
5.導入@Import:前端
- Sass 中只能在使用 url() 表達式引入時進行變量插值:
$device: mobile; @import url(styles.#{$device}.css); 複製代碼
- Less 中能夠在字符串中進行插值:
@device: mobile; @import "styles.@{device}.css"; 複製代碼
- Stylus 中在這裏插值無論用,可是能夠利用其字符串拼接的功能實現:
device = "mobile" @import "styles." + device + ".css" 複製代碼
-
總結vue
- 1.Sass和Less語法嚴謹、Stylus相對自由。由於Less長得更像 css,因此它可能學習起來更容易。
- 2.Sass 和 Compass、Stylus 和 Nib 都是好基友。
- 3.Sass 和 Stylus 都具備類語言的邏輯方式處理:條件、循環等,而 Less 須要經過When等關鍵詞模擬這些功能,這方面 Less 比不上 Sass 和 Stylus。
- 4.Less 在豐富性以及特點上都不及 Sass 和 Stylus,若不是由於 Bootstrap 引入了 Less,可能它不會像如今這樣被普遍應用(我的愚見)。
link與@import區別與選擇
<style type="text/css"> @import url(CSS文件路徑地址); </style> <link href="CSSurl路徑" rel="stylesheet" type="text/css" / 複製代碼
- link功能較多,能夠定義 RSS,定義 Rel 等做用,而@import只能用於加載 css;
- 當解析到link時,頁面會同步加載所引的 css,而@import所引用的 css 會等到頁面加載完才被加載;
- @import須要 IE5 以上才能使用;
- link可使用 js 動態引入,@import不行;
居中佈局
css3的高級特性舉例
h5新增了哪些內容或者API,使用過哪些?
1像素邊框問題
什麼是BFC
BFC是什麼
- BFC 英文解釋: block formatting context。中文意思:塊級格式化上下文;
- formatting context 意思是:頁面中一個渲染區域,有本身的一套渲染規則,決定其子元素如何定位,以及和其餘兄弟元素的關係和做用。
- BEC有以下特性
- 內部的box會在垂直方向,從頂部開始一個接一個地放置;
- box垂直方向的距離由margin決定。屬於同一個BFC的兩個相鄰的box的margin會發生摺疊;
- 每個元素的margin box的左遍,與包含塊border box的左邊相接觸。即便浮動元素也是如此;
- BFC區域不會與float box疊加;
- 計算 BFC 的高度時,浮動子元素也參與計算;
- 文字層不會被浮動層覆蓋,環繞於周圍
產生BFC 做用的css 屬性
- float 除了none之外的值;
- overflow 除了visible 之外的值(hidden,auto,scroll );
- display (table-cell,table-caption,inline-block, flex, inline-flex);
- position值爲(absolute,fixed) 這些屬性值得元素都會自動建立 BFC;
BFC做用
- BFC 最大的一個做用就是:在頁面上有一個獨立隔離容器,容器內的元素 和 容器 外的元素佈局不會相互影響。
- 解決上外邊距重疊;重疊的兩個box都開啓bfc;
- 解決浮動引發高度塌陷;容器盒子開啓bfc;
- 解決文字環繞圖片;左邊圖片div,右邊文本容器p,將p容器開啓bfc;
js基礎
for...in和for...of區別
- for...in
- 1.循環出來的是index索引,是字符串型的數字;
- 2.遍歷順序有可能不是按照實際數組的內部順序;
- 3.使用for in會遍歷數組全部的可枚舉屬性,包括原型上的以及數組自定義的屬性;
- 因此for in更適合遍歷對象,不要使用for in遍歷數組。
- 推薦在循環對象屬性的時候,使用for...in,在遍歷數組的時候的時候使用for...of;
- for...in循環出的是key,for...of循環出的是value;
- 注意,for...of是ES6新引入的特性。修復了ES5引入的for...in的不足;
- for...of不能循環普通的對象,須要經過和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 靜態',則只是在dom中插入了一行字符串,就更不會管字符串裏引入的js了,因此不能用這個方法插入script!!!
- 2.各個js文件的加載時機(script標籤插入文檔的時機順序)
- 好比: 1.js 依賴 2.js,2.js 依賴 3.js;實際的加載順序是爲 1.js,2.js,3.js
- 注意: 而實際模塊運行的順序,纔是 3.js,2.js,1.js。因此,文件的加載、加載後文件的運行、模塊的運行,這是 3 個東西啊,別混了。
- 3.文件模塊的執行時機
// 1.js 中的代碼 require([], functionA() { // 主要邏輯代碼 }) 複製代碼
- 文件的加載:將
<script src='1.js'>
節點插入dom中,以後,下載 1.js 文件; - 加載後文件的運行:1.js 文件加載完後,執行 1.js 中的代碼,即執行 require() 函數!!!
- 模塊的運行: require回調函數,上方的,主要邏輯代碼,所在的函數,functionA,的運行!!!
- 文件加載/文件運行 順序: 1.js , 2.js , 3.js;
- 模塊運行 順序:3.js , 2.js , 1.js;
- 文件的加載:將
webpack對比requirejs
- webpack在管理模塊的時候不須要再封裝一層像requireJS以下的東西
define(['jquery'], function(jquery){}) 複製代碼
- 它實現了前端代碼模塊化,提升了代碼的複用性,從而提供公共模塊的緩存功能。
- webpack經過打包,不一樣頁面單獨加載本身的模塊的javascript 和 common javascript,而requireJS將全部的javascript文件打包成一個文件,使得一個站點中多個頁面之間公用的JS模塊沒法緩存。
- Webpack 引入了切分點(split point)與代碼塊(Chunk),切分點定義了全部依賴的模塊,合起來就是一個代碼塊,從而實現一個頁面引用一個代碼塊。
主流框架Vue
vue2中的diff算法是怎樣實現的?
- 參考:讓虛擬DOM和DOM-diff再也不成爲你的絆腳石
- 當數據發生改變時,set方法會讓調用Dep.notify通知全部訂閱者Watcher,訂閱者就會調用patch給真實的DOM打補丁,更新相應的視圖。
diff流程
- patch函數接收兩個參數oldVnode和Vnode分別表明新的節點和以前的舊節點
- 判斷兩節點是否值得比較,值得比較則執行patchVnode;
- 不值得比較則用Vnode替換oldVnode;
- patchVnode:當咱們肯定兩個節點值得比較以後咱們會對兩個節點指定patchVnode方法;
- 找到對應的真實dom,稱爲el;
- 判斷Vnode和oldVnode是否指向同一個對象,若是是,那麼直接return;
- 若是他們都有文本節點而且不相等,那麼將el的文本節點設置爲Vnode的文本節點;
- 若是oldVnode有子節點而Vnode沒有,則刪除el的子節點;
- 若是oldVnode沒有子節點而Vnode有,則將Vnode的子節點真實化以後添加到el;
- 若是二者都有子節點,則執行updateChildren函數比較子節點,這一步很重要;
- updateChildren函數圖解
- 如今分別對oldS、oldE、S、E兩兩作sameVnode比較,有四種比較方式,當其中兩個能匹配上那麼真實dom中的相應節點會移到Vnode相應的位置,這句話有點繞,打個比方:
- 若是是oldS和E匹配上了,那麼真實dom中的第一個節點會移到最後;
- 若是是oldE和S匹配上了,那麼真實dom中的最後一個節點會移到最前,匹配上的兩個指針向中間移動;
- 若是四種匹配沒有一對是成功的,那麼遍歷oldChild,S挨個和他們匹配,匹配成功就在真實dom中將成功的節點移到最前面,若是依舊沒有成功的,那麼將S對應的節點插入到dom中對應的oldS位置,oldS和S指針向中間移動。
vue雙向數據綁定
- vue.js 是採用數據劫持結合發佈者-訂閱者模式的方式,經過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變動的雙向綁定效果。
vue生命週期的執行過程
- 首先建立一個vue實例,Vue();
- 在建立Vue實例的時候,執行了init(),在init過程當中首先調用了beforeCreate。
- Created以前,對data內的數據進行了數據監聽,而且初始化了Vue內部事件。具體以下:
- 完成了數據觀測;
- 完成了屬性和方法的運算;
- 完成了watch/event事件的回調;
- 可是此時還未掛載dom上,$el屬性是不可見的;
- beforeMount以前,完成了模板的編譯。把data對象裏面的數據和vue的語法寫的模板編譯成了html,可是此時尚未將編譯出來的html渲染到頁面;
- 一、在實例內部有template屬性的時候,直接用內部的,而後調用render函數去渲染。
- 二、在實例內部沒有找到template,就調用外部的html(「el」option(選項))。實例內部的template屬性比外部的優先級高。 render函數 > template屬性 > 外部html;
- 三、要是前二者都不知足,那麼就拋出錯誤。
- Mounted以前執行了render函數,將渲染出來的內容掛載到了DOM節點上。mounted是將html掛載到頁面完成後觸發的鉤子函數;當mounted執行完畢,整個實例算是走完了流程;在整個實例過程當中,mounted僅執行一次;
- beforeUpdate:數據發生變化時,會調用beforeUpdate,而後經歷virtual DOM,最後updated更新完成;
- beforeDestory是實例銷燬前鉤子函數,銷燬了全部觀察者,子組件以及事件監聽;
- destoryed實例銷燬執行的鉤子函數;
總結
- beforeCreate:初始化了部分參數,若是有相同的參數,作了參數合併,執行 beforeCreate;el和數據對象都爲undefined,還未初始化;
- created :初始化了 Inject 、Provide 、 props 、methods 、data 、computed 和 watch,執行 created ;data有了,el尚未;
- beforeMount :檢查是否存在 el 屬性,存在的話進行渲染 dom 操做,執行 beforeMount;$el和data都初始化了,可是dom仍是虛擬節點,dom中對應的數據尚未替換;
- mounted :實例化 Watcher ,渲染 dom,執行 mounted ;vue實例掛載完成,dom中對應的數據成功渲染;
- beforeUpdate :在渲染 dom 後,執行了 mounted 鉤子後,在數據更新的時候,執行 beforeUpdate ;
- updated :檢查當前的 watcher 列表中,是否存在當前要更新數據的 watcher ,若是存在就執行 updated ;
- beforeDestroy :檢查是否已經被卸載,若是已經被卸載,就直接 return 出去,不然執行 beforeDestroy ;
- destroyed :把全部有關本身痕跡的地方,都給刪除掉;
Vue.js的template編譯
- 參考:Vue2 原理淺談
const ast = parse(template.trim(), options) // 構建抽象語法樹
optimize(ast, options) // 優化
const code = generate(ast, options) // 生成代碼
return { ast, render: code.render, staticRenderFns: code.staticRenderFns } 複製代碼
- 能夠分紅三部分
- 將模板轉化爲抽象語法樹;
- 優化抽象語法樹;
- 根據抽象語法樹生成代碼;
- 具體作了什麼
- 第一部分其實就是各類正則了,對左右開閉標籤的匹配以及屬性的收集,經過棧的形式,不斷出棧入棧去匹配以及更換父節點,最後生成一個對象,包含children,children又包含children的對象;
- 第二部分則是以第一部分爲基礎,根據節點類型找出一些靜態的節點並標記;
- 第三部分就是生成render函數代碼了
- 簡言之,就是先轉化成AST樹,再獲得的render函數返回VNode(Vue的虛擬DOM節點);
- 回答:
- 首先,經過compile編譯器把template編譯成AST語法樹(abstract syntax tree 即 源代碼的抽象語法結構的樹狀表現形式),compile是createCompiler的返回值,createCompiler是用以建立編譯器的。另外compile還負責合併option。
- 而後,AST會通過generate(將AST語法樹轉化成render funtion字符串的過程)獲得render函數,render的返回值是VNode,VNode是Vue的虛擬DOM節點,裏面有(標籤名、子節點、文本等等);
數據到視圖的總體流程
- 在組件級別,vue會執行一個new Watcher;
- new Watcher首先會有一個求值的操做,它的求值就是執行一個函數,這個函數會執行render,其中可能會有編譯模板成render函數的操做,而後生成vnode(virtual dom),再將virtual dom應用到視圖中;
- 其中將virtual dom應用到視圖中(這裏涉及到diff後文會講),必定會對其中的表達式求值(好比{{message}},咱們確定會取到它的值再去渲染的),這裏會觸發到相應的getter操做完成依賴的收集;
- 當數據變化的時候,就會notify到這個組件級別的Watcher,而後它還會去求值,從而從新收集依賴,而且從新渲染視圖;
vue組件間的七種交互
- 1.props和$emit
- 父組件向子組件傳遞數據是經過prop傳遞的,子組件傳遞數據給父組件是經過$emit觸發事件來作到的。
- 2.特性綁定$attrs和$listeners
- 若是父組件A下面有子組件B,組件B下面有組件C,這時若是組件A想傳遞數據給組件C怎麼辦呢? 若是繼續用上面的方法,會變得很是複雜,不利於維護;Vue 2.4開始提供了$attrs和$listeners來解決這個問題,可以讓組件A之間傳遞消息給組件C。
- 3.中央事件總線 Events Bus
- 新建一個Vue事件bus對象,而後經過bus.$emit觸發事件,bus.$on監聽觸發的事件。
- 4.依賴注入:provide和inject
- 父組件中經過provider來提供變量,而後在子組件中經過inject來注入變量。
- 不論子組件有多深,只要調用了inject那麼就能夠注入provider中的數據。而不是侷限於只能從當前父組件的prop屬性來獲取數據,只要在父組件的生命週期內,子組件均可以調用。
// 父組件 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
vuex原理
- 參考:深刻vuex原理(上)
- 參考:Vuex 源碼解析
- vuex的state是藉助vue的響應式data實現的。
// 使用 this.$store.getters.xxx 獲取 xxx 屬性時,其實是獲取的store._vm.data.$$state 對象上的同名屬性 get state () { return this._vm._data.$$state } // 處理state 和 getter的核心函數resetStoreVM(this, state) store._vm = new Vue({ data: { $$state: state } }) // 因爲vue的data是響應式的,因此,$$state也是響應式的,那麼當咱們 在一個組件實例中 對state.xxx進行 更新時,基於vue的data的響應式機制,全部相關組件的state.xxx的值都會自動更新,UI天然也會自動更新 複製代碼
- getter是藉助vue的計算屬性computed特性實現的。
// 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 }) }) 複製代碼
- 其設計思想與vue中央事件總線一模一樣。中央事件總線的實現,簡單講就是新建了一個vue對象,藉助vue對象的特性(emit 與on) 做爲其餘組件的通訊橋樑,實現組件間的通訊 以及數據共享!
Vue-router 中hash模式和history模式的區別
- hash模式url裏面永遠帶着#號,咱們在開發當中默認使用這個模式。那麼何時要用history模式呢?若是用戶考慮url的規範那麼就須要使用history模式,由於history模式沒有#號,是個正常的url適合推廣宣傳。
- 固然其功能也有區別,好比咱們在開發app的時候有分享頁面,那麼這個分享出去的頁面就是用vue或是react作的,我們把這個頁面分享到第三方的app裏,有的app裏面url是不容許帶有#號的,因此要將#號去除那麼就要使用history模式,可是使用history模式還有一個問題就是,在訪問二級頁面的時候,作刷新操做,會出現404錯誤,那麼就須要和後端人配合讓他配置一下apache或是nginx的url重定向,重定向到你的首頁路由上就ok啦。
- 路由的哈希模式實際上是利用了window能夠監聽onhashchange事件,也就是說你的url中的哈希值(#後面的值)若是有變化,前端是能夠作到監聽並作一些響應(搞點事情),這麼一來,即便前端並無發起http請求他也可以找到對應頁面的代碼塊進行按需加載。
- pushState與replaceState,這兩個神器的做用就是能夠將url替換而且不刷新頁面,比如掛羊頭賣狗肉,http並無去請求服務器該路徑下的資源,一旦刷新就會暴露這個實際不存在的「羊頭」,顯示404。這就須要服務器端作點手腳,將不存在的路徑請求重定向到入口文件(index.html)。
自定義組件
- 參考:Vue——關於自定義組件
- secondDemoComponent.js
- index.js:index.js文件幫咱們把全部自定義的組件都經過Vue.component註冊了,最後export一個包含install方法的對象給Vue.use()使用。
- 統一導入
import global from './components/global/index.js' Vue.use(global) 複製代碼
計算機網絡
http 狀態碼的分類?什麼是無狀態?
- http無狀態
- 服務器中沒有保存客戶端的狀態,客戶端必須每次帶上本身的狀態去請求服務器;
- 每次的請求都是獨立的,<它的執行狀況和結果>與<前面的請求>和<以後的請求>是無直接關係的
- 狀態碼分類
- 1XX指示信息,表示信息已接收,繼續處理;
- 2XX成功-表示請求已被成功接收;
- 3XX重定向,表示要完成請求進行更進一步操做;
- 4XX客戶端錯誤,請求依法錯誤或請求沒法實現;
- 5XX服務器端錯誤,服務器未能實現合法請求;
- 舉例:
- 200,請求成功;
- 302:重定向;
- 304:上次請求後頁面未修改;
- 400:客戶端請求語法錯誤;
- 401:權限問題;
- 403,服務器接受請求,但拒絕提供服務;
- 404,請求資源未存在;
- 500,服務器內部錯誤;
http 1.1 與 http 2 的區別
- HTTP/2採用二進制格式而非文本格式
- 比起像HTTP/1.x這樣的文本協議,二進制協議解析起來更高效、「線上」更緊湊,更重要的是錯誤更少。
- HTTP/2是徹底多路複用的,而非有序並阻塞的——只需一個鏈接便可實現並行
- HTTP/1.x 有個問題叫線端阻塞(head-of-line blocking), 它是指一個鏈接(connection)一次只提交一個請求的效率比較高, 多了就會變慢。 HTTP/1.1 試過用流水線(pipelining)來解決這個問題, 可是效果並不理想(數據量較大或者速度較慢的響應, 會阻礙排在他後面的請求). 此外, 因爲網絡媒介(intermediary )和服務器不能很好的支持流水線, 致使部署起來困難重重。而多路傳輸(Multiplexing)能很好的解決這些問題, 由於它能同時處理多個消息的請求和響應; 甚至能夠在傳輸過程當中將一個消息跟另一個摻雜在一塊兒。因此客戶端只須要一個鏈接就能加載一個頁面。
- 使用報頭壓縮,HTTP/2下降了開銷
- HTTP/2讓服務器能夠將響應主動「推送」到客戶端緩存中
post和get請求的區別
基本區別
- 應用:表單的method屬性設置post時發送的是post請求,其他都是get請求(沒有考慮AJAX);
- 傳參方式:get請求經過url地址發送請求參數,post請求經過請求體發送請求參數;
- 安全性:get請求直接經過url地址發送請求參數,參數在地址欄可見,不太安全;post請求經過請求體發送請求參數,參數在地址欄不可見,相對安全;
- 大小限制:get請求直接經過url地址發送請求參數,url地址的長度限制在255字節內,因此get請求不能發送過多的參數,post請求經過請求體發送參數,長度沒有限制。
- Get方法提交的數據大小長度並無限制,而是IE瀏覽器自己對地址欄URL長度有最大長度限制:2048個字符。
高級區別
- GET 的本質是「得」,而 POST 的本質是「給」。GET 的內容能夠被瀏覽器緩存,而 POST 的數據不能夠。
- 1.get產生一個TCP數據包;post產生兩個TCP數據包;
- 2.在一次請求中,get一次性完成,post在部分瀏覽器(除了火狐)須要發送兩次信息,因此get比post更快,更有效率。
什麼是跨域,解決跨域的方法及原理是什麼?
- 1.不一樣源就是跨域
- 2.同源策略是瀏覽器的一種安全策略
- 3.協議,域名,端口號徹底相同就是同源,只要有一處不同就是跨域
- 4.特例: ajax在判斷域名的時候只能解析字符串,致使(localhost和127.0.0.1)在它看來也是跨域請求
- 5.解決跨域的方式一般用cors和jsonp
- 6.JSONP
- 1.JSONP是一種技巧,不是一門新的技術
- 2.利用scirpt標籤的src屬性不受跨域的限制的特色
- 3.解決跨域:
- 1.瀏覽器端:動態生成script標籤,提早定義好回調函數,在合適的時機添加src屬性指定請求的地址。
- 2.服務器端:後臺接收到回調函數,將數據包括在回調函數調用的句柄中,一塊兒返回。
- 3.只支持get請求
function jsonp({url,params,callback}){ return new Promise((resolve,reject)=>{ // 建立srcipt let script = document.createElement("script") window[callback] = function(data){ resolve(data) document.body.removeChild(script) } // 參數從新格式化 params = {...params,callback} // wd=b&callback=show let arrs = [] for(let key in params){ arrs.push(`${key}=${params[key]}`) } // 後臺獲取數據的接口拼接上參數 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.服務器端設置響應頭:Access-Control-Allow-Origin
- 3.cors是一門技術,在本質上讓ajax引擎容許跨域
- 4.get和post請求都支持
瀏覽器問題
瀏覽器緩存
客戶端兩種存儲
sessionStorage用法和localStorage區別
- 徹底一致,差異只在有效期:
- sessionStorage在用戶結束會話(即關閉瀏覽器或退出帳戶時失效);
- localStorage無失效期,用戶在清理瀏覽器緩存的時候會被清除。
Cookie存儲和Web Storage存儲區別
- localStorage與sessionStorage做爲新時代的產物,相比舊時代的cookie有其巨大的優越性。優越性有三:
- 其一在能存儲的數據量,cookie最大能存儲4kb的數據,而localStorage與sessionStorage最大能存儲5Mb,目前各大瀏覽器支持的標準都是如此;
- 其二在功能上,cookie只能存儲String類型的數據,以往要將用戶數據存儲在本地,須要將數據拼接成字符串,再存進cookie,取數據的時候一樣麻煩,先將整個cookie對象拿到(String對象),再按拼接的規則拆分,再拿須要的數據,存取都很麻煩! localStorage與sessionStorage不只支持傳統的String類型,還能夠將json對象存儲進去,存取數據都方便很多,json的優越性就不贅述,localStorage與sessionStorage無疑更現代化;
- 其三是cookie是不可或缺的,cookie的做用是與服務器進行交互,做爲http規範的一部分而存在;而web storage僅僅是爲了在本地‘存儲’而生;
- 其四在語義層面上,localStorage與sessionStorage語法更優雅、簡便。
//cookie的操做
設置cookie: document.cookie = 'key=value'; 獲取cookie: document.cookie; 刪除cookie: document.cookie = "key=value;max-age=0"; 設置max-age存儲期限: document.cookie = "key=value;max-age=1000"; // 1000秒 //web storage操做 保存數據 setItem(key,value) 讀取數據 getItem(key) 刪除單個數據 removeItem(key) 清空所有數據 clearItem() 獲取數據索引 key(index) 複製代碼
瀏覽器內核?以及常見的瀏覽器兼容問題
- 瀏覽器內核
- Trident(IE內核):以IE爲表明,IE六、IE七、IE8(Trident 4.0)、IE9(Trident 5.0)、IE10(Trident 6.0)。
- Gecko(Firefox內核): Gecko 內核的瀏覽器仍是Firefox (火狐) 用戶最多,因此有時也會被稱爲Firefox內核。
- webkit(Safari內核,Chrome內核原型,開源):它是蘋果公司本身的內核,也是蘋果的Safari瀏覽器使用的內核。 Apple Safari也會用。
- presto(Opera前內核) (已廢棄): Opera12.17及更早版本曾經採用的內核,現已中止開發並廢棄。Opera現已改用Google Chrome的Blink內核。
常見的瀏覽器兼容問題
HTML中的兼容問題
- 不一樣瀏覽器的標籤默認的外補丁和內補丁不一樣;
- 場景:隨便寫幾個標籤,不加樣式控制的狀況下,各自的margin 和padding差別較大。
- 解決方法:上來先消除默認樣式*{margin:0;padding:0;};
- 塊屬性標籤float後,又有橫行的margin狀況下,在IE6顯示margin比設置的大(即雙倍邊距bug);
- 場景:常見症狀是IE6中後面的一塊被頂到下一行;
- 解決方法:在float的標籤樣式控制中加入 display:inline;將其轉化爲行內屬性
- IE6中 z-index失效
- 場景:元素的父級元素設置的z-index爲1,那麼其子級元素再設置z-index時會失效,其層級會繼承父級元素的設置,形成某些層級調整上的BUG;
- 緣由:z-index起做用有個小小前提,就是元素的position屬性要 是relative,absolute或是fixed。
- 解決方案:1.position:relative改成position:absolute;2.去除浮動;3.浮動元素添加position屬性(如relative,absolute等)。
- 在寫a標籤的樣式,寫的樣式沒有效果,其實只是寫的樣式被覆蓋了
- 正確的a標籤順序應該:link/ visited/hover/active
- 24位的png圖片,ie6中不兼容透明底兒
- 解決方式:使用png透明圖片唄,可是須要注意的是24位的PNG圖片在IE6是不支持的,解決方案有兩種:
- 使用8位的PNG圖片;
- 爲IE6準備一套特殊的圖片
- 解決方式:使用png透明圖片唄,可是須要注意的是24位的PNG圖片在IE6是不支持的,解決方案有兩種:
js在不一樣瀏覽器中的兼容問題
- 事件監聽的兼容;
- 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的兼容,引起事件的DOM元素。
- IE6789不支持event.target;
- 解決方法:event.srcElement;
// 如下爲兼容寫法
target = event.target || event.srcElement;
複製代碼
- 阻止系統默認的兼容
- IE6789不支持event.preventDefault;
// 如下爲兼容寫法
event.preventDefault ? event.preventDefault() : (event.returnValue = false); 複製代碼
- 阻止事件冒泡的兼容
- IE6789不支持event.stopPropagation;
// 如下爲兼容寫法
event.stopPropagation ? event.stopPropagation() : (event.cancelBubble = false); 複製代碼
業務問題
360搜索圖片這種的瀑布流佈局
圖片懶加載
- 高逼格方法:getBoundingClientRect()直接獲取元素到頂部的距離。
- 緣由:在頁面中咱們每每須要放上不少張圖,性能是個大問題,一次性加載全部圖片通常都會卡好久,所以,在須要預覽的時候再加載,是一個很好的解決方案。
- 思路:當圖片出如今瀏覽器可視區域中時,再把圖片的url傳給它,也能夠在這個時候建立圖片,而圖片被包裹在一個容器中,好比li或div,圖片的url放在其容器的自定義屬性data-src中;
- 過程:
- 給img標籤的元素添加一個自定義屬性,好比data-src,而真正的src設置爲空;
- 判斷圖片距離頁面頂端的距離小於瀏覽器滾動距離加上可視區域高度,即它出如今可視區域時就加載他;
// h = window.innerHeight——可視區域高度 // s = document.documentElement.scrollTop || document.body.scrollTop——滾動距離; // getTop(imgs[i])經過getBoundingClientRect()獲取當前圖片距離頂端的高度 if (h + s > getTop(imgs[i]) && !imgs[i].getAttribute('src')) 複製代碼
- 加載圖片
imgs[i].src = imgs[i].getAttribute('data-src');
- 最後在把頁面滾動函數賦值給元素window.onload,在全部元素加載完之後再進行操做,這一步很重要!
window.onload = window.onscroll = function () { // 懶加載的函數 lazyLoad(imgs); } 複製代碼
項目中碰見的問題
ajax中使用get的問題
- 問題一. 緩存:當每次訪問的url相同,客戶端直接讀取本地緩存裏面的內容,即便後臺數據變化前臺也不會有變化;
- 解決方法:在?後面連接一個num=【隨機數Math.random()】或者num=【時間戳new Date().getTime()】,'1.php?username="May"&'+num(這裏沒有變量名,避免和後臺參數衝突)
性能優化
- 雪碧圖
- 減小dom操做:事件代理,fragment;
- 壓縮js和css,html;
主流框架問題
vue、react和angular區別
- 借鑑angular的模板和數據綁定技術;
- 借鑑react的組件化和虛擬DOM技術;
- 體積下, 運行效率高, 編碼簡潔, PC/移動端開發都合適;
- 它自己只關注UI, 能夠輕鬆引入vue插件和其它第三庫開發項目;