【前端面试汇总】

2019-11-02  本文已影响0人  Qingelin

1. HTML

1. 必考:你是如何理解 HTML 语义化的?

荒野阶段:最开始是 PHP 后端写 HTML,不会 CSS,于是就用 table 来布局。table 使用展示表格的。严重违反了 HTML 语义化,索然很快就会写出页面,但是后期维护很麻烦。
美工阶段:后来有了专门的写 CSS 、html 的前端,他们只会使用 DIV + CSS 布局,主要是用 float 和绝对定位布局。稍微符合一点,但还是不够语义化,因为不知道每个div什么意思,其实是对于第一种方法的换汤不换药的做法。
前端阶段:再后来,前端越来越专业化,知道 HTML 的各个标签的用法,于是会使用恰当的标签来展示内容,而不是傻傻的全用 div,会尽量使用标题用 h1~h6、列表用ul/ol>li、段落用 p、导航栏用header, 侧边栏用aside,底部用footer,链接用a标签,图片用img等等标签分别表示不同的意思。目前我们写页面的就是html语义化标签。

语义化的好处是易读、有利于SEO等。

2.meta viewport 是做什么用的,怎么写?

这个标签是控制页面在移动端不要缩小显示。具体写法是<meta name=viewport content="width=divice-width,user-scalable=no,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0">
一开始,所有页面都是给PC准备的,乔布斯推出 iPhone 3GS,页面是不适应手机屏幕的,所以乔布斯的工程师想了一个办法,默认把手机模拟成 980px,页面缩小。
后来,智能手机普及,这个功能在部分网站不需要了,所以我们就用 meta:vp 让手机不要缩小我的网页。

3.你用过哪些 HTML 5 标签?

最常见的有:

4.H5 是什么?

移动端页面就叫做H5,注意注意!html5是一项标准,而H5是是一门技术,他俩不是一个概念。


2. CSS

1. 必考:两种盒模型分别说一下

2. 必考:如何居中?

  1. 水平居中:
    • 块级元素:
    • 内联元素:
  2. 垂直居中:

3. 考:flex 怎么用,常用属性有哪些?

Flex是Flexible Box的缩写,意为”弹性布局”,用来为盒状模型提供最大的灵活性。Flex布局有两层,采用flex布局的元素称为flex容器,其子元素则自动成flex item,即项目.

flex-item属性:

          order:定义项目的排列顺序。数值越小,排列越靠前,默认为0。
          flex-grow:定义项目的放大比例,如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍。

          flex-shrink:定义了项目的缩小比例,默认为1,如果所有项目的flex-shrink属性都为1,当空间不足时,都将等比例缩小。如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小。

          flex-basis:定义了在分配多余空间之前,项目占据的主轴空间(main size)。

           flex:是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。

          align-self:允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch。

举例子问题:在行栏中,最左边是一个按钮,右边有两个按钮
实现方法:

<box>
  <item>logo<item>
  <item>登录<item>
  <item>注册<item>
</box>
<style>
  box{
      display:flex;        
      justify-content:space-between;
}
item:nth-child(2){
    margin-left:auto;
}
</style>

4.必考:BFC 是什么?

中文翻译:块级格式化上下文,举个例子:我如果给一个div添加overflow:hidden;那么它里面的浮动元素就会被包裹起来。

5. CSS 选择器优先级

选择器优先级的说法 class第一位,id第二位,……是错的,在css2时带还能用,但是目前css3时带是不能用。【注意】如果hr引导你往这个错误的方向,那就说这个。

  1. 越具体优先级越高
  2. 写在后面的覆盖写在前面的
  3. !important的优先级最高,但是建议少用  

6. 清除浮动说一下(背代码)


3.原生 js

1. 必考:ES 6 语法知道哪些,分别怎么用?

1. 作用域:

2. 箭头函数:

3. 模板字符串:
1. 实现多行字符串:

```
    console.log(`string text line 1
    string text line 2`)
```
  1. 插入表达式:
       var a = 10;
       var b = 5;
       console.log(`Fifteen is ${a + b } and
       not ${a * b} `)
    

4. 解构赋值:可以将属性/值从对象/数组中取出,赋值给其他变量,对象或数组诸葛对应值或表达式。

[a,b] = [10,20]
console.log(a); //10
console.log(b); //20
[a,b,...rest] = [10,20,30,40,50]
console.log(rest); //[30,40,50]
var a = 10;
var b = 20;
[a,b] = [b,a];
function parseProtocol(url) { 
  var parsedURL = /^(\w+)\:\/\/([^\/]+)\/(.*)$/.exec(url);
  if (!parsedURL) {
    return false;
  }
  console.log(parsedURL); // ["https://developer.mozilla.org/en-US/Web/JavaScript", "https", "developer.mozilla.org", "en-US/Web/JavaScript"]

  var [, protocol, fullhost, fullpath] = parsedURL;
  return protocol;
}

