2021前端面试题

  • 基础知识与素养
  • JS基本功训练与思考
  • 程序设计的渗透与应用
  • 业务技巧的积累与训练
  • 生产力转换
  • 项目的组织架构
  • 转换专业人才的全面生产力

什么样的技术水平决定了你应该学习什么样的知识与技术,什么样的知识与技术水平决定了你到什么样的公司,到什么样的公司决定了你在什么样社会层次,什么样的社会层次决定了你的眼界与发展的高度。

试题来源

一 面试题:

0、*浮动的影响

① 浮动元素不占位,脱离文档流,可以达到文字环绕的排版效果,也会引起标准流div被浮动元素遮挡
② 父元素高度塌陷

1、*BFC:解决因为浮动引起的问题 BFC

1)触发BFC的条件

① body元素
② float非none的
③ 绝对定位的(position:fixed/absolute)
④ display: flex/inline-block/table-cells
⑤ overflow非visible

2)BFC的特性

同一BFC内margin折叠

3)BFC的作用

① 清除浮动(解决父元素高度塌陷)
② 解决元素被浮动元素覆盖(可用于做左右两列布局,左宽度固定,右自适应)

2、*完整的web请求(返回了html)浏览器访问地址

3、*页面渲染HTML过程

在这里插入图片描述

4、*get、post请求的区别,解释get请求可以被缓存(浏览器决策)、不想缓存如何做:

1)在ajax发送请求前加上xmlHttpRequest.setRequestheader(‘Cache-Control’,“no-cache”) 或者请求头(“if-Modified-Since”:“0”)
2)在服务端加 header("cache-Control:no-cache,must-revalidate)
3)增加一个唯一值的参数:一般是使用timestamp = new Date().getTime() (推荐)
(场景:请求服务器资源,如下载文件,文件更新时)

5、下载文件,window.open、download属性依然不下载(必须同源)

6、反向代理是什么、作用

1)反向代理

反向代理(Reverse Proxy)方式是指:代理服务器来接受 Internet 上的连接请求,然后将请求转发给内部网络上的服务器,并将从内部网络上服务器得到的结果返回给 Internet 上请求连接的客户端。此时代理服务器对外就表现为一个服务器,反向代理服务器对于客户端而言它就像是原始服务器,并且客户端不需要进行任何特别的设置。
反向代理的作用:
保证内网的安全,可以使用反向代理提供 WAF 功能,阻止 web 攻击
负载均衡,通过反向代理服务器来优化网站的负载。

