z-index只做用於被定位了的元素上,還有就是子元素的z-index會被父的值覆蓋。css
有 content-box
和 border-box
兩個,前者是默認值,指設定的width只包含content的寬,不包含border和padding,後者都包括。
這個問的還挺多的有的是給html+css代碼叫算大小的,有的是口頭表達的。html
flex是佈局的大方向,問的頻率也挺高的,要麼是問垂直居中的時候引出來,要麼是叫你實現一個簡單佈局而後引出來,不清楚的能夠看一哈阮一峯老師的教程(傳送門)vue
這種優化的手段是說不完的,我也僅表達一下本身現階段的一些理解。
一、提升加載速度:好比最最最基礎的壓縮文件大小,還有能夠經過內聯css來使瀏覽器開始頁面渲染的時間提早,文件大小須要控制在14.6kb(由於初始擁塞窗口存在限制),還有就是chrome自帶的 coverage
標籤,能夠分析js和css文件的使用率,而後咱們去進一步作懶加載或者移除無用代碼。
二、提升選擇器的性能,好比不要嵌套太多複雜的層級,選擇器從右到左匹配。
三、提升渲染速度,這個我也不太懂,只是最近看canvas
的時候,mdn裏關於canvas優化提到CSS transforms使用GPU,所以速度更快,找到了一篇文章介紹使用transform與否的對比演示,也解釋了爲何會更快,感受不錯,文章傳送門。面試
map的回調裏return啥就是啥,filter的回調裏返回的布爾值決定當前項是否會存到新的數組裏。
我其實沒懂這個是想問啥,由於筆試遇到這道題的時候其餘題都還挺有意思的,有點把我整懵了。vue-router
單獨實現一個sleep很簡單chrome
function sleep(time) { return new Promise((res) => { setTimeout(res, time) }) }
可是面試過程當中,碰到了一道筆試題很是有意思,大概是這樣:canvas
//實現 Person('Jack').eat('lunch').sleep(2).eat('dinner').firstSleep(5) //輸出 // 等待5s firstSleep 5s Hi, my name is Jack Eat lunch // 等待2s sleep 2s Eat dinner
我一開始的思路是使用setTimeout
和Promise
的macro/micro
特徵,即firstSleep使用Promise,其餘所有使用setTimeout,在這樣的思路下,sleep和eat大概是這樣的數組
sleep(time) { this.sleepTime += time setTimeout(() => { log('balabala') }, this.sleepTime) return this } eat(food) { setTimeout(() => { log('balabala') }, this.sleepTime) return this }
那後面的firstSleep就根本無法寫了,前面時常爲this.sleepTime沒有操做空間了。
產生這樣的錯誤思路的緣由是對上面說的sleep
函數或者是瀏覽器的事件循環理解不透徹。
這裏咱們須要的是一個雙向隊列(好像是叫這個 吧),即正常狀況的鏈式調用中往隊列中push
,遇到firstSleep就unshift
,在Person的構造函數中定義一個setTimeout來開始執行這個雙向隊列中的函數(就像串聯多個異步任務時用於鏈接每一個任務的next()
)。
代碼:瀏覽器
const log = console.log const deque = [] function next() { const fn = deque.shift() fn && fn() } function Person(name) { deque.push(() => { log(`Hi, my name is ${name}`) next() }) setTimeout(() => { next() }, 0) return this } Person.prototype = { eat(food) { deque.push(() => { log(`Eat ${food}`) next() }) return this }, sleep(time) { deque.push(() => { setTimeout(() => { log(`sleep ${time}s`) next() }, time * 1000) }) return this }, sleepFirst(time) { deque.unshift(() => { setTimeout(() => { log(`sleepFirst ${time}s`) next() }, time * 1000) }) return this } } new Person('Jack').eat('lunch').sleep(2).eat('dinner').sleepFirst(2)
再觀察到題目中沒有new關鍵字,寫個函數包一下就好dom
function _Person(name) { return new Person(name) }
// 實現三數相加的add函數 add(1,2,3) // 6 add(1,2)(3) // 6 add(1)(2)(3) // 6
實現一個函數柯里化不難,主要經過判斷當前參數數量與目標函數參數數量,不夠的話返回函數,夠了的話返回結果,兩種實現手段以下:
const sum3 = (x, y, z) => x + y + z const add = currying(sum3) // 方法1 function currying1(fn) { /* *@param{ Number } n 目標函數指望剩餘參數數量 *@param{ Array } args 已有參數數組 */ function next(n, args) { return (...xs) => { if(n <= xs.length) { return fn(...args, ...xs) } return next(n - xs.length, [...args, ...xs]) } } return next(fn.length, []) } // 方法2 function currying2(fn) { return (...a) => { if(a.length >= fn.length) { return fn(...a) } return currying2(fn.bind(null, ...a)) } }
思路都同樣的,方法1中合併參數的[...args, ...xs]
操做其實就是bind函數最後return裏的合併arguments。
柯里化的部分就完了,可是若是仍是這個add,想實現的是不知道多少個參數相加呢。
與柯里化相同的是在函數內部保存已經收集的參數,不一樣的是柯里化能夠經過判斷參數數量來決定返回值,新需求須要重寫返回函數的toString
來輸出最後執行的返回值。
JavaScript calls thetoString
method automatically when aFunction
is to be represented as a text value, e.g. when a function is concatenated with a string.
代碼:
function add() { var args = Array.prototype.slice.call(arguments) var adder = function() { args.push(...arguments) return adder } adder.toString = function() { return args.reduce((a, b) => a + b) } return adder } add(1, 2, 3)(4)(5) // f 15 add(1, 2, 3)(4)(5) + 0 // 15
看起來是成了,可是若是不轉換類型的話,輸出的結果前有個 f
,這讓我很疑惑,找了不少資料也沒有結果,若是你知道的話,還請不吝賜教。
父beforeCreate 父created 父beforeMount
子beforeCreate 子created 子beforeMount 子mounted
父mounted
子組件是先於父組件mounted的。
這個題也挺有意思的,是在vue雙向綁定原理以後問的,有意思不是在於多難或者多偏,而是能感到面試管真的在考驗你的能力,不是看你會背多少面試題。題目是這樣的
// ... data() { return { title: 'abc' } } methods: { change: function() { this.title = '1' this.title = '2' this.title = '3' // 調用change以後dom更新幾回 } } // ...
猜也能猜到確定是更新一次。可是我想到別的地方緣由說錯了淦。具體緣由是Vue把更新都借用本身的 nextTick
去異步更新。
下面這段若是不熟的話建議配和Vue(2.6.10)源碼一塊兒食用。
調用 change
以後,順序同步執行三次 defineProperty
裏的 set
, 也就是順序同步三次 Watcher
的 update
方法,update
的核心是 queueWatcher
,
export function queueWatcher (watcher: Watcher) { const id = watcher.id if (has[id] == null) { has[id] = true if (!flushing) { queue.push(watcher) } else { // ... } // queue the flush if (!waiting) { waiting = true // ... nextTick(flushSchedulerQueue) } } }
代碼裏的 has
就是用來過濾相同 watcher ,雖而後面的被無情拋棄了,可是隻要有這個watcher的id,異步更新的時候使用的也是同步修改的數據。
最直觀的區別是hash模式帶 '#'
history模式使用h5新增的 pushState
和 replaceState
,他們用來修改瀏覽器的歷史記錄棧,修改時不會當即發送請求。
能看到這篇文章大機率說明你在準備面試,若是你是萌新沒怎麼面過,那我能夠告訴你不論是大廠仍是小做坊,面試過程有很大比重是介紹你簡歷中寫的能力和項目,與其盲目的在面試題海里不知所措,不如好好準備簡歷拿下那些送分題。若是你是久經沙場的禿頭碼農 ,那也但願這篇文章能幫助到你。