console.log(parseProtocol('https://developer.mozilla.org/en-US/Web/JavaScript')); // "https"
//基本赋值
var obj = {p:42,q:true}
var {p.q} = obj
console.log(p) //42
console.log(q) //true
//无声明赋值
var a,b;
({a,b} = {a:1,b:2})
let {a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40}
a; // 10 
b; // 20 
rest; // { c: 30, d: 40 }

5. 模块
1.导入:import:

//语法(必须在严格模式下,type='module'的script标签中使用)
import defaultExport from "Moudule-name" 
let module = await import('/modules/my-module.js')
  1. 导出:export:在创建 javascript 模块时,export语句从模块中导出函数、对象或原始值,以便其他程序通过import 导入并使用他们。
//导出单个单个特性
export let name1,name2,...,nameN;(var const 一样)
export function FunName(){}
export class ClassName{}
//导出列表
export {name1,name2,...,nameN}
//重命名导出
export {Variable1 as name1,variable2 as name2,...,namwN}
  1. 默认导出:export default
export default expression
export default function(){}
export default function name1(…) { … } // also class, function*
export { name1 as default, … };

4.模块重定向

export {defaullt} from './other-module';
exprt * from './other-module';

6.class 类 :类其实是一个特殊的函数,类语法糖有两个部分组成:类表达式和类声明

class Rectangle{
    constructor(width,height){
      this.width = width;
      this.height = height;
    }
}
//匿名类:
let Rectangle = class {
    constructor(width,height){
      this.width = width;
      this.height = height;
    }
}
//具名类
let Rectangle = class  Rectangle{
    constructor(width,height){
      this.width = width;
      this.height = height;
    }
}
class Animal{
    constructor(){
      this.name = name
    }
    speak(){
        console.log(this.name + 'makes a noise')
    }
}
class Dog extends Animal{
     speak(){
        console.log(this.name + 'barks')
      }
}
var dog  = new Dog('mike');
dog.speak();//mike barks
function Animal(name){
    this.name = name
}
Animal.prototype.speak = function (){
    console.log(this.name + 'make a noise')
}
class Dog extends Animal{
    speak(){
        console.log(this.name + 'barks')
    }
}
var dog = new Dog('mike')
dog.speak();  //mike barks
class Cat{
    constructor(name){
        this.name = name
    }

    speak(){
        console.log(this.name + 'makes a noise')
    }
}
 class Lion extends Cat{
    speak(){
        super.speak();
        console.log(this.name + 'roars')
    }
}

7.迭代器
for of VS for in :
这两个语句都是迭代一些东西;
for in 以任意顺序迭代对象的(synbol以外的)可枚举属性;
for of 遍历可迭代对象要迭代的数据。

let arr = ["Apple","Samsung","Nokia","Xiaomi"];

for (let value of arr){
   console.log(value)
}
//  Apple Samsung Nokia Xiaomi


for (let x in arr){
cosnole.log(x)
}
// 0 1 2 3
let obj = { Apple:"iPhone X", Samsung:"Galaxy 6", Nokia:"Lumia",Xiaomi:"Note 3" }

for(let x of obj){
  console.log(x)
}

// !! 这样就报错了(obj is not iterable)原因是这个对象的值的索引必须是可迭代的

for(let x in obj){
  console.log(x)
}

// Apple Samsung Nokia Xiaomi

// for-of 遍历可以迭代的任意对象。而 for-in 遍历的是必需有明确索引的对象
function* company(){
  yield 'Apple';
  yield 'Samsung';
  yield 'Nokia';
  yield 'Xiaomi';
}


for(let x of company()){
  console.log(x)
}

// Apple Samsung Nokia Xiaomi

for(let x in company()){
  console.log(x)
}

// !! 这将什么都不会输出

8.Symbol :
ES5的属性名都是字符串,容易造成属性名冲突,ES6引进了一种新的原始数据类型:Symbol,表示独一无二值(每个从Symbol()返回的symbol值都是唯一的)。
Symbol函数可以接受一个字符串作为参数,表示对Symbol实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分。
它每次都会创建一个新的 symbol类型:

//没有参数的情况
var s1 = Symbol();
var s2 = Symbol();
s1 === s2  //false
//有参数的情况下:
var s1 = Symbol('foo');
var s2 = Symbol('foo');
s1 === s2 //false

