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
,他们用来修改浏览器的历史记录栈,修改时不会当即发送请求。
能看到这篇文章大几率说明你在准备面试,若是你是萌新没怎么面过,那我能够告诉你不论是大厂仍是小做坊,面试过程有很大比重是介绍你简历中写的能力和项目,与其盲目的在面试题海里不知所措,不如好好准备简历拿下那些送分题。若是你是久经沙场的秃头码农 ,那也但愿这篇文章能帮助到你。