前端面试复习总结---为学弟学妹秋招护驾 (超丰富,极力推荐)

前端面试复习总结-为学弟学妹秋招护驾

1,实现居中

水平居中:

  • ext-align:center;
  • margin: 0 auto;
  • display:flex; justify-content: center;
  • position:absolute;left: 50%; transform: translateX(-50%);

垂直居中:

  • line-height等于高度
  • position:absolute; top: 50%; transform: translateY(-50%);
  • display:flex; align-items:center;
  • 父元素display:table; 子元素display:table-cell;vertical-align:middle;

2,闭包的概念

  • 概念:闭包就是能读取其他函数内部变量的函数
  • 优点:1、避免全局变量的污染;2、希望一个变量长期存储在内存(缓存变量);
  • 缺点:1、容易造成内存泄露 内存泄露例子:
let getMoney = function() {
    let money = 10
    return function() {
        return money
    }
}
let f = getMoney()
// f函数存在的话,money会一直得不到释放

3,深拷贝和浅拷贝

浅拷贝:

Object.assign()
Array.prototype.slice()

深拷贝:

JSON.parse(JSON.stringify()) // 无法序列化函数

递归函数:

function cloneObject(obj) {
  var newObj = {} //如果不是引用类型,直接返回
  if (typeof obj !== 'object') {
    return obj
  }
  //如果是引用类型,遍历属性
  else {
    for (var attr in obj) {
      //如果某个属性还是引用类型,递归调用
      newObj[attr] = cloneObject(obj[attr])
    }
  }
  return newObj
}
// 无法解决循环引用问题

4,数组去重

ES6中的set:

let arr = [1,2,3,1,2,3]
let arr2 = [...new Set(arr)]

新数组去重:

let newArr = []
let arr = [1,2,3,1,2,3]
arr.forEach(item => {
    if (newArr.indexOf(item) === -1) {
        newArr.push(item)
    }
})

5,JS执行机制、事件循环

  • 事件循环:同步任务进入主线程,异步任务进入EventTable中并注册回调函数中。当所有同步任务执行完毕时,主线程从事件队列中读取回调函数并执行。上述过程不断重复,称为事件循环

6, 宏任务和微任务

  • 异步任务会分成宏任务与微任务
  • 微任务是在宏任务执行完后立即执行的任务
  • 宏任务:主代码块,setTimeout,setInterval等
  • 微任务:Promise,process.nextTick等
  • 当宏任务执行完时,如果有可执行的微任务,则执行所有微任务后再执行新的宏任务。如果没有可执行的微任务,那么直接开始执行新的宏任务

7,函数提升与变量提升

在作用域中,函数声明与变量声明都会提升到顶部。首先声明变量整体,然后再声明函数整体。

function v() {
  console.log(a)
  var a = 1;
  function a() {}
}
v()
// 输出函数a
// 上面函数相当于:
function v() {
  var a;
  function a() {}
  console.log(a)
  a = 1;
}
v()

注意:函数表达式不会被提升

8,常见内存泄露

  • 1、全局变量滥用,当不用var声明变量的时候,比如b=1,相当于挂载到全局变量。解决方法:使用严格模式
  • 2、没有清理DOM元素的引用
  • 3、闭包
  • 4、定时器被遗忘

9,性能优化

  • 1、减少请求数量
  • 2、事件委托:减少DOM操作,每个新增的元素都能拥有该事件
  • 3、压缩资源大小
  • 4、减少重绘回流
  • 5、innerHTML代替dom操作
  • 6、图片预加载

10,Vue性能优化

  • 1、路由懒加载
  • 2、v-if与v-show正确使用
  • 3、v-for中设置唯一key
  • 4、图片懒加载

11,实现EventBus

function EventEmitter() {
  this.events = new Map()
  this.addListener = function (name, fn) {
    this.events.set(name, fn)
  }
  this.emit = function (name) {
    let fn = this.events.get(name)
    fn(...[...arguments].slice(1))
  }
}
var bus = new EventEmitter()
bus.addListener('age', (age, time) => {
  console.log(age, time)
})
bus.emit('age', 18, '2019')