2. 必考 Promise、Promise.all、Promise.race 分别怎么用?

promise对象用于返回一个异步操作的最终完成结果。

  1. promise对象使用方法:

    • .then方法:
      $.ajax(……).then(成功函数,失败函数)
    • 链式 .then方法:
      $.ajax(……).then(成功函数,失败函数).then(成功函数2,失败函数2)
  2. 如何自己生成promise对象:

function fn(){
     return new Promise((resolve, reject)=>{
         成功时调用 resolve(数据)
         失败时调用 reject(错误)
     })
 }
 fn().then(success, fail).then(success2, fail2)
  1. Promise.all()的用法:
    promise.all(iterable)方法返回一个promise实例,其参数iterable是可迭代对象,接受一个或多个值的数组(比如,立即值、promise、thenable)。它返回一个promise,此方法在集合多个 promise 的返回结果时很有用。
    举例:promise1和promise2都成功才会调用success1
          Promise.all([promise1, promise2]).then(success1, fail1)
  1. promise.race()的用法:顾名思义,Promise.race就是赛跑的意思,意思就是说,promise1和promise2只要有一个成功就会调用success1,不管结果本身是成功还是失败状态。所接受的参数是一样的,接收多个值的数组。
 Promise.race([promise1, promise2]).then(success1, fail1)

3. 手写函数防抖和函数节流

function fn(){}
CD = false
button.oncLick = function(){
    if(CD){
    }else{
      fn()
      CD = true
     var timerId = setTimeout(()=>{
        CD = false
      } ,3000)
    }
}
    function fn(){}
    var timerId = null
    button.onclick = function(){
          if(timerId){
              window.clearTimeout(timerId)
          }
          fn()
         timerId = null
        timerId = setTimeout(()=>{
                  timerId = null
            },5000)
          }
    }

4. 必考:手写AJAX(背诵代码)

function get/post(url,data,callback){
      var xhr = new XMLHttpRequest()
      xhr.open('POST',"/xxx")
      xhr.setRequestHeader("Content-type":"application/x-www-form-url-encoded")
      xhr.onreadystatechange = function(){
            if(xhr.readyState === 4 && xhr.response.Status === 200 || xhr.status === 304){
                  callback(response)
            }
     }
      xhr.send("a = 1 & b = 2")
}

5. 考:这段代码里的 this 是什么?

函数里的this就看函数是怎么调用的:

6, 必考:闭包/立即执行函数是什么?

  1. 闭包是什么?
    由于在JS中,变量的作用域属于函数作用域,在函数执行后作用域就会被清理、内存也随之回收,但是由于闭包是建立在一个函数内部的子函数,由于其可访问上级作用域的原因,即使上级函数执行完,作用域也不会随之销毁,这时的子函数——也就是闭包,便拥有了访问上级作用域中的变量的权限,即使上级函数执行完后作用域内的值也不会被销毁。
//这里就有闭包,local 变量和 bar 函数就组成了一个闭包(Closure)。
function foo(){
  var local = 1
  function bar(){
    local++
    return local
  }
  return bar //只是为了 bar 能被使用,也跟闭包无关,把 return bar 改成 window.bar = bar 也是一样的,只要让外面可以访问到这个 bar 函数就行了
}

var func = foo()
func()
  1. 闭包的作用:

在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁,由于闭包可以缓存上级作用域,那么就使得函数外部打破了“函数作用域”的束缚,可以访问函数内部的变量。以平时使用的Ajax成功回调为例,这里其实就是个闭包,由于上述的特性,回调就拥有了整个上级作用域的访问和操作能力,提高了极大的便利。开发者不用去写钩子函数来操作上级函数作用域内部的变量了。闭包随处可见,一个Ajax请求的成功回调,一个事件绑定的回调方法,一个setTimeout的延时回调,或者一个函数内部返回另一个匿名函数,这些都是闭包。简而言之,无论使用何种方式对函数类型的值进行传递,当函数在别处被调用时都有闭包的身影。

7. 必考:什么是 JSONP,什么是 CORS,什么是跨域?

1. JSONP:
JSONP是JSON with Padding的略称。它是一个非官方的协议,它允许在服务器集成JavaScript返回至 客户端,通过javascript callback形式实现跨域访问。

$.ajax({
    url : "http://jack.com:8080/pay",
    dataType : "jsonp",
     success : function(response){
        if(response === "success"){
             ...  //执行语句
        }
    }
})

