前端面试题(三)

写在前面

  • 本面试题是本人在工作和找工作中总结出来的面试题,不代表行业通用标准。
  • 本文只关注技术相关问题
  • 问的问题更偏向于前端深入了解、性能优化、故障定位等。
  • 面试题难度大致相当于前端4-5年经验的水平
  • 部分与我另一篇博客相同或类似,但毕竟随着成长以及技术的发展重视的东西也在改变。
  • 答案仅供参考,不一定正确和完整,有异议或建议可提出修改

缓存

  1. 怎么设置静态资源缓存时间
   1. 设置expires属性
   2. 设置cache-control: max-age=毫秒
  1. 浏览器今天请求了静态文件,如果文件设置一个月缓存,明天再访问,会不会发起网络请求
	1. 主流浏览器会根据最近一次访问时间,减去last modify,再除以十,来决定对这个文件保存多久。也即 lastVisitTime + (lastVisitTime - lastModifyTime) / 10。在这个时间之前不会发起网络请求
	2. 在这之后会发起带 If-Modified-Since 的http请求。
	3. 之所以这么设置,是因为如果文件很久没修改了,说明比较稳定。
	4. 查到的答案,未实践,详见https://blog.csdn.net/youbl/article/details/84879670
  1. 服务端怎么判断要不要返回304
	1. 根据etag比对和last modify时间(追问:etag是什么——文件内容哈希)
	2. 根据 If-Modified-Since 判断

网络协议

  1. http2.0有什么新特性
	1. 管道复用
	2. 头部压缩
	3. 服务端推送
	4. 二进制帧
  1. TCP三次握手
	详见 https://blog.csdn.net/sysuzjz/article/details/79545321 三次握手部分
  1. HTTPS交换密钥过程
  1. TCP握手(HTTPS基于HTTP,即基于TCP)
  2. 客户端预请求,将支持的加密算法、版本等信息发给服务端
  3. 服务端将自己的配置、证书发给客户端
  4. 客户端检验证书(是否有效,是否篡改,是否吊销等)。提取服务端公钥
  5. 客户端生成随机数(对称密钥),用服务端公钥加密发送给服务端
  6. 服务端根据自己的私钥解密得到对称密钥
  7. 用对称密钥发送finish信息,完成密钥交换
  8. 用对称密钥完成传递内容的加密
  1. HTTPS证书包含什么内容
  1. 公钥(Public Key)
  2. ISSUER(证书的发布机构)
  3. Subject(证书持有者)(含使用域名)
  4. 证书有效期
  5. 签名
  1. 如何校验证书是否被篡改
  1. 客户端预先下载根证书(权威CA机构的公钥)
  2. 用CA公钥解开证书签名,得到指纹(哈希)和指纹算法
  3. 用指纹算法对证书内容进行哈希计算
  4. 哈希计算出来的结果与指纹进行对比,不一致则为被篡改
  1. 如何用UDP实现可靠传输
   1. 引入序列号, 保证数据顺序;
   2. 引入确认应答, 确保对端收到了数据;
   3. 引入超时重传, 如果隔一段时间没有应答, 就重发数据

性能相关

脚本在head里加载没完成之前,dom会渲染吗
domready和onload区别
http1.0/1.1和http2.0在优化上有什么区别
link预请求

框架

react和vue有什么区别
react单向数据流与vue双向绑定孰优孰劣
react hooks 相比 class api有什么优缺点
react hooks没法实现class的什么功能
react 生命周期有哪些?(旧版和新版)
vue导航守卫

后端

缓存策略
ssr

可用性

监控哪些类型错误
怎么监控脚本错误
怎么监控资源加载错误
怎么监控接口错误

安全

csrf是什么
csrf如何防御

实现深拷贝(需要考虑value用到同一个对象的问题)