12,引用类型有哪几种

  • Object
  • Array
  • Date
  • RegExp
  • Function

12,CSS盒模型

  • Margin、Border、Padding、Content
  • IE定义的盒模型中元素的宽高包括了padding和border
  • W3C盒模型元素宽高为Content
  • box-sizing: content-box; // W3C盒模型
  • box-sizing: border-box; // IE盒模型

13,伪类和伪元素的区别

  • 它们之间的根本区别在于是否创造了新的元素
  • 伪类不会创造新的元素,比如:hover :active
  • 伪元素会创造新的元素,比如:after :before
  • 伪类:表示已存在的某个元素处于某种状态
  • 伪元素:用于将特殊的效果添加到某元素

14,实现快速排序

function quickSort(arr) {
  if (arr.length < 1) {
    return arr
  }
  var left = []
  var right = []
  var pivot = arr[0]
  for (var i = 1; i < arr.length; i++) {
    if (arr[i] > pivot) {
      right.push(arr[i])
    } else {
      left.push(arr[i])
    }
  }
  return [...quickSort(left), pivot, ...quickSort(right)]
}
var arr = [0, 3, 4, 2, 6, 1, -1, 123]
console.log(quickSort(arr))
// ----------------------
console.log('------------')
// ----------------------
// 单指针循环法
function quickSort2(arr) {
  if (arr.length < 1) {
    return arr
  }
  var pivot = arr[0]
  var mark = 0
  for (var i = 0; i < arr.length; i++) {
    if (arr[i] < pivot) {
      mark++
      let temp = arr[i]
      arr[i] = arr[mark]
      arr[mark] = temp
    }
  }
  let temp = arr[0]
  arr[0] = arr[mark]
  arr[mark] = temp
  return [...quickSort2(arr.slice(0, mark)), arr[mark], ...quickSort2(arr.slice(mark+1, arr.length))]
}
var arr = [0, 3, 4, 2, 6, 1, -1, 3]
console.log(quickSort2(arr))

15,堆排序

// 最小堆,父节点小于两个子节点

function downAjust(arr, parentIndex, length) {
  let childIndex = 2 * parentIndex + 1
  while (childIndex < length) {
    if (childIndex + 1 < length && arr[childIndex + 1] < arr[childIndex]) {
      childIndex ++
    }
    if (arr[parentIndex] < arr[childIndex]) {
      return
    }
    let temp = arr[parentIndex]
    arr[parentIndex] = arr[childIndex]
    arr[childIndex] = temp
    parentIndex = childIndex
    childIndex = 2 * parentIndex + 1
  }
}
function buildHeap(arr) {
  for (let i = parseInt((arr.length -1) / 2); i >= 0; i--) {
    downAjust(arr, i, arr.length)
  }
  console.log(arr)
}
var arr = [7, 1, 3, 10, 5, 2, 8, 9, 6]
buildHeap(arr)
heapSort(arr)
function heapSort(arr) {
  for (let i = arr.length - 1; i >= 0; i--) {
    let temp = arr[i]
    arr[i] = arr[0]
    arr[0] = temp
    downAjust(arr, 0, i)
  }
  console.log(arr)
}

16,归并排序

function merge(left, right) {
  let arr = []
  while (left.length && right.length) {
    if (left[0] < right[0]) {
      arr.push(left.shift())
    } else {
      arr.push(right.shift())
    }
  }
  arr.push(...left, ...right)
  return arr
}
function mergeSort(arr) {
  if (arr.length > 1) {
    let mid = parseInt(arr.length / 2)
    let left = arr.slice(0, mid)
    let right = arr.slice(mid)
    return merge(mergeSort(left), mergeSort(right))
  }
  return arr
}
var arr = [8, 2, 4, 1, 3, 9, 0, -1, -2]
console.log(mergeSort(arr))

17,实现二分查找

