2021年前端基础面试题 18 额外一些面试真题

typeOf 返回的数据类型有哪些
手写深度比较函数,模拟lodash的 isEqual()
string.split()和arr.jion()的区别
数组中哪些方法是纯函数,哪些是非纯函数
数组中的splice和slice的区别,splice会改变原数组的值

网红题目 [1,2,3].map(parseInt) // [1,NaN,NaN]

原因: parseInt(17,2) // NaN, 因为parseInt的第个参数进制基数radix必须是10、8、16、2 parseInt(10,2) // 2
parseInt(10,8) // 8
parseInt(10,16) //16

let a = function(){} 和 function a(){} 的区别

let a是函数表达式,function a是函数声明,函数声明可以在代码执行前预加载,所以在function a上面执行 a()不会报错;

new Object()和 Object.create()的区别

new Object() 等于 let a = {}, 它是有原型属性的 而Object.create()参数中可以指定原型对象,所以当传入null的时候,例如Object.create(null) 它是没有原型属性的。

异步操作的相关题目

let i 
for(i = 1; i<=3; i++){
    setTimeout(function(){
       console.log(i)
    })
} 
// 4 4 4 

解释如果不使用setTimeout结果是 1 2 3,用了之后则会先执行同步任务的for循环,结束之后i的值为4,因为循环了3次,webApi中会往事件队列中放入3个function,所以打印了3次i

作用域相关题目

let a = 100
function test(){
    alert(a)
    a = 10
    alert(a)
}
test()
alert(a)
// 100 10 10

捕获错误的2种方式 try catch和window.onerror

获取url参数的2种方式

老:location.search // '?a=1&b=2' 需要自己实现个方法去获取对应的参数 新:URLSearchParams
let params = new URLSearchParams(location.search)
console.log(params.get('a'))

将url参数解析为js对象

function queryToObj(){
    const res = {}
    cosnt pList new URLSearchParams(location.search)
    pList.forEach((val,key)=>{
        res[key] = val
    })
    return res
}

数组拍平
数组去重
手写深拷贝

RAF( window.requestAnimationFrame)

可以让动画更流畅,比setTimeout更适合做动画,自动控制频率,dom隐藏或窗口切换后会暂停,性能更好 比如我们要做60帧的动画,1秒要用setTimeout执行60次

2021年前端基础面试题 16-17 运行环境、性能和安全

16 运行环境、性能和安全

XSS/XSRF 攻击

预防XSS:替换特殊字符,如< 变为< 可以通过xss工具 npm i xss


17 性能优化

提升加载速度

减少资源体积(压缩代码)
减少访问次数(合并代码、SSR、缓存)
使用更快的网络(CDN)

提升渲染速度

CSS放在header内,js放在body最下面
尽早开始执行js,用DOMContentLoaded触发
懒加载
对dom查询进行缓存
频繁的dom操作合并到一起后统一插入
节流和防抖

页面加载过程

DNS(domain name server) 解析: 域名 – ip
HTTP
生成DOM Tree
生成CSSOM
整合DOM Tree和CSSOM合成Render Tree
遇到script暂停渲染,完成后继续
图片加载不会阻塞render tree

window.addEventListener('load') // 页面全部加载完成后触发,包括图片和视频
window.addEventListener('DOMContentLoaded') //Dom渲染完之后触发,无需等待图片和视频

图片懒加载的方式

将图片地址先写死一个预览的小图地址,而真实的图片地址可以放在例如data-relasrc属性中,当屏幕滚动到需要显示这个图片的位置时,替换src



2021年前端基础面试题 15 开发环境

git使用

假如在a分支上不小心修改了很多文件后发现其实应该在b分支上修改,这时直接切换分支已经不行了,注意新建的文件m不受影响。
可以先执行git stash把已修改的文件暂存起来。切换到b分支后再执行git stash pop把文件取出来

charles使用

手机抓包的过程

webpack