function deepCopy(obj) {
    const valueMap = new Map();
    function copy(obj) {
        if (valueMap.get(obj)) {
            return valueMap.get(obj);
        }
        if (Array.isArray(obj)) {
            const temp = [];
            for (let i = 0; i < obj.length; i++) {
                temp[i] = deepCopy(obj[i]);
            }
            valueMap.set(obj, temp);
            return temp;
        }

        if (Object.prototype.toString.call(obj) === '[object Object]') {
            const temp = {};
            Object.keys(obj).forEach(key => {
                temp[key] = deepCopy(obj[key]);
            })
            valueMap.set(obj, temp);
            return temp;
        }
        return obj;
    }
    const result = copy(obj);
    valueMap.clear();
    return result;
}
const a = { b: 1 }
const obj = {
    a1: a,
    a2: a,
}
const copyedObj = deepCopy(obj);
console.log(copyedObj === obj)

按顺序输出:

async function async1() {
  console.log('async1 start');
  await async2();
  console.log('async1 end');
}

async function async2() {
  console.log('async2');
}

console.log('script start');

setTimeout(function() {
    console.log('setTimeout');
}, 0);  

async1();

new Promise(function(resolve) {
    console.log('promise1');
    resolve();
  }).then(function() {
    console.log('promise2');
});

console.log('script end');

编程

批量请求

请实现如下的函数,可以批量请求数据,所有的 URL 地址在 urls 参数中,同时可以通过 max 参数控制请求的并发度,当所有请求结束之后,需要执行 callback 回掉函数。发请求的函数可以直接使用 fetch 即可

function sendRequet(urls: string[], max: number, callback: () => void) {

}
function fetch(url) {
    return new Promise();
}

function sendRequet(urls: string[], max: number, callback: () => void) {
    if (!urls.length) {
        callback();
    }
    let sendingRequestNum = 0;
    let currentUrlIndex = 0;
    let hasSendRequestNum = 0;
    function checkQueneIsIdleAndSend() {
        if (hasSendRequestNum === urls.length) {
            callback();
        }
        if (sendingRequestNum === max) {
            return;
        }
        for (let i = currentUrlIndex; i < currentUrlIndex + max - sendingRequestNum; i++) {
            if (i >= urls.length) {
                return;
            }
            sendingRequestNum++;
            currentUrlIndex++;
            fetch(urls[i]).finally(() => {
                sendingRequestNum--;
                hasSendRequestNum++;
                checkQueneIsIdleAndSend();
            })
        }
        
    }
    checkQueneIsIdleAndSend();
}

连续数字区间

给定一个升序整形数组[0,1,2,4,5,7,13,15,16],找出其中连续出现的数字区间为如下:[“0->2”, “4->5”, “7”, “13”, “15->16”]

function summaryRanges(arr) {
    if (!arr.length) {
        return [];
    }
    let left = 0, right = 0;
    const result = [];
    while(left < arr.length) {
        while (right < arr.length - 1 && arr[right + 1] - arr[right] <= 1) {
            right++;
        }
        if (arr[left] === arr[right]) {
            result.push(arr[left]);
        } else {
            result.push(`${arr[left]}->${arr[right]}`);
        }
        left = right + 1;
        right = left;
    }
    return result;
}
console.log(summaryRanges([0,1,2,4,5,7,13,15,16,16, 18]))

斜45度打印二维矩阵

对于一般的m * n矩阵a
第一条45度斜边:a0
第二条45度斜边:a0, a1
………
最后一条45度斜边:am - 1
例如:

input = [[ 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10],
[11, 12, 13, 14, 15]]
output = 1, 2, 6, 3, 7, 11, 4, 8, 12, 5, 9, 13, 10, 14, 15

function logSquare(arr) {
    if (!arr || !arr.length || !arr[0].length) {
        return [];
    }
    const cols = arr[0].length,
        rows = arr.length;
    let col = 0, row = 0;
    const result = [];
    function loop() {
        for (let i = col; i < cols; i++) {
            for (j = row; j < rows; j++) {
                if (i - j + row < 0) {
                    continue;
                }
                result.push(arr[j][i - j + row]);
            }
        }
    }
    while (row < rows) {
        loop();
        row++;
        col = cols - 1;
    }
    
    return result;
}

字符串转二维数组

var strInput = `
1  2 3  
  4  5   6
7 8        9   
`
var arrResult = [
    [1,2,3],
    [4,5,6],
    [7,8,9]
]
function strToArr(str) {
    if (!str) {
        return [];
    }
    return str.split('\n')
        .filter(row => row && row.trim())
        .map(row => {
            return row.trim().split(/\s+/g);
        })
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值