function binarySearch(arr, target) {
  let low = 0
  let high = arr.length - 1
  while (low <= high) {
    let mid = parseInt((low + high) / 2)
    if (arr[mid] > target) {
      high = mid - 1
    } else if (arr[mid] < target) {
      low = mid + 1
    } else {
      return mid
    }
  }
  return -1
}
var arr = [0, 1, 2, 3, 3, 4, 5]
console.log(binarySearch(arr, 5))

18,数组和链表的区别

数组:

  • 在内存中连续存储
  • 优点是具有高效的随机访问能力,常量时间内可以找到对应元素
  • 缺点是在插入和删除元素时,可能会导致大量元素被迫移动,影响效率
  • 数组适合在读操作多,写操作少的场景

链表:

  • 在内存中是随机存储
  • 优点是能够灵活地进行插入删除操作
  • 缺点是查找元素的性能较差

19,URI和URL

  • URI就是统一资源标识符,URL就是统一资源定位符
  • URI有两种形式,URL和URN
  • URL由协议、主机、端口、路径四个部分组成,唯一标识资源位置
  • URN是统一资源名,它使得资源与位置无关,只使用资源名就能够获取资源,这种形式处于试验阶段,尚未被大范围使用

20,TCP与UDP

  • TCP是一种可靠的传输方式,能够将数据按序无差错传输。HTTP使用TCP来传输其报文数据。
  • TCP的建立需要经过三次握手
  • UDP是一种不可靠的传输方式,它不保证数据能准确传输。在允许丢包的情况下使用UDP传输效率会更高,比如视频、音频,个别丢包不影响整体画面

21,访问一个网址时浏览器经历的步骤

  • 1、浏览器从URL中解析主机名和端口
  • 2、DNS解析出IP地址
  • 3、建立TCP连接
  • 4、浏览器发送HTTP请求报文
  • 5、服务器返回HTTP响应报文
  • 6、关闭连接,浏览器开始解析文档
  • 7、浏览器首先解析出DOM树
  • 8、再次解析出CSSOM树
  • 9、根据DOM树和CSSOM树来构造render tree渲染树
  • 10、浏览器重排、重绘,绘制每个节点

22,重排、重绘

  • 浏览器默认采用流式布局模型
  • 重排也叫回流
  • 重排:根据渲染树中每个对象的信息,计算渲染对象各自的几何信息(位置、尺寸大小),并将其安置在界面正确位置。
  • 因此呢,如果发生改变了位置、尺寸大小,会引发回流,重新计算全局布局(从根节点重新布局)或者局部布局。例如,改变窗口大小会引发全局布局的重新计算;
  • 引起重排的操作:
  • 页面首次渲染
  • 窗口大小改变
  • 元素尺寸或位置改变
  • 字体大小改变
  • 添加或删除DOM元素
  • 获取offsetTop、offsetLeft等属性触发重排,应缓存起来
  • 重绘:当页面某元素样式的改变并不影响其在文档流中的位置
  • 例如改变背景颜色、字体颜色等操作

23,强缓存与协商缓存

  • 强缓存:服务器通过设置response
    header中的cache-control字段来控制浏览器对资源缓存,max-age用于设置缓存的过期时间。如果是cache-control:no-cache,代表跳过设置强缓存,会走协商缓存。
  • 协商缓存:当强缓存过期后,客户端每次访问资源时会先看下缓存有无过期,如果过期了,则询问服务器资源是否已更改,如果已更改,服务器会返回资源以及对应的etag和last-modified;如果没有更改,则服务器返回一样的etag和last-modified,状态码为304(资源无变更),这时客户端之后访问缓存都要走一次协商缓存。
  • etag:每个文件的hash
  • last-modified:资源最后更改时间
  • 强制缓存是我们在第一次请求资源时在 http 响应头设置一个过期时间,在时效内都将直接从浏览器进行获取,常见的 http 响应头字段如
    Cache-Control 和 Expires 协商缓存是我们通过 http 响应头字段 etag 或者 Last-Modified等判断服务器上资源是否修改,如果修改则从服务器重新获取,如果未修改则 304 指向浏览器缓存中进行获取