7、**vue项目性能优化(小野森森

  1. vue-for为什么要加key(更快定位数据与diff)
  2. 模块化、组件化(封装高度复用性的模块:http、拆分高度复用性的组件、组件可配置性强)
  3. 路由懒加载/动态加载组件 :首屏加快渲染
  4. productionSourceMap设置false:否则,生产map文件,打包后体积变大,且能定位源码(泄漏源码逻辑)【在bulid/config/index文件下】
  5. productionGzip设置true:gzip压缩、打包体积更小
  6. keep-alive:缓存组件,用keep-alive包裹router-view
  7. 插件CDN:vue-router、axios可以用link方式引入到html中,并在configureWebpack里注册,减少打包(也可以将这些js、css文件下载,放在自己的CDN、以防官方服务器挂了)
  8. 图片CDN、图片懒加载(vue-lazyLoad插件,v-lazy指令)、使用CSS图标(在main.js里全局引入iconfont字体图标)
  9. 组件按需导入: import { Button, Input } from ‘element-ui’

8、**webpack打包工具 (小野森森)【考配置流程、loader的作用】

1、作用①:压缩代码,混淆js代码;
2、作用②:浏览器不支持ES5以上的语法,webpack可以安装一系列依赖包将之翻译成ES5
3、作用③:将less、sass编译成css
4、所需依赖:

  1. 【三大件】webpack、webpack-cli(脚手架)、webpack-dev-server(开发者服务器插件)
  2. 【六件套】处理ES6 ES7… 装饰器:
    . babel-loader@7、babel-core、babel-preset-env
    . babel-plugin-transform-runtime
    . babel-plugin-transform-decorators、 babel-plugin-transform-decorators-legacy
  3. 【四大件】处理样式sass:
    . sass-loader、node-sass、css-loader、style-loader ( postcss-loader autoprefixer )
  4. 处理模板:ejs-loader
  5. 处理HTML: html-webpack-plugin

5、安装指令:

  • –save-dev 简写 -D (安装在开发环境下的,线上不跑)
  • –save 简写 -S (安装在生成环境下的)

6、配置安装包 webpack.config文件
特*:所有plugin结尾的依赖,一般要require导入、babel则不用
plugins: [ new HtmlWebpackPlugin( { } ) ]
7、 用命令跑配置文件webpack.config,在package.json的script里(跑脚本)

9、***Promise(小野森森

引子:一个高阶函数(参数里有函数),返回一个fn,在fn里有条件的执行回调方法(闭包)

const doSth = (t) => {
    return () => {
        if (--t === 0) {
            print1(() => {
                print2(() => {
                    print3()
                })
            })
        }
    }
}
const print1 = (cb) => {
    console.log('第一次打印')
    // 打印出这句话后执行cb
    cb()
}
const print2 = (cb) => {
    console.log('第二次打印')
    cb()
}
const print3 = () => {
    console.log('第三次打印')
}
const fn = doSth(3, print1)
fn()
fn()
fn()

1. 基本

目的:需要处理异步请求的嵌套,比如,先根据接口判断是否重复,拿到res后再进行下一次请求
① Promise是解决异步流程化的手段,Promise不是异步
② Promise是构造函数,需要new
③ Promise的唯一参数,executor函数,有参数resolve、reject
executor在new Promise的时候调用
⑤ executor是同步执行的,而then是异步调用的
⑥ 每个返回的Promise都有一个then方法,方法有2个回调函数cb,第一个cb的参数需由resolve执行时传入,resolve时执行第一个cb,reject时执行第二个cb
没有第二个callback的时候可以通过.catch,优先走then里的第二个cb,且无论是第几个then,总是优先于catch
⑧ reject能做的,throw new Error也可以
⑨ 每个then可以再继续.then下去 (在第一个Promise里返回Promise)

⑤ ↓

let promise = new Promise((resolve, reject) => {
    console.log(1)
    reject(3)
})
promise.then((res) => {
    console.log('打印', res)
}, (err) => {
    console.log(err)
})
console.log(2)
// 打印 1 2 3

⑥ ↓

let promise = new Promise((resolve, reject) => {
    resolve('结果')
})
promise.then((err) => {
    console.log('打印', err)
})
// 打印 结果
let promise = new Promise((resolve, reject) => {
    reject('服务异常')
})
promise.then((res) => {
    console.log('打印', res)
}, (err) => {
    console.log(err)
})
// 服务异常

⑦ ↓

let promise = new Promise((resolve, reject) => {
    reject('服务异常')
})
promise.then().catch((err) => {
    console.log(err)
})
// 服务异常
let promise = new Promise((resolve, reject) => {
    reject('服务异常')
})
promise.then(() => { }, (err) => {
    console.log('优先then', err)
}).catch((res) => {
    console.log(res)
})
// 优先then 服务异常
let promise = new Promise((resolve, reject) => {
    reject('服务异常')
})
promise.then(() => { }).then().then(() => { }, (err) => {
    console.log('无论第几个then,总是优先', err)
}).catch((res) => {
    console.log(res)
})
// 无论第几个then,总是优先 服务异常

⑧ ↓

let promise = new Promise((resolve, reject) => {
    throw new Error('抛出错误')
})
promise.then(() => { }).then().then(() => { }, (err) => {
    console.log('无论第几个then,总是优先', err)
}).catch((err) => {
    console.log(err)
})
let promise = new Promise((resolve, reject) => {
    throw new Error('抛出错误')
})
promise.then(() => { }).catch((err) => {
    console.log(err)
})

在这里插入图片描述
⑨ ↓

let promise = new Promise((resolve, reject) => {
    resolve('结果1')
})
promise.then((res) => {
    console.log('打印', res)
    return new Promise((resolve, reject) => {
        resolve('结果2')
    })
}).then((res) => {
    console.log('打印', res)
})
// 打印 结果1
// 打印 结果2

2. 语法糖Promise.resolve Promise.reject

相当于是 new Promise(…)

let promise = new Promise((resolve, reject) => {
    resolve('结果1')
})
promise.then((res) => {
    console.log('打印', res)
    return Promise.resolve('成功啦')
}).then((res) => {
    console.log(res)
})
// 打印 结果1
// 成功啦

3. Promise.all(通常用于等待多个异步任务完成)

① Promise.all接收iterable类型数据(如Array、Set、Map),数据的每一项可以是Promise也可以不是
② 返回值是Promise,因此可以.then。 如果resolve,则将iterable的每个Promise resolve的data依次放入数组
若参数为空数组,返回空数组
只要其中一个Promise的状态rejected了,整个Promise.all的状态便rejected,失败的原因是第一个失败的Promise的结果
⑤ 使用场景:一个页面初始化需要请求多个接口,只要任何一个接口失败,便认为初始化是失败的,需要重新请求

4. Promise.race

① 谁先完成,就只返回那个Promise的结果,且无论成功或失败,都会返回
② 若参数为空数组,Promise.race的结果永远处于pending状态,看起来是什么都没返回
③ 可以比较资源或接口的响应速度

5. async、await

① await是一个操作符,她等待一个Promise对象产出结果,如果这个结果是rejected,就会抛出异常
② async函数返回一个pending状态,这本身并没有什么意义

10、***函数防抖与节流小野森森

1、函数防抖

1)含义:

① 延迟执行(时间被触发n秒后再执行的回调)
② 如果在n秒内再次触发,则重新开始计时

2)场景:

① ajax请求数据(比如下拉刷新、首次延迟)
② ajax提交数据(提交、支付等按钮重复点击、首次不延迟)
③ 表单校验(input输入时,延迟验证,首次也延迟)否则可能无法得到校验通过的结果

3)实现:

① clearTimeOut的返回值是计时器id,此时t还有值 只有t = null,t才会变成null
② 这里不要乱用箭头函数
③ 不要debugger调试
④ 思路:考虑首次不延迟的情况→没有定时器则为首次,因此time后要t = null
(time内频繁触发,计时器会频繁重新开始计时)

domObj.onclick = debounce(myFn)
const myClick = () => {
    console.log('tag', Date.now())
}
var debounce = function (fn, time, triggleNow) {
    var t = null // 只有第一次点击会走这里
    var debounced = function () {
        var _self = this,
            args = arguments;
        if (t) {
            console.log('t0', t)
            clearTimeout(t)
            // 清除定时器后,t的值还在 
            // 除非赋值null,否则随着点击次数而增加
        }
        console.log('t1', t)
        if (triggleNow) {
            var exec = !t
            console.log('t2', t)
            t = setTimeout(function () {
                t = null
            }, time)
            // 到这里 t必有id
            console.log('t3', t)
            if (exec) {
                fn.apply(_self, args)
            }
        } else {
            console.log('t4', t)
            t = setTimeout(function () {
                fn.apply(_self, args)
            }, time)
        }
    }
    debounced.remove = function () {
        clearTimeout(t)
        t = null
    }
    return debounced

}
const box = document.getElementsByClassName('box')[0]
box.onclick = debounce(myClick, 1000, true)

表单输入

const oInput = document.getElementById('input')
const myCheck = function () {
    var val = this.value
    if (val.length < 6) {
        console.log('校验失败')
    } else {
        console.log('校验成功')
    }
}
oInput.onkeyup = debounce(myCheck, 1000, true)
// 只会打印校验失败,之后即使长度满足了,由于在time内频繁键入,也不会再触发了

若函数有返回值

var debounce = function (fn, time, triggleNow) {
    var t = null,
        res
    // console.log('t', t)
    // time内多次点击,只有初次会走这里
    var debounced = function () {
        var _self = this,
            args = arguments;
        if (t) {
            console.log('t0', t)
            clearTimeout(t)
            // 清除定时器后,t的值还在 
            // 除非赋值null,否则随着点击次数而增加
        }
        console.log('t1', t)
        if (triggleNow) {
            var exec = !t
            console.log('t2', t)
            t = setTimeout(function () {
                t = null
            }, time)
            // 到这里 t必有id
            console.log('t3', t)
            if (exec) {
                res = fn.apply(_self, args)
            }
        } else {
            console.log('t4', t)
            t = setTimeout(function () {
                res = fn.apply(_self, args)
            }, time)
        }
        return res // 假若函数有返回值
    }
    debounced.remove = function () {
        clearTimeout(t)
        t = null
    }
    return debounced

}

2、 函数节流

1)含义场景:

事件被触发、n秒内只且必执行一次事件处理函数 ,可用于输入验证、ajax提交

2) 实现:
function throttle(fn, delay) {
    // 闭包
    var t = null,
        begin = new Date().getTime()
    return function () {
        var _self = this,
            args = arguments,
            cur = new Date().getTime()
        clearTimeout(t)
        if (cur - begin >= delay) {
            console.log(1)// 隔了很久后再在原来基础上输入,会先走1,再走2
            fn.apply(_self, args)
            begin = cur
        } else {
            console.log(2)
            t = setTimeout(function () {
                fn.apply(_self, args)
            }, delay)
        }
    }
}

对比:
n秒内频繁触发,永远不让执行,用函数防抖
n秒内频繁触发,有且执行一次,用函数节流

11、 事件循环

① 消息队列/任务队列/事件队列是一样的,即异步任务相关的队列(先进先出/排队)
② 异步任务有:(队列中的消息对应着事件,因此叫事件循环,循环读取消息队列)

  1. 普通事件:click、resize → DOM操作对应DOM事件
  2. 资源加载:load、error → 资源加载操作对应加载事件
  3. 定时器:setInterval、setTimeout

③ 详细步骤:

  1. 所有同步任务都在主线程上执行,形成一个执行栈
  2. 主线程之外,还存在一个"消息队列"。只要异步操作执行完成,就到消息队列中排队
  3. 一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取消息队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行
  4. 主线程不断重复上面的第三步

从代码执行顺序的角度来看,程序最开始是按代码顺序执行代码的,遇到同步任务,立刻执行;遇到异步任务,则只是调用异步函数发起异步请求。此时,异步任务开始执行异步操作,执行完成后到消息队列中排队。程序按照代码顺序执行完毕后,查询消息队列中是否有等待的消息。如果有,则按照次序从消息队列中把消息放到执行栈中执行。执行完毕后,再从消息队列中获取消息,再执行,不断重复。

12、宏任务、微任务

① 微任务早于宏任务
② 多个定时器(内含同步、微任务),按定时器顺序完整执行完
在这里插入图片描述

13、this指向

1:this永远指向一个对象;
2:this的指向完全取决于函数调用的位置
针对以上的第一点特别好理解,不管在什么地方使用this,它必然会指向某个对象;确定了第一点后,也引出了一个问题,就是this使用的地方到底在哪里,而第二点就解释了这个问题,但关键是在JavaScript语言之中,一切皆对象,运行环境也是对象,所以函数都是在某个对象下运行,而this就是函数运行时所在的对象(环境)。

11、****设计模式

1)单例模式

12、***原型链

13、***闭包

14、****事件循环

15、**vue路由模式、前端单页面路由跳转实现的原理是什么

1、Vue模板编译(小野森森

11、Vue2、3的区别(小野森森

  1. vue2.0:options API (低内聚)
  2. vue3.0:可以将方法提出来
    在这里插入图片描述

12、**call、bind、apply

  • 改变this指向(第一个参数)
  • 只有applay的参数是数组
  • 只有bind返回的是函数
    案例
const doSth = (t, cb) => {
    return () => {
        if (--t === 0) {
            cb()
        }
    }
}
const print1 = (cb) => {
    console.log('第一次打印')
    // 打印出这句话后执行cb
    cb()
}
const fn = doSth(3, print1)
fn()
fn()
fn()
const doSth = (t, cb) => {
    return () => {
        if (--t === 0) {
            cb()
        }
    }
}
const print1 = (cb) => {
    console.log('第一次打印')
    // 打印出这句话后执行cb
    cb()
}
const print2 = (cb) => {
    console.log('第二次打印')
    cb()
}
const fn = doSth(3, print1.bind(null, print2))
fn()
fn()
fn()

13、401:没有提供认证信息。请求的时候没有带上 Token 等

  1. 预编译、作用域、闭包
  2. 内容字数位置,宽度高度不定,只展示2行,多余内容…
  3. 中断ajax请求(超时、手动中断)后端响应超时:吉行无忧
  4. 事件代理的使用场景
  5. vue核心功能

微信网页版:Http 请求报文头部信息,其中 Connection: keep-alive 意味着这次请求结束后不会关闭 TCP 连接

待续…

es6程序设计
websocket
面试题
vue3.0+ts
响应式布局
vue3.0星座项目
使用开发者工具

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值