2. CORS:跨源资源分享
Cross-Origin Resource Sharing,是W3C标准,它是解决Ajax跨源请求的根本方法,CORS 允许发送任何类型的请求
用法:

  response.setHeader('Access-Control-Allow-Origin':'http://haha.com:8080')
//设置CORS,http://haha.com:8001这个网站可以访问本服务器响应内容

后台用 JSONP 还是 CORS? 首先JSONP 不能发起POST请求但可以实现跨源请求。CORS可以发起多种类型的请求(后台必须要用POST请求的话只能用CORS),但是需要访问的话在后台设置CORS才能实现跨源请求。
3. 跨域:
跨域是指从一个域名的网页去请求另一个域名的资源。比如从http://www.baidu.com/ 页面去请求 http://www.google.com 的资源。跨域的严格一点的定义是:只要 协议,域名,端口有任何一个的不同,就被当作是跨域。

8. 常考:async/await 怎么用,如何捕获异常?

捕获异常就是抛出promise.reject异常值

aysnc function fn(){
    try{
        var z = await.promise.reject(3)
    }catch(e){
        console.log(e)  //3
    }
}
fn();

9.常考:如何实现深拷贝?(背代码)

  1. JSON来实现深拷贝:
      var a = {...}
      var b = JSON.parse( JSON.stringify(a) )
    

缺点:JSON 不支持函数、引用、undefined、RegExp、Date……

  1. 递归:
       function clone(object){
          var object2
          if(! (object instanceof Object) ){
              return object
          }else if(object instanceof Array){
                object2 = []
          }else if(object instanceof Function){
                object2 = eval(object.toString())
          }else if(object instanceof Object){
                object2 = {}
          }
        //你也可以把 Array Function Object 都当做 Object 来看待,参考 https://juejin.im/post/587dab348d6d810058d87a0a
          for(let key in object){
                object2[key] = clone(object[key])
          }
          return object2
      }
  1. 判断类型:

  2. 检查循环引用(环):

10. 常考:如何用正则实现 trim()?
      function trim(string){
            return string.replace(/^\s | \s+$/g,' ')
      }

11. 考:不用 class 如何实现继承?用 class 又如何实现?

     class Animal{
        constructor(){
          this.body = '肉体'
        },
        move(){}
    }
    class Dog extends Animal{
      constructor(name){
          super(name)
          this.name = name
      },
      useTools(){}
    }
    var qinglin = new Human()

12. 常考:如何实现数组去重?

    //计数排序的逻辑(只能正整数)
 var a = [4,2,5,6,3,4,5]
 var hashTab = {}
 for(let i=0; i<a.length;i++){
     if(a[i] in hashTab){
         // 什么也不做
     }else{
         hashTab[ a[i] ] = true
     }
 }
 //hashTab: {4: true, 2: true, 5: true, 6:true, 3: true}
 console.log(Object.keys(hashTab)) // ['4','2','5','6','3']

      function unique(array){
          return [...new set(array)]
      }

13. 弃:== 相关题目(反着答)

14. 送命题:手写一个 Promise

function Promise(executor) {
    let self = this;
    self.status = 'pending'; //等待态
    self.value = undefined;  //成功的返回值
    self.reason = undefined; //失败的原因

    function resolve(value){
        if(self.status === 'pending'){
            self.status = 'resolved';
            self.value = value;
        }
    }
    function reject(reason) {
        if(self.status === 'pending') {
            self.status = 'rejected';
            self.reason = reason;
        }
    }
    try{
        executor(resolve, reject);
    }catch(e){
        reject(e);// 捕获时发生异常,就直接失败
    }
}
//onFufiled 成功的回调
//onRejected 失败的回调
Promise.prototype.then = function (onFufiled, onRejected) {
    let self = this;
    if(self.status === 'resolved'){
        onFufiled(self.value);
    }
    if(self.status === 'rejected'){
        onRejected(self.reason);
    }
}
module.exports = Promise;


4. Dom

1. 考:事件委托

//错误版(但是可能能过)bug 在于,如果用户点击的是 li 里面的 span,就没法触发 fn,这显然不对。
ul.addEventListener('click',function(e){
    if(e.target.tagName.tiLowerCase === 'li'){
        console.log('li被点击了')
        fn() //执行谋个函数
    }
})

最标准版:

function delegate(element, eventType, selector, fn) {
     element.addEventListener(eventType, e => {
       let el = e.target
       while (!el.matches(selector)) {
         if (element === el) {
           el = null
           break
         }
         el = el.parentNode
       }
       el && fn.call(el, e, el)
     })
     return element
   }

2. 曾考:用 mouse 事件写一个可拖曳的 div