24,call、apply、bind

  • 这三个函数都是改变this的指向
  • call、apply第一个参数都是this所指向的对象,它们之间的区别是传参的方式不同。
  • apply的传参方式是以数组的方式传参,而call是以逐个传参的方式
  • bind函数的第一个参数也是this所指向的对象,它和上面call、apply不一样,它返回一个新的函数。

25,完全二叉树与满二叉树

  • 满二叉树:深度为k,并且有2^k-1个节点的二叉树
  • 完全二叉树:完全二叉树的n个节点的编号都能对应相同深度满二叉树的1~n个节点一一对应

26,Promise对象

Promise有三个状态:

  • 1、进行中pending;2、成功态fulfilled;3、拒绝rejected;
  • Promise构造函数接受一个参数为resolve和reject的函数
  • resolve、reject能改变promise的状态。
  • 通过then方法为promise注册完成时的处理程序

27,Vue生命周期

beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestory、destoryed
  • created周期在模板渲染成HTML前调用,能够获取到实例的data,通常初始化某些属性值
  • mounted周期在模板渲染成HTML后调用,通常是初始化页面完成后对DOM进行一些操作。

28,web worker

JavaScript是单线程语言,WebWorker是为了创造多线程环境,允许主线程创建Worker线程,这样worker线程完成任务后会自动返回结果给主线程。

需要注意以下几点:

  • 1、主线程与worker线程必须同源
  • 2、worker无法读取主线程的Dom对象
  • 3、不能直接通信,需要通过消息postMessage来完成

29,封装ajax

function ajax(url, type, data, success) {
    let aj = new XMLHttpRequest()
    if (type === 'get') {
        if (data) {
            url += '?'
            let arr = []
            Object.keys(data).forEach(key => {
                arr.push(key + '=' + data[key])
            })
            url += arr.join('&')
        }
        aj.open(type, url)
        aj.send(data)
    } else if (type === 'post') {
        aj.open(type, url)
        aj.setRequestHeader('Content-type', 'x-www-form-urlencoded')
        if (data) {
            aj.send(data)
        } else {
            aj.send()
        }
    }
    aj.onreadystatechange = function() {
        if (aj.readyState === 4 && aj.status === 200) {
            success(aj.responseText)
            console.log(aj.responseText)
            return aj.responseText
        }
    }
    }

30,for…in与for…of

  • for…in循环用于获取键名
  • for…of循环用于获取键值

代码如下

var arr = ['a','b','c']
for (var i in arr) {
    console.log(i)
}
// 0, 1, 2 //遍历数组就是获取下标
for (var i of arr) {
    console.log(i)
}
// a b c //遍历数组就是获取值

var obj = {
    a: 1,
    b: 2,
    c: 3
}
for (var i in obj) {
    console.log(i)
}
// a b c  //遍历对象就是获取键名
for (var i of arr) {
    console.log(i)
}
// 用在对象会报错

31,防篡改对象

  • 主要使用三个方法Object.preventExtensions、Object.seal、Object.freeze
  • 分别对应为不可扩展、密封、冻结
  • 通过 Object.isExtensible([Object]) 可以确定对象是否可以扩展。 true 可以扩展, false不可以扩展。
  • 通过 Object.isSealed([Object]) 可以确定对象是否被密封了。
  • 通过 Object.isFrozen([Object]) 来检测对象是否被冻结。

32,数组扁平化

var arr = [1, 2, [3,4], [1, [2, 3, [3, 4]]]]
function fn(arr) {
  let newArr = []
  for (var i of arr) {
    if (i instanceof Array) {
      newArr.push(...fn(i))
    } else {
      newArr.push(i)
    }
  }
  return newArr
}
console.log(fn(arr))

33,判断数据类型

  • 判断数组:Array.isArray()
  • typeof:能判断的数据类型有String、number、objcet、function、boolean、undefined。不能判断null和array
typeof Symbol(); // symbol 有效
typeof ''; // string 有效
typeof 1; // number 有效
typeof true; //boolean 有效
typeof undefined; //undefined 有效
typeof new Function(); // function 有效
typeof null; //object 无效
typeof [] ; //object 无效
typeof new Date(); //object 无效
typeof new RegExp(); //object 无效
  • instanceof:判断是否某个原型的实例,不能检测null和undefined