如何创建开发环境和生成环境2套配置
使用模板插件,配置不同的loader,生产环境的文件名[contenthash]

babel

基本的es6转es5配置,使用预设插件

Liunx

mkdir //创建文件夹
touch a.js //新建文件
open . // 打开当前目录
ls ll //显示当前目录下的文件列表
cat index.html //把文件内容打印到控制台
rm -rf abc (r= recurrence f= force) //递归强制删除目录
mv a.html b.txt //修改文件名, 或者移动文件到目标文件夹
cp a.js b.js //拷贝
vimtutor //系统自带的vim教程

2021年前端基础面试题 13-14 存储和http

3种存储

cookie 主要是设计用来做server和浏览器通讯,所以并不适合做本地存储
缺点:最大容量4k,每次http请求都会带上,使用document.cookie =”方式修改!api太简陋
localstorage 和 sessionstorage 每个域名最大5m,不会放入hhtp请求中,使用setItem(使用方便

http状态码

1xx 服务端收到请求
2xx 请求成功
3xx 重定向
4xx 客户端错误
5xx 服务端错误

常见的状态码

200 成功
301 永久重定向
302 临时重定向
304 资源未被修改
404 未找到
403 无权限
500 错误
504 超时

http methods

get 查
post 增
patch put 改
delete 删

restful api

相对于传统的api设计, restful不会把url设计成一个功能,而是一个资源。
例如restful不使用url参数
api/list?index=2
api/list/2

常见的header

request header

accept 接受的数据格式
accept-encoding 接受的压缩格式如gzip
accept-language
connection keep-alive
cookie
host
user-agent
content-type application/json

response header

content-type application-json
content-length
content-encoding 服务器返回的压缩格式
set-cookie 服务器通过这个来设置cookie

http缓存

通常静态资源都会被缓存,比如js,css,images 。
为了避免静态资源被缓存通常在webpack打包时会在静态资源文件名后面加上hash字符串,例如index.3hjdjyu73hd8.js

强制缓存

服务器会在response header之中返回catch-control 来控制缓存的逻辑,例如max-age=3500000(秒)
no-catch 客户端无需缓存
no-store 客户端和服务器都不缓存,不常见
expires 是老标准,已经被catch-control取代

协商缓存

服务端判断请求的资源是否需要缓存,例如发现请求资源没有变化,则返回304告诉客户端无需请求。
服务端通过下发资源标识给客户端,客户端下次访问的时候带上资源标识返回给服务端。服务端再根据资源标识来判断此资源是否过期。
客户端下发资源标识分为两种:
last-modified 资源最后修改时间(秒)
e-tag 唯一标识 优先级最高
对应客户端请求的资源标识
if-modified-since
if-none-match

2021年前端基础面试题 12 AJAX

手写简易的ajax

const xhr = new XMLHttpRequest();
// method:要是用的HTTP方法,url:请求的主体,async(可选):false为同步,true为异步,默认为同步
xhr.open('GET', '/api', false);
xhr.onreadystatechange = function () {
    if (xhr.readyState === 4) {
        if (xhr.status === 200) {
            alert(xhr.responseText);
        };
    };
};
xhr.send(null); //如果请求方法是 GET 或者 HEAD,则应将请求主体设置为 null。

xhr.readyState

0 – (未初始化)还没有调用send()方法
1 – (载入) 已调用 send()方法,正在发送请求
2 – (载入完成) send()方法执行完成,已经接受到全部响应内容
3 – (交互)正在解析响应内容
4 – (完成)响应内容解析完成,可以在客户端调用

status 状态码

301 永久重定向
302 临时重定向
301表示旧地址A的资源已经被永久地移除了(这个资源不可访问了),搜索引擎在抓取新内容的同时也将旧的网址交换为重定向之后的网址;302表示旧地址A的资源还在(仍然可以访问),这个重定向只是临时地从旧地址A跳转到地址B,搜索引擎会抓取新的内容而保存旧的网址。

304 缓存
404 未找到
403 无权限
5xx 服务端报错

若想设置POST请求版,则需更改

xhr.open里的参数为xhr.open(‘POST’, url, true/false);
xhr.send里的参数为xhr.send(p);,

浏览器同源策略 协议 域名 端口 三者缺一不可

jsonp实现跨越
window.callback=fn
callback({data:1})

2021年前端基础面试题 9-11 DOM BOM

DOM (document object model)
BOM (browser object model)

DOM的数据结构是树型结构

attribute 是修改DOM标签,会改变HTML结构
P.setAttribute(‘style’,’width:100px’)
property 是修改Js对象,性能更好,推荐用这种方式
P.style.width =100px
2者都会触发DOM渲染

插入子节点

divEl.appendChild(P)
注意如果P存在,会变成移动节点

获取父节点

P.parentNode

获取子元素

divEl.childNodes
注意childNodes中会包含nodeType为3的text类型节点,需要过滤出nodeType等于1的b元素标签类型

nodeList转数组

Array.prototype.slice.call(NodeList)

删除子元素

divEl.removeChild(P1)

DOM操作性能优化注意点

将循环插入或修改DOM的操作放入一个临时片段中,遍历完成后再统一插入到容器节点中,说白了就是减少不必要的渲染次数。

判断ua的方法

这个自行在网络上搜索吧,可能随着技术更新每年都不一样

location属性

hash 设置或返回从井号 (#) 开始的 URL(锚)。
host 设置或返回主机名和当前 URL 的端口号。
hostname 设置或返回当前 URL 的主机名。
href 设置或返回完整的 URL。
pathname 设置或返回当前 URL 的路径部分。
port 设置或返回当前 URL 的端口号。
protocol 设置或返回当前 URL 的协议。
search 设置或返回从问号 (?) 开始的 URL(查询部分)。

History 对象属性

length 返回浏览器历史列表中的 URL 数量。

History 对象方法

back() 加载 history 列表中的前一个 URL。
forward() 加载 history 列表中的下一个 URL。
go() 加载 history 列表中的某个具体页面。

如何阻止超链接跳转 e.preventDefault
如何为下拉加载的图片列表添加点击事件, 事件代理

2021年前端基础面试题 8 异步编程

1. event loop 画图说明

  • JS 是单线程运行
  • 异步是基于回调来实现
  • event loop 就是异步回调的实现原理

Call Stack 同步代码

代码执行时放入Call Stack 执行完成后移出

Web APIs 浏览器的接口

setTimeout()是web Api的定时器方法,不是es6的语言
执行setTimeout时,将它放入Web APIs里面等待5秒,后面到第5秒出发时会放入Callback Queue

接下来执行第三行代码打印Bye,同样也是执行时放入Call Stack 执行后移出Call Stack,这时整个代码同步的部分都已经执行完了。

Event Loop 事件轮询

5秒后 Web APIs里面的回调函数被触发,将cb方法放入了 CallBack Queque队列中

Event Loop 轮询CallBack Queue 发现有cb() 则放入Call Stack中执行并移出

cb()方法中有console.log() 则先执行console.log 然后执行完移出,最终再把cb()移出

Promise相关

promise的三种状态

resolved只能触发then,reject只能触发catch,例如下面的代码

Promise.resolve(100).then(data=>{
    console.log(data) // 100
})

catch 中如果正常返回,则后续状态为resolved,否则为rejected

面试题:then和catch的链式调用

Promise.resolve().then(()=>{
    console.log(1) // 1 
    throw new Error('err') // then里面有报错会触发后续的catch
}).catch(()=>{
    console.log(2) // 2 // catch中没有报错会触发后续的then
}).then(()=>{
    console.log(3) // 3
})

async/await

!(async  function (){
await  1
})()

async 返回Promise
await 等于promise的then
await 200 等于 await Promise.resolve(200)

宏任务和微任务

宏任务:settimeout ajax dom事件
微任务:promise await
宏任务在dom渲染后执行,微任务反之
微任务是es6语法 不会放到webapi区域,所以先执行

2021年前端基础面试题 1-7

1 CSS

line-height 的继承机制
父元素行高20px:子元素行高直接继承20px
父元素2或者1.5:子元素行高就是font-size的2倍或者1.5倍
父元素200%:子元素行高是200%乘以父元素的font-size而不是乘子元素的font-size

flex画筛子三

box  {
    display: flex;
    justify-content: sapce-between;
}

item:nth-child(2)  {
    align-self :  center ;
}

item:nth-child(3){
    aligin-self:flex-end;
}

响应式布局

rem vw vh vmax vmin 通过媒体查询的方式动态的设置跟字体的大小

rem的计算机制

(N)rem = html的font-size *( N)

例1:

默认的html的font-size是16px,div的font-size设置为1rem就是16*1=16px
为了便于理解,我们用F表示html的font-size,用R表示rem,用P表示px。
从上面的结果就可以得到公式 P = F * R
F = 16px
R = 1
P = 16 *1
结果P就是16px

例2:

如果html的font-size设置为100px
目标像数要求为16px
那div的font-size设置0.16rem
rem就是目标像数除以根元素
得到公式 R = P / F (rem = 目标px / html的font-size)
第三个公式
F = P / R

2 JS

变量类型,事件机制

值类型,引用类型,手写深拷贝,事件冒泡,事件代理

原型、原型链 、类 、继承

画出原型链的类图,解释supper,es5继承方式

// 构造函数 
function Parent1(name) {
  this.name = name;
  this.age = 12;
}
function Child1() {
  Parent1.call(this,'son');
  this.type = 'child1';
}
console.log( new Child1().name); //son

闭包

作用域,自由变量,手写bind

Function.prototype.myBind = function (){
    const args = Array.prototype.slice.call(arguments)
    const t = args.shift() // 第一项为传入的this
    const that = this
    return function (){
        retrun that.apply(t, args)    
    }
}

实际的应用场景
隐藏数据,比如jquery的自定义事件也是这样隐藏对象数据,只暴露方法

事件流,事件循环

事件流分为3个阶段:
(1)捕获阶段:事件从Document节点自上而下向目标节点传播的阶段;
(2)目标阶段:真正的目标节点正在处理事件的阶段;
(3)冒泡阶段:事件从目标节点自下而上向Document节点传播的阶段。

webpack构建流程

初始化 – 配置
编译 – loader,plugin
输出 – chunk

数组求和

// Accumulator (acc) (累计器)
// Current Value (cur) (当前值)
// Current Index (idx) (当前索引)
// Source Array (src) (源数组)
var sum = [0, 1, 2, 3].reduce(function(accumulator, currentValue) {
  return accumulator + currentValue
}, 100) // 从100开始累加
console.log(sum) // 106

使用promise 封装一个图片加载的方法

function loadImg(src) {
    const p = new Promise(
        (resolve, reject) => {
            const img = document.createElement('img')
            img.onload = () => {
                resolve(img)
            }
            img.onerror = () => {
                const err = new Error('img load err' + src)
                reject(err)
            }
            img.src = src
        }
    )
    return p
}

const url1 = 'xxx1'
const url2 = 'xxx2'
loadImg(usr1).then(img1 => {
    console.log(img1.width)
    return img1
}).then(img1 => {
    console.log(img1.height)
    return loadImg(url2)

}).then(img2 => {
    console.log(img2.width)
})

for of 和for in forEach的区别

for of 可以处理异步的遍历

const nums = [1, 2, 3]

// 先遍历完数组,先执行3次异步调用
nums.forEach(async (i) => {
    const res = await getList(i)
    console.log(res)
})

// 遍历移数组一次,执行一次异步调用,返回结果后再遍历数组下一项
!(async function () {
    for (let i of nums) {
        const res = await getList(i)
        console.log(res)
    }
})()