摘要:本篇分享了10道面试题——四道算法题、判断两个对象是否相等、JS数组模拟队列、SSR服务端渲染、封装WebSocket、封装图片上传功能、浏览器缓存机制。
面试题
1、无重复字符的最长子串
需求:给定一个字符串(由英文字母、数字、符号和空格组成),请你找出其中不含有重复字符的最长子串的长度。
示例:输入s = "abcabcbb"
,输出为 3
。因为无重复字符的最长子串是 "abc",所以其长度为 3。
function maxSubString (s) {
let map = new Map(), max = 0
for(let i = 0, j = 0; j < s.length; j++) {
if(map.has(s[j])) {
i = Math.max(map.get(s[j]) + 1, i)
}
max = Math.max(max, j - i + 1)
map.set(s[j], j)
}
return max
}
// 测试
maxSubString("abcabcbb") // 3
2、求两个矩形重叠面积的大小。
需求:在二维平面上,求四组坐标构成的两个矩形所重叠的面积大小。
示例:输入[-3, 0, 3, 4, 0, -1, 9, 2]
,输出 6
(即重叠的面积大小为 6),图解如下。
function overlapArea([x1, y1, x2, y2, x3, y3, x4, y4]) {
let min = Math.min
let max = Math.max
// 记录矩形的右上角点、左下角点
let [Ax,Bx] = [min(x1,x2), max(x1,x2)]
let [Ay,By] = [min(y1,y2), max(y1,y2)]
let [Cx,Dx] = [min(x3,x4), max(x3,x4)]
let [Cy,Dy] = [min(y3,y4), max(y3,y4)]
console.log(Ax, Ay, Bx, By, Cx, Cy, Dx, Dy)
let w = 0
let h = 0
if(!(Cy>=By || Dy<=Ay || Dx<=Ax || Cx>=Bx)) {
console.log('两矩形重合')
if(Cx>Ax) w = Bx-Cx
if(Dx<Bx) w = Dx-Ax
if(Ax>Cx && Bx<Dx) w = Bx-Ax
if (Cx>Ax && Dx<Bx) w = Dx-Cx
if(Cy<By) h = By-Cy
if(Dy>Ay) h = Dy-Ay
if(Dy>By && Cy<Ay) h = By-Ay
if(By>Dy && Ay<Cy) h = Dy-Cy
}
return w*h
}
// 测试
overlapArea([-3, -3, 10, -1, 9, 2, 0, -1]) // 0,两矩形不重合
overlapArea([-3, 0, 3, 4, 0, -1, 9, 2]) // 6,两矩形重合
3、求两个非负数的最大公约数。
function divisor(a,b) {
for(i=a;i>0;i--){
if(a%i==0){
if(b%i==0){
return i
}
}
}
}
// 测试一下
divisor(512,768) // 256
4、封装洗牌算法。
function shuffle(arr) {
let m = arr.length
while (m){
let index = Math.floor(Math.random() * m--)
let cur = arr[m]
arr[m] = arr[index]
arr[index] = cur
}
return arr
}
// 测试一下
shuffle([1,2,3,4,5,6])
5、封装方法 判断两个元素是否相等。
function isObject(obj) {
return obj !== null && typeof obj === 'object'
}
function looseEqual(a, b) {
if (a === b) { return true }
var isObjectA = isObject(a);
var isObjectB = isObject(b);
if (isObjectA && isObjectB) {
try {
var isArrayA = Array.isArray(a);
var isArrayB = Array.isArray(b);
if (isArrayA && isArrayB) {
return a.length === b.length && a.every(function (e, i) {
return looseEqual(e, b[i])
})
} else if (a instanceof Date && b instanceof Date) {
return a.getTime() === b.getTime()
} else if (!isArrayA && !isArrayB) {
var keysA = Object.keys(a);
var keysB = Object.keys(b);
return keysA.length === keysB.length && keysA.every(function (key) {
return looseEqual(a[key], b[key])
})
} else {
return false
}
} catch (e) {
return false
}
} else if (!isObjectA && !isObjectB) {
return String(a) === String(b)
} else {
return false
}
}
// 测试一下
looseEqual(1,1) // true
looseEqual([1],[1]) // true
looseEqual({a:1},{a:1}) // true
looseEqual({a:1},{a:2}) // false
6、实现先进先出队列
需求:最多使用两个栈,实现先进先出队列,并支持以下操作:
- void push(int x) 将元素 x 推到队列的末尾
- int pop() 从队列的开头移除并返回这个元素
- int peek() 不改变队列,只返回队列开头的元素
- boolean empty() 如果队列为空返回 true ;否则返回 false
var MyQueue = function() {
this.inStack = []
this.outStack = []
}
MyQueue.prototype.push = function(x) {
this.inStack.push(x)
}
MyQueue.prototype.pop = function() {
if (!this.outStack.length) {
this.in2out()
}
return this.outStack.pop()
}
MyQueue.prototype.peek = function() {
if (!this.outStack.length) {
this.in2out()
}
return this.outStack[this.outStack.length - 1]
}
MyQueue.prototype.empty = function() {
return this.outStack.length === 0 && this.inStack.length === 0
}
MyQueue.prototype.in2out = function() {
while (this.inStack.length) {
this.outStack.push(this.inStack.pop())
}
}
// 测试
var queue = new MyQueue()
queue.push(1) // [1]
queue.push(2) // [1,2]
queue.push(3) // [1,2,3]
queue.pop() // [2,3]
queue.peek() // 2
queue.empty() // false
7、理解服务端渲染。
题目:什么是服务端渲染?SSR、BSR各有什么优势和劣势?有哪些SEO策略?
8、原生封装 WebSocket。
const socket = new WebSocket('ws://localhost:8080')
socket.addEventListener('open', function (event) {
socket.send('Hello Server!')
})
socket.addEventListener('message', function (event) {
console.log('Message from server ', event.data)
})
9、原生封装图片上传方法。
function upload(option) {
if (typeof XMLHttpRequest === 'undefined') {
return;
}
const xhr = new XMLHttpRequest();
const action = option.action;
if (xhr.upload) {
xhr.upload.onprogress = function progress(e) {
if (e.total > 0) {
e.percent = e.loaded / e.total * 100;
}
option.onProgress(e);
};
}
const formData = new FormData();
if (option.data) {
Object.keys(option.data).forEach(key => {
formData.append(key, option.data[key]);
});
}
formData.append(option.filename, option.file, option.file.name);
xhr.onerror = function error(e) {
option.onError(e);
};
xhr.onload = function onload() {
if (xhr.status < 200 || xhr.status >= 300) {
return option.onError(getError(action, option, xhr));
}
option.onSuccess(getBody(xhr));
};
xhr.open('post', action, true);
if (option.withCredentials && 'withCredentials' in xhr) {
xhr.withCredentials = true;
}
const headers = option.headers || {};
for (let item in headers) {
if (headers.hasOwnProperty(item) && headers[item] !== null) {
xhr.setRequestHeader(item, headers[item]);
}
}
xhr.send(formData);
return xhr;
}
10、谈一谈浏览器的缓存机制。
浏览器缓存机制本周结束,下周继续!!!
网友评论