[] instanceof Array; //true
{} instanceof Object;//true
new Date() instanceof Date;//true
new RegExp() instanceof RegExp//true
null instanceof Null//报错
undefined instanceof undefined//报错
  • Object.prototype.toString.call():这个较为准确,不能检测自定义类型
Object.prototype.toString.call('') ;   // [object String]
Object.prototype.toString.call(1) ;    // [object Number]
Object.prototype.toString.call(true) ; // [object Boolean]
Object.prototype.toString.call(undefined) ; // [object Undefined]
Object.prototype.toString.call(null) ; // [object Null]
Object.prototype.toString.call(new Function()) ; // [object Function]
Object.prototype.toString.call(new Date()) ; // [object Date]
Object.prototype.toString.call([]) ; // [object Array]
Object.prototype.toString.call(new RegExp()) ; // [object RegExp]
Object.prototype.toString.call(new Error()) ; // [object Error]

34,BFC
块格式化上下文,BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素
如何创建BFC:

  • 1、display为inline-block table-cell flex
  • 2、浮动元素float不是none
  • 3、定位元素:absolute、fixed
  • 4、overflow除了visible以外的值
    BFC的作用:
  • 1、避免margin重叠(放在不同的BFC)
  • 2、避免高度塌陷
  • 3、包裹浮动元素
    BFC布局规则:
  • 1、在BFC中,盒子(块级元素)会在垂直方向排列
  • 2、box垂直方向的距离有margin决定,同一个BFC的margin会重叠(以最大值为准)

35,清除浮动

  • 1、clear:both(通过after伪元素清除浮动)
  • 2、父级div设置overflow:hidden(触发BFC)

36,async和await

  • async函数返回一个Promise对象
  • await用于等待一个异步函数执行结果
  • 这两个配合使用能使得代码看起来更像同步代码

37,await处理错误
把await的代码放在try…catch块中或者使用catch注册函数

async function MyAsync() {
    try{
        await doSomething()
    } catch(err) {
        console.log(err)
    }

    await doAnotherThing().catch((err) => {
        console.log(err)
    })
}
// 以上两种方法皆可以

37,Cookie的弊端

  • 1、每个特定的域名下最多生成20个cookie
  • 2、最大存储空间为4K
  • 3、安全性问题。被恶意获取到时他人只需原样转发cookie便可以达到目的

38,CSS中 link 和@import 的区别是?

  • link是HTML标签,无兼容性问题
  • @import是CSS提供的,需要IE5以上才能识别
  • 页面加载时link会同时被加载,而import会在页面被加载后再加载

39,CSS 选择符有哪些?哪些属性可以继承?优先级算法如何计算?

css选择器:

  • id选择器#id
  • 类选择器.class
  • 属性选择器a[href=“bb”]
  • 后代选择器h2 p
  • 子代选择器div > p
  • 相邻选择器div + h1
  • 伪类选择器a:hover
  • 标签选择器div,p
  • 可继承样式:
  • font-size font-family color 不可继承样式:
  • margin padding border width height 优先级:
  • !important > 内联 > id > class > tag
  • !important比内联优先级高,内联优先级比id高

40,HTML语义化

  • 1、当样式丢失时,页面能够呈现出清晰 的结构
  • 2、有利于SEO搜索爬取有效信息
  • 3、方便其他设备解析(屏幕阅读器、盲人阅读器)

41,new操作符的作用

  • 1、创建空对象,并将this指向该对象
  • 2、属性和方法被加入到this指向的对象中
  • 3、最后隐式返回this

42,相等操作符的比较

  • ==操作符会将操作数进行数据类型的强制转换
  • 1、如果有操作数为布尔值,则布尔值转为数字,false转0,true转1
  • 2、如果有操作数为字符串,则字符串转为数字
  • 3、如果有操作数为对象,则调用valueOf, 没有valueOf就有toString,都没有就返回NaN
  • 反正就是都转为数字来进行比较