//html
<div id="xxx"></div>
//js
var dragging = false
var position = null

xxx.addEventListener('mousedown',function(e){
  dragging = true
  position = [e.clientX, e.clientY]
})


document.addEventListener('mousemove', function(e){
  if(dragging === false){return}
  console.log('hi')
  const x = e.clientX
  const y = e.clientY
  const deltaX = x - position[0]
  const deltaY = y - position[1]
  const left = parseInt(xxx.style.left || 0)
  const top = parseInt(xxx.style.top || 0)
  xxx.style.left = left + deltaX + 'px'
  xxx.style.top = top + deltaY + 'px'
  position = [x, y]
})
document.addEventListener('mouseup', function(e){
  dragging = false
})

5. HTTP

1. 考:HTTP 状态码知道哪些?分别什么意思?

状态码 202 表示:服务器已接受请求,但尚未处理。
状态码 204 表示:请求处理成功,但没有资源可返回。
状态码 206 表示:服务器已经成功处理了部分 GET 请求。

状态码 301 表示:请求的资源已被永久的分配了新的 URI。
状态码 302 表示:请求的资源临时的分配了新的 URI。

状态码 400 表示:请求报文中存在语法错误。
状态码 401 表示:发送的请求需要有通过 HTTP 认证的认证信息。
状态码 403 表示:对请求资源的访问被服务器拒绝了。
状态码 404 表示:服务器上无法找到请求的资源。

状态码 500 表示:服务器端在执行请求时发生了错误。
状态码 503 表示:服务器暂时处于超负债或正在进行停机维护,现在无法处理请求。

2. 大公司必考:HTTP 缓存有哪几种?

3. 考:GET 和 POST 的区别

4. ookie V.S. LocalStorage V.S. SessionStorage V.S. Session

  1. Cookie —— http协议的一部分
  2. session —— 存在服务器中的一小段哈希表(每个用户都有自己的sessionId请求时存放在session中,),是服务器与浏览器之间的一段时间内的会话。
  3. LocalStorage —— html5提供的API ,常用属性有 setItem()/getItem()/LocalStorage.clear()/removeItem().实现了不同页面中保存变量且其值不变。让后端有了记忆力。

5. HTTP1和 HTTP2的区别:

HTTP2的新特性:
a. 多路复用 (MultiPlexing) —— 解决了线头阻塞的问题,减少了 TCP 连接数量和 TCP 连接慢启动造成的问题
b. 服务端推送 (Server Push) —— 浏览器发送一个请求,服务器主动向浏览器推送与这个请求相关的资源,这样浏览器就不用发起后续请求。
c. Header 压缩 (HPACK) —— 使用 HPACK 算法来压缩首部内容
d. 二进制分帧层 (Binary Framing Layer)—— 帧是数据传输的最小单位,以二进制传输代替原本的明文传输,原本的报文消息被划分为更小的数据帧。


6. 框架

6.1 Vue

1. 必考:watch 和 computed 和 methods 区别是什么?

watch是监听数据,computed是计算属性;
watch和computed的最大区别是:computed是有缓存的,如果computed依赖的属性没有变化,computed属性就不会重新激计算。而watch则是看到一次计算一次。

2. 必考:Vue 有哪些生命周期钩子函数?分别有什么用?

Vue的生命周期:

Vue 的 Mounted生命周期进行数据请求。

3. 考:Vue 如何实现组件间通信?
  1. 父子组件: $emit('xxx',data) on('xxx',function(){})
  2. 爷孙组件之间: 两次 v-on 通过爷爷 => 爸爸 => 孙子
  3. 任意组件之间通信:eventBus = new Vue() 来通信;主要API: eventBus.on和eventBus.emit ; 任意组件之间也可以使用 Vuex来通信。
4. 必考:Vue 数据响应式怎么做到的?(以前的概念:双向绑定)

v-model实现响应式:一句话总结就是:在数据渲染时使用prop渲染数据,将prop绑定到子组件自身的数据上,修改数据时更新自身数据来替代prop,watch子组件自身数据的改变,触发事件通知父组件更改绑定到prop的数据。

 a. Object.defineProperty 通过 getter 和 setter 劫持了对象赋值的过程,在这个过程中可以进行更新 dom 操作等等。
 b. Vue 不能检测到对象属性的添加或删除,解决方法是手动调用 Vue.set 或者 this.$set.
const component = {
    model : {
        prop : 'value',
        event : 'change'
    },
    props : ['value'],
    template:`
       <div> 
          <component v-model="value"></component>
      </div>
    `,
    methods : {
        handleInput(e){
          this.$emit('change',e.target.value)
        }
    }
}

