HTTP
- 从“在浏览器输入域名”到“页面静态资源完全加载”的整个流程
- 讲一讲强缓存和协议缓存?
- 有了【Last-Modified,If-Modified-Since】为何还要有【ETag、If-None-Match】
- HTTP/2.0 都有哪些特性?头部压缩的原理?
- TCP三次握手和四次挥手?以其存在意义。
- 状态码。302.304.301.401.403的区别?
- 状态码。204和304分别有什么作用?
- HTTP和HTTPS握手差异?
- CSRF 跨站请求伪造和XSS 跨站脚本攻击是什么?
- 你是如何解决跨域的?都有几种?
- HTTP和TCP的区别
- HTTP/2对比HTTP1.1
- HTTP/2是怎么解决队头阻塞的
- HTTP/2是如何压缩头部的
- 为什么说HTTPS比HTTP安全呢
- HTTP请求的什么时候用的对称加密什么时候非对称加密
- 如果让你去实现一个CSRF攻击你会怎做?
- 如果使用jsonp的话会有什么安全问题吗?
- 假设有两个子项目,他们需要共用同一个用户体系如何保证关掉页面之后打开另一个项目用户还是登录状态?
- 有关HTTP缓存的首部字段说一下
- HTTP中的keep-alive有了解吗?
- 在一次传输中它是如何保证每个数据包之间的顺序的?
- 具体说一下HTTP/2中的多路复用
- GET和POST的区别
- 为什么说GET会留下历史记录?
- GET就一定是幂等的吗?
JS
- Promise实现
- Generator实现
- Async实现
- 垃圾回收中的堆和栈的区别。
- 0.1 + 0.2 != 0.3背后的原理?
- 手写vue2/3具体实现
- 手写继承
- requestAnimationFrame属于宏任务还是微任务
- 动态表单实现
- null为什么被typeof错误的判断为了'object'
Vue
- 双向绑定原理
- nextTick原理
- nextTick中的waiting是什么时候变为true的呢
- 虚拟DOM
- Object.defineProperty()有什么缺点?Vue3为什么用Proxy
- Vue3有哪些新的API或者有做哪些优化?
- 说一下Vue的diff算法
- diff算法的缺点
Devops
- webpack的构建流程、插件原理、打包原理,自定义loader,HMR的实现、常用的插件以及性能优化
- 单元测试做过吗?你是怎么做的?
书单
- 《Vue3 究竟好在哪里?(和 React Hook 的详细对比)》
- 《网络是怎样连接的》
- 《DevOps实战笔记》
- 《透视HTTP协议》
- 《浏览器原理》
- 《Nginx核心知识 100 讲》
代码实现
- 手写节流防抖
/**
* 节流
* @param {Func} callback 需要节流的函数
* @param {Number} wait 等待毫秒数
* 执行一次后,一段时间内不再执行
*/
function throttle(func, wait = 0) {
let timeoutId = null;
return function throttle_fn(...args) {
if (timeoutId === null) {
timeoutId = setTimeout(() => {
func.apply(this, args);
timeoutId = null;
}, wait);
}
};
}
/**
* 防抖
* @param {Func} callback 需要防抖的函数
* @param {Number} wait 等待毫秒数
* 一段时间内,取最后一次执行
*/
function debounce(func, wait = 0) {
let timeoutId = null
return function () {
if (timeoutId) {
clearTimeout(timeoutId)
}
timeoutId = setTimeout(() => {
func.apply(this, arguments)
}, wait)
}
}
- 圣杯与双飞翼布局
/** 圣杯 **/
<div class="wrapper1">
<div class="main">
<p>bilibili</p>
</div>
<div class="left"></div>
<div class="right"></div>
</div>
<style>
.wrapper1 {
padding: 0 60px 0 30px;
}
.wrapper1 .main {
float: left;
width: 100%;
height: 300px;
background: red;
}
.wrapper1 .left {
float: left;
width: 30px;
margin-left: -100%;
background: blue;
height: 100px;
position: relative;
right: 30px;
}
.wrapper1 .right {
float: left;
width: 60px;
margin-left: -60px;
background: yellow;
height: 200px;
position: relative;
left: 60px;
}
</style>
/** 双飞翼 **/
<div class="wrapper2">
<div class="container">
<div class="main">
<p>bilibili</p>
</div>
</div>
<div class="left"></div>
<div class="right"></div>
</div>
<style>
.wrapper2 {
min-width: 630px;
}
.wrapper2 .container {
float: left;
width: 100%;
}
.wrapper2 .container .main {
height: 300px;
background: red;
margin: 0 600px 0 30px;
}
.wrapper2 .left {
float: left;
width: 30px;
background: blue;
height: 100px;
margin-left: -100%;
}
.wrapper2 .right {
float: left;
width: 600px;
background: yellow;
height: 200px;
margin-left: -600px;
}
</style>
- 数组长度为5且元素的随机数在2-32间不重复的值
// 生成 [n,m] 的随机整数
const creatRandomNum = (min,max) => parseInt(Math.random()*(max-min+1)+min);
function arr5(arr=[]) {
if(arr.length >= 5){return arr};
arr = [...new Set([...arr, creatRandomNum(2,32)])];
return arr5(arr);
}
4.写一个获取当前url查询字符串中的参数的方法
const getUrlQuery = (url = location.href) => {
try {
return [...new URL(url).searchParams].reduce(
(pre, [key, value]) => Object.assign(pre, { key, value }),
{},
);
} catch {
throw new Error(`url格式不正确。url: ${url}`);
}
};
- html5中的form怎么关闭自动完成?
// 在 input 标签中,可以设置 autocomplete="off" 来关闭自动填充。
<form action="demo_form.html" method="get" autocomplete="off">
First name:<input type="text" name="fname"><br>
E-mail: <input type="email" name="email"><br>
<input type="submit">
</form>
1.script 同步下载,下载成功继续阻塞 DOM 的渲染,立即执行。
2. async异步下载,下载成功后阻塞 DOM 的渲染,立即执行。
3. defer异步加载,下载成功后等待文档加载,文档加载完成后执行。
4.async、defer这两个属性无法应用于内联script。
image
- 实现一个call / apply / bind
// call
Function.prototype._call = function (target=window, ...res) {
target._fun = this;
const ret = target._fun(...res);
delete target._fun;
return ret;
}
// apply
Function.prototype._apply = function (target=window, list=[]) {
target._fun = this;
const ret = target._fun(...list);
delete target._fun;
return ret;
}
// bind
Function.prototype._bind = function (target, ...res) {
if (typeof this !== 'function') {
throw new TypeError('Error')
}
const that = this;
const _func = function(...args) {
// 判断当前韩式是直接访问还是通过new进行构造
return that.apply(this instanceof _func ? this : target, res.concat(args));
}
// 添加一层原型,防止修改_func.prototype时影响到this.prototype
_func.prototype = Object.create(this.prototype);
return _func;
}
8.Object.create 的模拟实现
Object.create = function(target) {
function _func () {};
_func.prototype = target;
return new _func();
}
- instanceof模拟实现
function _instanceof(L,R){
L = L.__proto__;
while(true){
if(L === null) return false;
if(R.prototype === L) return true;
L = L.__proto__;
}
}
10.解释一个为什么10.toFixed(10)会报错?
/**
在我们的直觉上,10.toFixed(10) 是把整数的 10 转为浮点数并且保留 10 位小数部分。
但实际上会出错,是因为 JS 的解释器对 . 操作符产生了歧义。
在 JS 中 . 可以表示小数和从对象中取值。在这个例子中, 由于 10 是整数,
所以在 10. 默认是小数点,因此会报错。
**/
// 解决的办法有下面几种:
(10).toFixed(10) 个人喜欢这种,看起来舒服一点
10..toFixed(10)
11.将Object 与 Map 互转
var obj = { foo: "bar", baz: 42 };
var map = new Map(Object.entries(obj));// Map { foo: "bar", baz: 42 }
var obj2 = Object.fromEntries(map);// {foo: "bar", baz: 42}
12.寄生组合式继承
// 通过构造函数来继承实例属性,通过原型链的混成形式来继承原型方法
function clonePrototype(Super,Suber){
var prototype = Object.create(Super.prototype);
prototype.constructor = Suber;
Suber.prototype = prototype;
}
function Super(name){
this.name = name
this.like = ['sing','dance','rap','basketball']
}
Super.prototype.sayName=function(){
console.log(this.name)
}
function Suber(name,age){
Super.call(this,name) // 继承属性
this.age=age
}
clonePrototype(Super,Suber);
Suber.prototype.sayAge=function(){
console.log(this.age)
}
var sub1 = new Suber('sss',18);
console.log(sub1.name); // -> sss
sub1.sayName(); // -> sss
sub1.sayAge(); // -> 18
13.如何让 (a == 1 && a == 2 && a == 3) 的值为true?
var a = {
valueOf: (function () {
let i = 1;
//闭包的特性之一:i 不会被回收
return function () {
return i++;
}
})()
}
console.log(a == 1 && a == 2 && a == 3); // true
- JS 模块化
AMD: require.js 为代表,依赖前置,一律先加载再使用。
CMD: sea.js 为代表,依赖就近原则。
UMD: 兼容AMD和commonJS规范的同时,还兼容全局引用的方式。
ES6 import/export
15.你从未注意的隐藏危险: target = "_blank" 和 "opener"
// 最佳实践
<a href="https://an.evil.site" target="_blank"
rel="noopener noreferrer nofollow">
Enter an "evil" website
</a>
16.阶乘
function factorial(num, sum = 1) {
if(num <= 1)return sum;
sum *= num;
return factorial(--num, sum); // 尾递归
}
factorial(3) // -> 6
17.柯里化
const curry = (fn , args = []) => {
return (...rets) => {
const allArgs = args.concat(rets);
if(allArgs.length < fn.length) {
return curry(fn, allArgs);
} else {
return fn.apply(this, allArgs);
}
}
}
function multiFn(a, b, c) {
return a * b * c;
}
var multi = curry(multiFn);
multi(2)(3)(4);
multi(2,3,4);
multi(2)(3,4);
multi(2,3)(4);
18.「中高级前端面试」JavaScript手写代码无敌秘籍
- 实现一个Promise 《图解 Promise 实现原理》
// Promise 简单的实现
function Promise(excutor) {
this.callbacks = [];
function resolve(value) {
setTimeout(() => {
this.data = value;
this.callbacks.forEach((callback) => callback(value));
});
}
excutor(resolve.bind(this));
}
Promise.prototype.then = function (onResolved) {
return new Promise((resolve) => {
this.callbacks.push(() => {
const result = onResolved(this.data);
if (result instanceof Promise) {
result.then(resolve);
} else {
resolve(result);
}
});
});
};
// test
new Promise((resolve) => {
setTimeout(() => {
resolve(1);
}, 500);
})
.then((res) => {
console.log(res);
return new Promise((resolve) => {
setTimeout(() => {
resolve(2);
}, 500);
});
})
.then(console.log);
//Promise 完整的实现
class Promise {
callbacks = [];
state = 'pending';//增加状态
value = null;//保存结果
constructor(fn) {
fn(this._resolve.bind(this), this._reject.bind(this));
}
then(onFulfilled, onRejected) {
return new Promise((resolve, reject) => {
this._handle({
onFulfilled: onFulfilled || null,
onRejected: onRejected || null,
resolve: resolve,
reject: reject
});
});
}
catch(onError) {
return this.then(null, onError);
}
finally(onDone) {
if (typeof onDone !== 'function') return this.then();
let Promise = this.constructor;
return this.then(
value => Promise.resolve(onDone()).then(() => value),
reason => Promise.resolve(onDone()).then(() => { throw reason })
);
}
static resolve(value) {
if (value && value instanceof Promise) {
return value;
} else if (value && typeof value === 'object' && typeof value.then === 'function') {
let then = value.then;
return new Promise(resolve => {
then(resolve);
});
} else if (value) {
return new Promise(resolve => resolve(value));
} else {
return new Promise(resolve => resolve());
}
}
static reject(value) {
if (value && typeof value === 'object' && typeof value.then === 'function') {
let then = value.then;
return new Promise((resolve, reject) => {
then(reject);
});
} else {
return new Promise((resolve, reject) => reject(value));
}
}
static all(promises) {
return new Promise((resolve, reject) => {
let fulfilledCount = 0
const itemNum = promises.length
const rets = Array.from({ length: itemNum })
promises.forEach((promise, index) => {
Promise.resolve(promise).then(result => {
fulfilledCount++;
rets[index] = result;
if (fulfilledCount === itemNum) {
resolve(rets);
}
}, reason => reject(reason));
})
})
}
static race(promises) {
return new Promise(function (resolve, reject) {
for (let i = 0; i < promises.length; i++) {
Promise.resolve(promises[i]).then(function (value) {
return resolve(value)
}, function (reason) {
return reject(reason)
})
}
})
}
_handle(callback) {
if (this.state === 'pending') {
this.callbacks.push(callback);
return;
}
let cb = this.state === 'fulfilled' ? callback.onFulfilled : callback.onRejected;
if (!cb) {//如果then中没有传递任何东西
cb = this.state === 'fulfilled' ? callback.resolve : callback.reject;
cb(this.value);
return;
}
let ret;
try {
ret = cb(this.value);
cb = this.state === 'fulfilled' ? callback.resolve : callback.reject;
} catch (error) {
ret = error;
cb = callback.reject
} finally {
cb(ret);
}
}
_resolve(value) {
if(this.state !== 'pending') return
if (value && (typeof value === 'object' || typeof value === 'function')) {
var then = value.then;
if (typeof then === 'function') {
then.call(value, this._resolve.bind(this), this._reject.bind(this));
return;
}
}
this.state = 'fulfilled';//改变状态
this.value = value;//保存结果
this.callbacks.forEach(callback => this._handle(callback));
}
_reject(error) {
if(this.state !== 'pending') return
this.state = 'rejected';
this.value = error;
this.callbacks.forEach(callback => this._handle(callback));
}
}
- 深拷贝
function deepCopy(obj){
let result;
if(typeof obj == "object"){
//复杂数据类型
result = obj.constructor == Array ? [] : {};
for(let i in obj){
result[i] = typeof obj[i] == "object" ? deepCopy(obj[i]) : obj[i];
}
}else {
result = obj;
}
return result;
}
21.浏览器进程与线程
https://imweb.io/topic/58e3bfa845e5c13468f567d5
22.设计一个简单的任务队列,要求分别在1,3,4秒后打印出”1“,”2“,”3“
/**
* 题目
*/
new Quene()
.task(1000, () => {
console.log(1);
})
.task(2000, () => {
console.log(2);
})
.task(1000, () => {
console.log(3);
})
.start();
function Quene() { ... }
/**
* 解题1 promise
*/
class Quene {
constructor() {
this.tasks = [];
}
task(wait, fn) {
this.tasks.push({
wait,
fn,
});
return this;
}
async start() {
for (let task of this.tasks) {
const { wait, fn } = task;
await new Promise((res, rej) => {
setTimeout(() => {
fn();
res();
}, wait);
});
}
}
}
/**
* 解题2 递归
*/
class Quene {
constructor() {
this.tasks = [];
}
task(wait, fn) {
this.tasks.push({ wait, fn });
return this;
}
start() {
const firstTask = this.tasks.shift();
if (firstTask) {
setTimeout(() => {
firstTask.fn();
this.start();
}, firstTask.wait);
}
}
}
/**
* 解题3 闭包
*/
class Queue {
constructor() {
this.tasks = [];
}
task(wait, fn) {
this.tasks.push({
wait,
fn,
});
return this;
}
start() {
let int = 0;
this.tasks.forEach(({ wait, fn }) => {
setTimeout(() => {
fn();
}, (int += wait));
});
}
}
- 用 setTimeout 实现 setInterval,阐述实现的效果与 setInterval 的差异
function mySetInterval(fn, wait) {
mySetInterval.timer = setTimeout(() => {
fn();
mySetInterval(fn, wait);
}, wait)
}
mySetInterval.clear = function() {
clearTimeout(mySetInterval.timer)
}
mySetInterval(() => {
console.log(11111)
}, 1000)
setTimeout(() => {
// 5s 后清理
mySetInterval.clear()
}, 5000)
- vue3 中的数据侦测
const rawToReactive = new WeakMap();
const reactiveToRaw = new WeakMap();
/**
* utils
* */
function isObject(val) {
return typeof val === "object";
}
function hasOwn(val, key) {
const hasOwnProperty = Object.prototype.hasOwnProperty;
return hasOwnProperty.call(val, key);
}
/**
* traps
* */
// get
function createGetter() {
return function(target,key,receiver) {
const res = Reflect.get(target,key,receiver);
console.log('get', key);
return isObject(res) ? reactive(res) : res;
}
}
// set
function set(target,key,value,receiver) {
const hadKey = hasOwn(target, key);
const oldValue = target[key];
value = reactiveToRaw.get(value) || value;
const res = Reflect.set(target, key, value, receiver)
if(!hadKey || value !== oldValue) {
console.log('tigger...');
}
return res;
}
// handle
const mutableHandlers = {
get: createGetter(),
set: set
};
// create reactive object
function createReactiveObject(target, toProxy, toRaw, baseHandlers) {
let observed = toProxy.get(target);
// target 生成过 observed,返回 observed
if(observed !== void 0) {
return observed;
};
// target 是 observed, 返回 target
if(toRaw.has(target)) {
return target;
}
observed = new Proxy(target, baseHandlers);
toProxy.set(target, observed);
toRaw.set(observed, target);
return observed;
}
// enter
function reactive(target) {
return createReactiveObject(target, rawToReactive, reactiveToRaw, mutableHandlers)
}
网友评论