43,对象转字符串或数字

var a = {
    toString: () => '1',
    valueOf: () => 0
}
a == '1' // false
a == 0 // true
var b = {
    toString: () => '1'
}
b == '1' // true

对象转字符串:

  • 1、判断对象是否有toString,有则调用
  • 2、没有toString,判断有无valueOf,有则调用
  • 3、都没有,报错

对象转数字:

  • 1、判断有无valueOf,有则调用
  • 2、没有valueOf,判断有无toString,有则调用
  • 3、都没有。报错

44,虚拟DOM

  • 虚拟DOM其实就是用JavaScript去模拟真实的DOM,当DOM变化的时候,先在虚拟DOM上进行新旧对比,然后将差异部分更新到真实的DOM上。

45,Vue中key值的作用

  • key值主要出现在使用v-for的时候,需要为每个渲染元素指定key值。当v-for更新列表时,默认采用就地复用的策略。如果顺序被打乱,vue不会移动DOM元素来匹配,而是用就地复用每个元素。key的作用是为了更高效的更新虚拟DOM
  • 为每个元素指定key值,以便vue能跟踪节点的身份

46,Vue组件通信

  • 1、props和emit:props是父组件向子组件单向传值,子组件不能改变父组件的属性。因此子组件只能通过emit:props是父组件向子组件单向传值,子组件不能改变父组件的属性。因此子组件只能通过emit向父组件派发事件来进行传值。
  • 2、vuex:这是vue配套的状态管理插件,通过抽离部分状态为全局状态,使整个数据流变得清晰可追踪。

47,Vue的prop单向数据流

  • 父级prop的更新将向下流动到子组件中,反过来不行。但是如果传入的prop是引用类型比如数组或者对象,那么子组件对prop的改动会影响父组件的状态

48,vuex有哪几种属性

  • state、getter、mutation、action、module

49,vue中的v-model

  • v-model实际上是默认利用了名为value的prop属性和名为input的事件,通过model选项来指定prop和事件的名称
Vue.component('base-checkbox', {
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: {
    checked: Boolean
  },
  template: `
    <input
      type="checkbox"
      v-bind:checked="checked"
      v-on:change="$emit('change', $event.target.checked)"
    >
  `
})

50,vue的插槽

使用插槽可以将组件内的slot替换为任何模板代码

<navigation-link url="/profile">
  Your Profile
</navigation-link>

然后你在 的模板中可能会写为:

<a
  v-bind:href="url"
  class="nav-link"
>
  • 注意:如果组件内没有slot元素,那么组件起始标签和结束标签之间的任何内容都会被抛弃
  • 当含有多个插槽时,为每个插槽指定一个name,这是就可以指定希望往哪个具名插槽内添加模板代码了

51,箭头函数

  • 箭头函数没有this、arguments、new.target等属性
  • 他只能通过作用域查找来寻找this
  • 如果被包含在非箭头函数时,自动绑定到最近一层非箭头函数。否则自动绑定到全局对象

52,class和构造函数的区别

  • 1、class不能被提升
  • 2、class中所有方法默认是不可枚举的
  • 3、class必须使用new调用否则会报错

53,this指向问题

  • 情况1:如果一个函数中有this,但是它没有被上一级的对象所调用,那么this指向的就是window,这里需要说明的是在js的严格版中this指向的不是window,但是我们这里不探讨严格版的问题,你想了解可以自行上网查找。
  • 情况2:如果一个函数中有this,这个函数有被上一级的对象所调用,那么this指向的就是上一级的对象。
  • 情况3:如果一个函数中有this,这个函数被多个对象包含,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象
  • this永远指向的是最后调用它的对象
  • 一句话:如果一个函数没有被一个对象所调用,那么它指向window。只有被对象所调用,才会指向对象

54,HTTP常见状态码

  • 302:临时重定向。展示最新的网页,但网址仍然是旧网址
  • 301:永久重定向。网页将永久转移到另一个网址上
  • 304:未修改
  • 401:未验证登录
  • 403:拒绝访问
  • 500:服务器错误
  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cheng Lucky

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值