5. 必考:Vue.set 是做什么用的?

Vue不能识别添加或删除属性的变化,vue不能在已经创建的实力上动态的添加新的根级响应式属性,而是必须用 Vue.set方法将响应式属性添加到嵌套对象上。

6. Vuex 你怎么用的?

Vuex是Vue.js应用的程序的状态管理工具。
其核心概念有以下:
state : 基本数据
getters : 基本数据派生的数据
mutations : 提交更改数据的方法,同步
actions : 相当于装饰器,封装mutations,使之可以异步实现
mudules : 模块化Vuex;

7. VueRouter 你怎么用的?

VueRouter是Vue.js官方的路由器管理。常考点:重定向模式,history模式,导航守卫,路由懒加载(import('./Foo.vue')//组件路径,返回promise对象)。
1. 重定向模式:“重定向”的意思是,当用户访问 /a时,URL 将会被替换成 /b,然后匹配路由为 /b。
2. 导航守卫:导航守卫是路由跳转过程中的一些钩子函数,路由跳转是一个大的过程,这个大的过程分为跳转前中后等多个细节过程,在每一个过程中都有一个函数,这些个函数能让你操作一些其他的操作的机会,这就是导航守卫。
导航守卫有三种模式:
* 全局的:指路由在实例上直接操作的函数:钩子函数按执行顺序包括beforeEach、beforeResolve、afterEach三个。
* 单个路由独享的:指单个路由配置的时候可以设置的函数,只有一个函数:beforeEnter,其参数有to,from,next.
* 组件内的:组件内执行的钩子函数,类似于组件内的生命周期,钩子函数按执行顺序包括beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave三个。
3. history模式:history模式采用html5的新特性,提供了两个新方法,pushState ,replaceState,可以对浏览器历史记录栈进行修改,以及popState事件的监听到状态变更。
4. 路由懒加载:当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。
结合 Vue 的异步组件和 Webpack 的[代码分割功能],轻松实现路由组件的懒加载。
使用方法:

import('./Foo.vue') // 返回 Promise。
const router = new VueRouter({
  routes: [
    {
      path: '/Foo',
      name: 'Home',
      component:() = import('../views/home')
        }
  ]
})
8. 路由守卫是什么?(导航守卫的钩子函数来完成)

6.2 React

1. 必考:受控组件 V.S. 非受控组件

举个例子:
<FInput value={x} onChange={fn} /> //受控组件
<FInput defaultValue={x} />//非受控组件

2. 必考:React 有哪些生命周期函数?分别有什么用?(Ajax 请求放在哪个阶段?)
3. 必考:React 如何实现组件间通信?
4. 必考:shouldComponentUpdate 有什么用?

shouldComponentUpdate 这个方法用来判断是否需要调用 render 方法重新描绘 dom。因为 dom 的描绘非常消耗性能,如果我们能在 shouldComponentUpdate 方法中能够写出更优化的 dom diff 算法,可以极大的提高性能。

5. 考:虚拟 DOM 是什么?

react操作中render的结果并不能得到一个真正的DOM节点,而是一个轻量级的javascript对象,我们称之为虚拟DOM。
就是用来模拟DOM的一个对象,有一些常用属性,并且更新 UI 主要就是通过对比(DIFF)旧的虚拟 DOM 树 和新的虚拟 DOM 树的区别完成的,对真实的DOM进行最小化的修改。

6. 必考:什么是高阶组件?

高阶组件是一个以组件为参数并返回一个新组件的函数。HOC 运行你重用代码、逻辑和引导抽象。最常见的高阶组件是 Redux 的 connect 函数。比如 connect(mapState)(MyComponent) 接受组件 MyComponent,返回一个具有状态的新 MyComponent 组件。除了简单分享工具库和简单的组合,HOC 最好的方式是共享 React 组件之间的行为。如果你发现你在不同的地方写了大量代码来做同一件事时,就应该考虑将代码重构为可重用的 HOC。

7. React diff 的原理是什么?

对比两颗DOM树的区别,找出其中不同的部分。React diff 作为Virtual DOM的加速器,其算法上的改进优化是 React 整个界面渲染的基础,以及性能提高的保障,同时也是 React 源码中最神秘、最不可思议的部分,本文将剖析 React diff 的不可思议之处。

8. 考 Redux 是什么?

Redux是一个库,它是javascript状态容器(事件分发中心),提供可以预策划的状态管理。核心概念的名词:action reducer store 单向数据流。
常用的API 有:store.dispatch(action) store.getState() 等。

9. connect 的原理是什么?

是react-redux库提供的API,是基于react和redux封装的函数,负责连接React和Redux,把组件和store连接起来组成一个新的组件。
* 获取state: connect通过context获取Provider中的store,通过store.getState()获取整个store tree 上所有state

10. (组件的)状态(state)和属性(props)之间有何不同?

7. TypeScript

1. never 类型是什么?

never是不应该出现的类型,never类型可以理解为没有返回指的函数或者总是会抛出错误的函数。

//举例:
function(){while return{}}//如果函数内含有 while(true) {}
function foo(){
      throw new Error('not implemented')
  }
//foo的返回类型是never

【注意】never仅能被赋值给另一个never
viod表示没有任何类型。never表示永远不存在的类型。

2. TypeScript 比起 JavaScript 有什么优点?

目前主流框架都已经使用了typescript,Vue3.0\React都已经使用了,typescript是javascript的超集,也就是说js能做到的东西typescript都能做到,javascript程序员会的东西typescript程序员都会,js程序员不会的他们也都会,所以typescript一定是以后的主流。其优点:typescript提供了类型约束,因此可控,更容易重构,做更大的项目,更容易维护。

项目目前只支持 JS,也没有关系,只需要加一个 ts-loader 或者 awesome-typescript-loader 就能提供 TypeScript 支持,TS 可以和 JS 共存。学完 JS 后,只需要学习一下类型声明就可以掌握 TS 了。TS 就是在 JS 上加上类型声明,这样我们就能知道代码是否「大概」正确。
另外,这种方式速度非常快,快到你只要修改代码,TS 就能告诉你代码是否「大概」正确。
从而避免很多 bug。


8. Webpack

参考链接【https://zhuanlan.zhihu.com/p/44438844

1. 必考:有哪些常见 loader 和 plugin,你用过哪些?

三者都是前端构建工具,grunt和gulp在早期比较流行,现在webpack相对来说比较主流,webpack会自动地递归解析入口所需要加载的所有资源文件,然后用不同的Loader来处理不同的文件,用Plugin来扩展webpack功能。
常见的loader—— 加载器

    * html —— pug-loader    markdown-loader
    * css —— style-loader   less-loader   scss-loader  postloader
    * js ——  babel-loader   
    * 图片 —— url-loader  eslint-loader

常见的plugin—— 用Plugin来扩展webpack功能

2. loader 和 plugin的区别是什么?

  1. 不同的作用:
    a. Loader直译为"加载器"。Webpack将一切文件视为模块,但是webpack原生是只能解析js文件,如果想将其他文件也打包的话,就会用到loader。 所以Loader的作用是让webpack拥有了加载和解析非JavaScript文件的能力。
    b . Plugin直译为"插件"。Plugin可以扩展webpack的功能,让webpack具有更多的灵活性。 在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
  2. 不同的用法:
    a. Loader在module.rules中配置,也就是说他作为模块的解析规则而存在。 类型为数组,每一项都是一个Object,里面描述了对于什么类型的文件(test),使用什么加载(loader)和使用的参数(options)
    b. Plugin在plugins中单独配置。 类型为数组,每一项是一个plugin的实例,参数都通过构造函数传入。

3. 必考:如何按需加载代码?

Vue UI组件库的按需加载 为了快速开发前端项目,经常会引入现成的UI组件库如ElementUI、iView等,但是他们的体积和他们所提供的功能一样,是很庞大的。 而通常情况下,我们仅仅需要少量的几个组件就足够了,但是我们却将庞大的组件库打包到我们的源码中,造成了不必要的开销。

不过很多组件库已经提供了现成的解决方案,如Element出品的[babel-plugin-component](https://link.zhihu.com/?target=https%3A//github.com/ElementUI/babel-plugin-component)和AntDesign出品的[babel-plugin-import](https://link.zhihu.com/?target=https%3A//github.com/ant-design/babel-plugin-import) 安装以上插件后,在.babelrc配置中或babel-loader的参数中进行设置,即可实现组件按需加载了。

{
  "presets": [["es2015", { "modules": false }]],
  "plugins": [
    [
      "component",
      {
        "libraryName": "element-ui",
        "styleLibraryName": "theme-chalk"
      }
    ]
  ]
}

单页应用的按需加载 现在很多前端项目都是通过单页应用的方式开发的,但是随着业务的不断扩展,会面临一个严峻的问题——首次加载的代码量会越来越多,影响用户的体验。

通过import(*)语句来控制加载时机,webpack内置了对于import(*)的解析,会将import(*)中引入的模块作为一个新的入口在生成一个chunk。 当代码执行到import(*)语句时,会去加载Chunk对应生成的文件。import()会返回一个Promise对象,所以为了让浏览器支持,需要事先注入Promise polyfill

4. 必考:如何提高构建速度?

5. 义出的文件过大怎么办?


9. 网络安全

1. 考:什么是 XSS?如何预防?

XSS —— Cross-Site Scripting 跨站脚本。

用户 A 提交评论「小谷你好」到服务器,然后用户 B 来访问网站,看到了 A 的评论「小谷你好」,这里没有 XSS。

恶意用户 H 提交评论「<script>console.log(document.cookie)</script>」,然后用户 B 来访问网站,这段脚本在 B 的浏览器直接执行,恶意用户 H 的脚本就可以任意操作 B 的 cookie,而 B 对此毫无察觉。有了 cookie,恶意用户 H 就可以伪造 B 的登录信息,随意访问 B 的隐私了。而 B 始终被蒙在鼓里。
防范方法:

<p>
评论内容:<?php echo $content; ?>
</p>

$content 的内容,没有经过任何过滤,原样输出。

要解决这个原因,只需要后台输出的时候,将可疑的符号 < 符号变成 < (HTML实体)就行。

$p.html(content)
或者

$p = $('<p>'+ content +'</p>')

content 内容又被原样输出了。解决办法就是不要自己拼 HTML,尽量使用 text 方法。如果一定要使用 HTML,就把可疑符号变成 HTML 实体。

2. 必考:什么是 CSRF?如何预防?

Cross Site Request Forgery,跨站请求伪造。其原理是攻击者构造网站后台某个功能接口的请求地址,诱导用户去点击或者用特殊方法让该请求地址自动加载。用户在登录状态下这个请求被服务端接收后会被误以为是用户合法的操作。对于 GET 形式的接口地址可轻易被攻击,对于 POST 形式的接口地址也不是百分百安全,攻击者可诱导用户进入带 Form 表单可用POST方式提交参数的页面。


10. 开放题目

1. 必考:你遇到最难的问题是怎样的?

2. 你在团队的突出贡献是什么?

3. 最近在关注什么新技术

阮一峰的课本,(微博)。

4. 有没有看什么源码,看了后有什么记忆深刻的地方,有什么收获

看一些源代码,命名规范的重要性,从而提高代码的可读性。
设计模式,轮播思路。


11. 个性化题目

1. PWA

2. echarts.js / d3.js

3. three.js

4. flutter

5. SSR


12. 算法 + 数据库


13. git 版本控制:

1. github创建仓库:

 命令行:
git init
git commit -m "first commit"
git add --all
创建远程仓库(复制即可)
git push -u origin master

2. 查看版本:

git log (--prety=online //输出信息太多时可以用) //显示最近到最远的提交日志
git checkout -b <new-branch-name>  //如果版本次数太多可以写成  HEAD~100
//和上一步git checkout 一样功能的命令行有 :
gitk  //功能和git checkout -b <new-branch-name>一样,一图形化工具显示显示已提交版本
选项         说明
-p            按补丁格式显示每个更新之间的差异
--word-diff       按 word diff 格式显示差异
--stat          显示每次更新的文件修改统计信息
--shortstat       只显示 --stat 中最后的行数修改添加移除统计
--name-only       仅在提交信息后显示已修改的文件清单
--name-status     显示新增、修改、删除的文件清单
--abbrev-commit   仅显示 SHA-1 的前几个字符,而非所有的 40 个字符
--relative-date   使用较短的相对时间显示(比如,“2 weeks ago”)
--graph        显示 ASCII 图形表示的分支合并历史
--pretty        使用其他格式显示历史提交信息可用的选项包括oneline,short,full,fuller 和format(后跟指定格式)
--oneline        `--pretty=oneline --abbrev-commit` 的简化用法

3. 切换版本:

git reset --HEAD^ //返回第一个版本
git reflog 命令行提供了查询commit id 的功能,查询到的id 写在git reset后面就会返回指定版本。


14. 垃圾回收机质:

javascript有自动垃圾收集机制(GC:Garbage Collection),也就是说执行环境会负责管理代码执行过程中使用的内存,开发人员不用再过于担心内存使用的问题,所需内存的分配与无用内存的回收完全实现了自动管理。
JS的垃圾回收机制是为了以防内存泄漏,内存泄漏的含义就是当已经不需要某块内存时这块内存还存在着,垃圾回收机制就是间歇的不定期的寻找到不再使用的变量,并释放掉它们所指向的内存。

上一篇 下一篇

猜你喜欢

热点阅读