乐趣区

2020春季13年前端面经

css

z-index 在什么状况下生效

z-index 只作用于被定位了的元素上,还有就是子元素的 z -index 会被父的值笼罩。

box-sizing 有哪些值

content-boxborder-box 两个,前者是默认值,指设定的 width 只蕴含 content 的宽,不蕴含 border 和 padding,后者都包含。
这个问的还挺多的有的是给 html+css 代码叫算大小的,有的是口头表白的。

flex 相干属性值以及他们的意义

flex 是布局的大方向,问的频率也挺高的,要么是问垂直居中的时候引出来,要么是叫你实现一个简略布局而后引出来,不分明的能够看一哈阮一峰老师的教程(传送门)

css 优化伎俩

这种优化的伎俩是说不完的,我也仅表白一下本人现阶段的一些了解。
1、进步加载速度:比方最最最根底的压缩文件大小,还有能够通过内联 css 来使浏览器开始页面渲染的工夫提前,文件大小须要管制在 14.6kb(因为初始拥塞窗口存在限度),还有就是 chrome 自带的 coverage 标签,能够剖析 js 和 css 文件的使用率,而后咱们去进一步做懒加载或者移除无用代码。
2、进步选择器的性能,比方不要嵌套太多简单的层级,选择器从右到左匹配。
3、进步渲染速度,这个我也不太懂,只是最近看 canvas 的时候,mdn 里对于 canvas 优化提到 CSS transforms 应用 GPU,因而速度更快,找到了一篇文章介绍应用 transform 与否的比照演示,也解释了为什么会更快,感觉不错,文章传送门。

JS

map 和 filter 的区别

map 的回调里 return 啥就是啥,filter 的回调里返回的布尔值决定以后项是否会存到新的数组里。
我其实没懂这个是想问啥,因为口试遇到这道题的时候其余题都还挺有意思的,有点把我整懵了。

sleep

独自实现一个 sleep 很简略

function sleep(time) {return new Promise((res) => {setTimeout(res, time)
  })
}

然而面试过程中,碰到了一道口试题十分有意思,大略是这样:

// 实现
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

我一开始的思路是应用 setTimeoutPromisemacro/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 关键字,写个函数包一下就好

function _Person(name) {return new Person(name)
}

currying

// 实现三数相加的 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 the toString method automatically when a Function 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,这让我很纳闷,找了很多材料也没有后果,如果你晓得的话,还请不吝赐教。

Vue

父子组件钩子程序

父 beforeCreate 父 created 父 beforeMount
子 beforeCreate 子 created 子 beforeMount 子 mounted
父 mounted
子组件是先于父组件 mounted 的。

数据变动之后会立刻更新 dom 吗

这个题也挺有意思的,是在 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, 也就是程序同步三次 Watcherupdate 办法,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,异步更新的时候应用的也是同步批改的数据。

vue-router 两种模式 hash 和 history 的区别

最直观的区别是 hash 模式带 ‘#’
history 模式应用 h5 新增的 pushStatereplaceState,他们用来批改浏览器的历史记录栈,批改时不会立刻发送申请。

一些感想

能看到这篇文章大概率阐明你在筹备面试,如果你是萌新没怎么面过,那我能够通知你不论是大厂还是小作坊,面试过程有很大比重是介绍你简历中写的能力和我的项目,与其自觉的在面试题海里手足无措,不如好好筹备简历拿下那些送分题。如果你是久经沙场的 秃头 码农,那也心愿这篇文章能帮忙到你。

退出移动版