robbiemie/keep-learning

面试题(day1)

Opened this issue · 0 comments

1. css3特性中的transform:translateZ(0)有什么作用?

该属性可以利用 GPU 加速,提高浏览器的渲染性能。原理是 translateZ 的元素会单独占据一个渲染层;这样当元素发生改动时,浏览器的重绘区域减少,提升性能。

tips:

  • 重排(reflow) : 对dom元素进行定位和布局
  • 重绘(repaint): 绘制dom元素的样式,如颜色、背景、文字大小、边框等

动画优化技巧:

  • 减少浏览器重排和重绘操作
  • 不要使用 table 布局
  • css 动画尽量使用 transform 和 opacity
  • 避免使用 js 操作dom,实现动画
  • 减少图片尺寸、优化 gpu 加载性能

参考文档:

2. 列举三种禁止浏览器缓存的头字段,并写出响应的设置值

tips:

  • 缓存控制(cache-control): 是http/1.1定义的缓存策略。
  • cache-control: 设置值包括:
    • no-store: 没有缓存,不得缓存客户端请求和服务端响应的内容
    • no-cache: 缓存但重新验证,客户端会将请求带给服务端,服务端进行校验,若未过期(返回code:304),直接使用缓存内容
    • max-age=<seconds>: 过期机制,表示缓存的最大时长
  • pragma: 是http/1.0定义的header属性。
  • 缓存失效公式:
exirationTime = responseTime + freshnessLifetime - currentAge

3. 精确获取页面元素位置的方式有哪些

  • getBoundingClientRect() 方法:返回元素大小以及相对于视窗的位置。

返回的结果有:

  • left
  • top
  • right
  • bottom
  • x
  • y
  • width
  • height

除了 width 和 height 以外,其他属性值都是以视窗左上角来计算的。如果视窗发送滚动操作,则需要计算滚动位置,topleft发生了变化。此时,可以通过如下方式计算滚动后的相对位置:

// x
el.getBoundingClientRect().x + el.scrollLeft
// y
el.getBoundingClientRect().y + el.scrollTop

4. 正则从 2018-10-07T11:48:47 Asia/zh-cn 获取 [2018,10,07,11,48,47]

let str = '2018-10-07T11:48:47 Asia/zh-cn'
str.match(/\d+/g)

5. 如何判断 object 是数组类型

// 方法一
Array.isArray([]) // true
// 方法二
Object.prototype.toString.call([]) // [object Array]

编程题

1.已知数据结构users,请实现语法支持user.unique能够按照name字段去重,
并输出结构为:["a","b","v"]

var users=[{
   id:1,name:"a"
},{
   id:2,name:"a"
},{
   id:3,name:"b"
},{
   id:4,name:"v"
}]

2.已知如下对象,请基于es6的proxy方法设计一个属性拦截读取操作的例子,要求实现去访问目标对象example中不存在的属性时,抛出错误:Property "$(property)" does not exist

3.给出如下虚拟dom的数据结构,如何实现简单的虚拟dom,渲染到目标dom树

//样例数据
let demoNode = ({
    tagName: 'ul',
    props: {'class': 'list'},
    children: [
        ({tagName: 'li', children: ['douyin']}),
        ({tagName: 'li', children: ['toutiao']})
    ]
});

//构建一个render函数,将demoNode对象渲染为以下dom
<ul class="list">
    <li>douyin</li>
    <li>toutiao</li>
</ul>

题解

1.已知数据结构users,请实现语法支持user.unique能够按照name字段去重,
并输出结构为:["a","b","v"]

var users=[{
   id:1,name:"a"
},{
   id:2,name:"a"
},{
   id:3,name:"b"
},{
   id:4,name:"v"
}]
// 解法一
// 常规解法
Array.prototype.unique = function () {
  console.log(this)
  if(!this || !Array.isArray(this)) return []
  let uniqueMap = {}
  this.forEach(item=>{
    uniqueMap[item.name] = item.name
  })
  return Object.keys(uniqueMap)
}


// 解法二
// 使用 ES6 Map
Array.prototype.unique = function () {
  console.log(this)
  if(!this || !Array.isArray(this)) return []
  let uniqueMap = new Map()
  this.forEach(item => {
    uniqueMap.set(item.name, item.name)
  })
  let values = []
  for (let [key, value] of uniqueMap) {
    values.push(key)
  }
  return values
}

// 解法三
// 使用 ES6 Set
Array.prototype.unique = function () {
  console.log(this)
  if(!this || !Array.isArray(this)) return []
  let uniqueSet = new Set()
  this.forEach(item => {
    uniqueSet.add(item.name)
  })
  let values = [...uniqueSet]
  return values
}


var users=[{
  id:1,name:"a"
},{
  id:2,name:"a"
},{
  id:3,name:"b"
},{
  id:4,name:"v"
}]

let value = users.unique() // ["a","b","v"]

2.已知如下对象,请基于es6的proxy方法设计一个属性拦截读取操作的例子,要求实现去访问目标对象example中不存在的属性时,抛出错误:Property "$(property)" does not exist

const man={
  name:'jscoder',
  age:22
}
//补全代码
const proxy = new Proxy(man, {
  get(target, key) {
    if(target[key]) {
      return target[key]
    }
    return `Property "$(${key})" does not exist`
  }
})

let a = proxy.name //"jscoder"
let b = proxy.age //22
let c = proxy.location //Property "$(property)" does not exist
console.log(a)
console.log(b)
console.log(c)

3.给出如下虚拟dom的数据结构,如何实现简单的虚拟dom,渲染到目标dom树

//样例数据
let demoNode = ({
    tagName: 'ul',
    props: {'class': 'list'},
    children: [
        ({tagName: 'li', children: ['douyin']}),
        ({tagName: 'li', children: ['toutiao']})
    ]
});

//构建一个render函数,将demoNode对象渲染为以下dom
<ul class="list">
    <li>douyin</li>
    <li>toutiao</li>
</ul>
let demoNode = ({
  tagName: 'ul',
  props: {'class': 'list'},
  children: [
      ({tagName: 'li', children: ['douyin']}),
      ({tagName: 'li', children: ['toutiao']})
  ]
});


function createElement (tagName,props) {
  let el = document.createElement(tagName)
  props && Object.keys(props).forEach(key => {
    if(props[key]) {
      el.setAttribute(key, props[key])
    }
  })
  return el
}

function createTextNode(text) {
  return document.createTextNode(text)
} 

function searchVNode (vnode) {
  if(!vnode) throw new Error("参数不能为空")
  if(typeof vnode === 'string') {
    return createTextNode(vnode)
  }
  let parentNode = createElement(vnode.tagName, vnode.props)
  vnode.children.forEach( childVNode => {
    let childNode = searchVNode(childVNode)
    parentNode.appendChild(childNode)
  })
  return parentNode
}

searchVNode(demoNode)


//构建一个render函数,将demoNode对象渲染为以下dom
{/* <ul class="list">
  <li>douyin</li>
  <li>toutiao</li>
</ul> */}