2021准备前端面试二三事

360 阅读13分钟

下面是 2021年面试准备的内容,有的是看大佬文章视频总结,有的是按自己理解.....如有错误内容可以在评论区留言,我看到会及时更正,逐渐抽空补全当中.....

一.CSS3

盒子水平垂直居中5大方案

水平:

1.text-align:center(对行内内容有效,必须将子元素设置为 display: inline; 或者 display: inline-block; )

2.margin: 0 auto;(必须定宽)

3.绝对定位实现(代码较多;脱离文档流;使用margin-left需要知道宽度值;使用transform兼容性不好(ie9+)。记得好像是回引起重绘??)

#parent{
    height: 200px;
    width: 200px;  /*定宽*/
    position: relative;  /*父相*/
    background-color: #f00;
}
#son{
    position: absolute;  /*子绝*/
    left: 50%;  /*父元素宽度一半,这里等同于left:100px*/
    transform: translateX(-50%);  /*自身宽度一半,等同于margin-left: -50px;*/
    width: 100px;  /*定宽*/
    height: 100px;
    background-color: #00ff00;
}


4.最爱的flex(pc端兼容不好 移动端ok)

#parent{
    display: flex;
    justify-content: center;
}

垂直:

1.line-height(只能用于单行行内内容;要知道高度的值)

2.vertical-align: middle; (需要添加font-size: 0; 才可以完全的垂直居中;需要给它的父元素设置display: table; 才生效;table-cell不感知margin,在父元素上设置table-row等属性,也会使其不感知height;设置float或position会对默认布局造成破坏,可以考虑为之增加一个父div定义float等属性;内容溢出时会自动撑开父元素 建议看下vertical-align和line-height的关系)

#parent{
    height: 150px;
    line-height: 150px;
    font-size: 0;
}
img#son{vertical-align: middle;} /*默认是基线对齐,改为middle*/

======================================================
#parent{
    display: table-cell;
    vertical-align: middle;
}

3.绝对定位(和上面水平差不多)

4.flex(和上面水平差不多)

#parent{
    display: flex;
    align-items: center;
}

或

#parent{display: flex;}
#son{align-self: center;}

水平垂直:

1.text-align: center; vertical-align: middle;

#parent{
    height: 150px;
    line-height: 150px;  /*行高的值与height相等*/
    text-align: center;
    font-size: 0;   /*消除幽灵空白节点的bug*/
}
#son{
    /*display: inline-block;*/  /*如果是块级元素需改为行内或行内块级才生效*/
    vertical-align: middle;
}

2.display: table-cell;(缺点同水平)

#parent{
    height: 150px;
    width: 200px;
    display: table-cell;
    vertical-align: middle;
    /*text-align: center;*/   /*如果是行内元素就添加这个*/
}
#son{
    /*margin: 0 auto;*/    /*如果是块级元素就添加这个*/
    width: 100px;
    height: 50px;
}


4.绝对定位(代码较多;脱离文档流)

#parent{
    position: relative;
}
#son{
    position: absolute;
    margin: auto;
    width: 100px;
    height: 50px;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
}

5.flex

#parent{
    display: flex;
}
#son{
    margin: auto;
}

或

#parent{
    display: flex;
    justify-content: center;
    align-items: center;
}

或

#parent{
    display: flex;
    justify-content: center;
}
#son{
    align-self: center;
}

关于CSS3几道面试题

标准盒模型,ie盒模型;

清除浮动;

BFC

px,em,rem

经典布局(圣杯,双飞翼)

二.HTML5

语义化标签类

音视频处理

canvas/webGL

history API

requestAnimationFrame

地理位置

web scoket

三.永远的Javascript

一堆栈内存及闭包作用域

JS的8种数据类型及区别

基本类型:number string boolean,null,undefined
引用类型:function,object 特殊(es6新加):symbol

JS堆栈内存的运行机制

堆:存储引用类型值的空间 栈:存储基本类型值和指定代码的环境

变量提升(var function)es5

在代码执行之前,在当前作用域当前执行上下文,所有带var function关键字的变量提前声明 声明定义

作用域、作用域链

闭包的两大作用:保护/保存

JS编译机制:VO/AO/GO

JS高级编程技巧:惰性函数/柯里化函数/高级函数

几道面试题

1.

//###example1
let a={},
    b='1'
    c=1
a[b]='AAAA'
a[c]='BBBB'
console.log(a[b])//BBBB
//=》对象和数组区别
//###example2
let a={},
    b=Symbol('1')
    c=Symbol('1')
a[b]='AAAA'
a[c]='BBBB'
console.log(a[b])//AAAA
//=》实现symbol
//###example3
let a={},
    b={
        n:'1'
    },
    c={
        m:'2'
    }
a[b]='AAAA'
a[c]='BBBB'
console.log(a[b])//AAAA
//=》Object.prototype.toString()

image.png

2.

var test=(function(i){
        return function(){
            alert(i*=2)
        }
    })(2);//创建并立即执行
test(5)///'4' *************注意alert输出字符串(细节决定成败)

image.png

3.

var a=0,
b=0;
function A(a){
    A=function(b){
        alert(a+b++);
    };
    alert(a++)
}
A(1)
A(2)

image.png

4.

对象数组深浅克隆

let obj={
    a:'AAA',
    b:['BBB',1,1,2,3],
    c:{c:xx,}
    d:/^\d+$/
}
let obj2={}
//浅克隆
obj2={...obj};

for(let i in obj){
    if(!obj.hasOwnProperty(i))break;
    obj2[i]=obj[i]
}
//深克隆
let obj2=JSON.parse(JSON.stringify(obj))//函数、正则、日期new Date()不能用,=》弊端

function deepClone(obj){
//过滤特殊情况
    if(obj===null) return null
    if(typeof obj!=='object') return obj
    if(obj instanceof RegExp){
        return new RegExp(obj);//*********注意不能返回obj,不然地址一样是浅克隆
    }
    if(obj instanceof Date){
        return new Date(obj);//*********注意
    }
//不直接创建空的对象,为了克隆结果和之前保持相同的所属类
    let newObj=new Object();//new obj.constructor==>有什么好处???
    for(let key in obj){
        if(obj.hasOwnProperty(key)){
          newObj[key]=deepClone(obj[key])
        };
        
    }
    return newObj
}

5.

function Foo(){
    getName=function(){
        console.log(1);
    }
    retune this;
}
Foo.getName=function(){
    console.log(2);
}
Foo.prototype.getName=function(){
    console.log(3);
}
var getName=function(){
    console.log(4);
}
function getName(){
    console.log(5);
}
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();

image.png

image.png

image.png www.bilibili.com/video/BV1ek…

二面向对象和this处理

单例设计模式

类和实例

原型/原型链

new运算符的实现机制

函数调用的方法一共有 4 种:

  • 作为一个函数调用
  • 函数作为方法调用
  • 使用构造函数调用函数
  • 作为函数方法调用函数(call、apply) new 的过程:
  • 创建一个空对象 obj;
  • 将新创建的空对象的隐式原型指向其构造函数的显示原型。
  • 使用 call 改变 this 的指向
  • 如果无返回值或者返回一个非对象值,则将 obj 返回作为新对象;如果返回值是一个新对象的话那么直接直接返回该对象。
var a = new myFunction("Li","Cherry");

new myFunction{
    var obj = {};
    obj.__proto__ = myFunction.prototype;
    var result = myFunction.call(obj,"Li","Cherry");
    return typeof result === 'obj'? result : obj;
}

call/apply/bind

改变this指向方法: 改变 this 的指向我总结有以下几种方法:

  • 使用 ES6 的箭头函数
  • 在函数内部使用 _this = this
  • 使用 apply、call、bind
  • new 实例化一个对象

在 MDN 中定义 apply 如下; apply() 方法调用一个函数, 其具有一个指定的this值,以及作为一个数组(或类似数组的对象)提供的参数。 fun.apply(thisArg, [argsArray])

call 的语法为:

fun.call(thisArg[, arg1[, arg2[, ...]]])

其实 apply 和 call 基本类似,他们的区别只是传入的参数不同, call 方法接受的是若干个参数列表,而 apply 接收的是一个包含多个参数的数组。

MDN 中定义 bind 如下:

bind()方法创建一个新的函数, 当被调用时,将其this关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列。

bind 是创建一个新的函数,我们必须要手动去调用

示例:

//example1
var a ={
    name : "Cherry",
    fn : function (a,b) {
        console.log( a + b)
    }
}

var b = a.fn;
b.apply(a,[1,2])     // 3

//example2
var a ={
    name : "Cherry",
    fn : function (a,b) {
        console.log( a + b)
    }
}

var b = a.fn;
b.call(a,1,2)       // 3
//example3
var a ={
    name : "Cherry",
    fn : function (a,b) {
        console.log( a + b)
    }
}

var b = a.fn;
b.bind(a,1,2)()    // 3

constructor构造函数模式

JS中this五种情况的综合梳理

JS的4种数据类型检测方案

typeof

typeof '5' // string
typeof 5 // number
typeof null // object*************************注意
typeof undefined // undefined
typeof true // boolean
typeof Symbol('5') // symbol
typeof 5n // bigint
typeof new Object(); // object
typeof new Function(); // function

【#】null被认为是一个空对象,因此返回了object,因为任何对象都会被转化为二进制,null转为二进制则表示全为0,如果前三个均为0,js就会把它当作是对象,这是js早期遗留下来的bug。

instanceof

[] instanceof Array; // true
//[].proto 的原型 是指向Array.prototype 的,说明两个对象是属于同一条原型链的,返回true
[] instanceof Object; // true

function Person() {};
const person = new Person();

person instanceof Person; // true
person instanceof Object; // true
//person和Object是属于原型链的关系

let obj1 = {}
console.log(obj1 instanceof Object) // true

let obj2 = Object.create(null)
console.log(obj2 instanceof Object) // false*******************注意

let obj3 = Object.create({})
console.log(obj3 instanceof Object) // true


【#】只能用来判断变量的原型链上是否有构造函数的prototype属性(两个对象是否属于原型链的关系),不一定能获取对象的具体类型,Instanceof 不适用判断原始类型的值,只能用于判断对象是否从属关系。

constructor

//原理:每一个实例对象都可通过constructor来访问它的构造函数,其实也是根据原型链的原理来的。注意---undefined和null是无效的对象,因此是没有constructor属性的,这两个值不能用这种方法判断.
'5'.__proto__.constructor === String // true
[5].__proto__.constructor === Array // true

undefined.__proto__.constructor // Cannot read property '__proto__' of undefined

null.__proto__.constructor // Cannot read property '__proto__' of undefined


toString

//因为实例对象有可能会自定义toString方法,会覆盖Object.prototype.toString,所以在使用时,最好加上call.*********注意
Object.prototype.toString.call('5') // [object String]
Object.prototype.toString.call(5) // [object Number]
Object.prototype.toString.call([5]) // [object Array]
Object.prototype.toString.call(true) // [object Boolean]
Object.prototype.toString.call(undefined) // [object Undefined]
Object.prototype.toString.call(null) // [object Null]
Object.prototype.toString.call(new Function()); // [object Function]
Object.prototype.toString.call(new Date()); // [object Date]
Object.prototype.toString.call(new RegExp()); // [object RegExp]
Object.prototype.toString.call(new Error()); // [object Error]


【#】Object.prototype.toString方法返回对象的类型字符串,因此可用来判断一个值的类型。所有的数据类型都可以使用此方法进行检测,且非常精准

JS继承方案(深浅拷贝)

1.原型链继承

2.借用构造函数继承

3.组合继承

4.原型式继承

5.寄生式继承

6.寄生组合式继承

7.混入方式继承多个对象

8.ES6类继承extends

几道面试题

三dom/bom及事件处理机制

DOM/BOM的核心操作

事件对象

拖拽及拖拽插件封装

发布订阅设计模式

JQ部分源码理解

事件传播机制和事件代理

DOM2级事件的核心运行机制

移动端Touch、Gesture事件及封装处理

浏览器底层渲染机制和DOM的回流重绘

DIALOG模态框组件的封装

四.框架(我自己用的vue)

组件通信

vue2

双向数据绑定

vue3

双向数据绑定

script setup

mvc和mvvm区别

五.webpack

六.算法

数组、对象去重

排序(冒泡、选择、快排)

数组扁平化N种方法及优缺点

涉及递归的几道题

斐波那契数列

七.es6-9

let const var

注意使用区别和变量提升

箭头函数Arrowfunction

注意箭头函数不能被new。

this的指向问题

解构赋值和拓展运算符

set、map数据结构

promise设计模式

回调函数本身并没有问题,它的问题出现在多个回调函数嵌套。假定读取A文件之后,再读取B文件,代码如下。

fs.readFile(fileA, function (err, data) {
  fs.readFile(fileB, function (err, data) {
    // ...
  });
});

不难想象,如果依次读取多个文件,就会出现多重嵌套。代码不是纵向发展,而是横向发展,很快就会乱成一团,无法管理。这种情况就称为"回调函数噩梦"(callback hell)。

Promise就是为了解决这个问题而提出的。它不是新的语法功能,而是一种新的写法,允许将回调函数的横向加载,改成纵向加载。采用Promise,连续读取多个文件,写法如下。

var readFile = require('fs-readfile-promise');

readFile(fileA)
.then(function(data){
  console.log(data.toString());
})
.then(function(){
  return readFile(fileB);
})
.then(function(data){
  console.log(data.toString());
})
.catch(function(err) {
  console.log(err);
});

上面代码中,使用了 fs-readfile-promise 模块,它的作用就是返回一个 Promise 版本的 readFile 函数。Promise 提供 then 方法加载回调函数,catch方法捕捉执行过程中抛出的错误。

可以看到,Promise 的写法只是回调函数的改进,使用then方法以后,异步任务的两段执行看得更清楚了,除此以外,并无新意。

Promise 的最大问题是代码冗余,原来的任务被Promise 包装了一下,不管什么操作,一眼看去都是一堆 then,原来的语义变得很不清楚。-->>如何优化???

async、await及实现原理

Generator生成器函数

www.ruanyifeng.com/blog/2015/0…

interator迭代器和for..in for..of循环

promise A++规范

js底层运行机制:单线程和同步异步编程

异步编程对 JavaScript 语言太重要。JavaScript 只有一根线程,如果没有异步编程,根本没法用,非卡死不可。

以前,异步编程的方法,大概有下面四种。

  • 回调函数
  • 事件监听
  • 发布/订阅
  • Promise 对象

对异步理解:简单说就是一个任务分成两段,先执行第一段,然后转而执行其他任务,等做好了准备,再回过头执行第二段。比如,有一个任务是读取文件进行处理,异步的执行过程就是下面这样。

image.png

连续的执行,就叫做同步。

image.png

js底层运行机制:微任务宏任务和事件循环机制

执行顺序:微任务-》宏任务-》主程序 event queue(micro-task:promise,async,await ,macro-task:定时器,事件绑定)

几道面试题

1.

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(){
    console.log('Promise1');
    resolve();
}).then(function(){

    console.log('Promise2')
});

console.log('script end')

www.bilibili.com/video/BV1ek…

2.

3.

八.AJAX/HTTP前后端数据交互

AJAX核心4步操作

get、post核心机制与区别

get和post虽然本质都是tcp/ip,但两者除了在http层面外,在tcp/ip层面也有区别。get会产生一个tcp数据包,post两个。

具体就是:

get请求时,浏览器会把headers和data一起发送出去,服务器响应200(返回数据), post请求时,浏览器先发送headers,服务器响应100 continue, 浏览器再发送data,服务器响应200(返回数据)。

再说一点,这里的区别是specification(规范)层面,而不是implementation(对规范的实现)

TCP三次握手、4次握手

http的本质就是tcp/ip请求,.需要了解3次握手规则建立连接以及断开连接时的四次挥手,tcp将http长报文划分为短报文,通过三次握手与服务端建立连接,进行可靠传输。 三次握手的步骤:(抽象派)

客户端:hello,你是server么?
服务端:hello,我是server,你是client么
客户端:yes,我是client

建立连接成功后,接下来就正式传输数据,然后,待到断开连接时,需要进行四次挥手(因为是全双工的,所以需要四次挥手)

四次挥手的步骤:(抽象派)

主动方:我已经关闭了向你那边的主动通道了,只能被动接收了
被动方:收到通道关闭的信息
被动方:那我也告诉你,我这边向你的主动通道也关闭了
主动方:最后收到数据,之后双方无法通信

tcp/ip的并发限制:

  • 浏览器对同一域名下并发的tcp连接是有限制的(2-10个不等)
  • 而且在http1.0中往往一个资源下载就需要对应一个tcp/ip请求
  • 所以针对这个瓶颈,又出现了很多的资源优化方案

axios库和源码

fetch基础和应用

前端跨域9种方案(非同源策略请求)

协议、域名、端口号

  • 同源策略请求(部署到web服务器) ajax、fetch
  • 跨域请求(服务器拆分) 1.JSONP(缺点:只能get-》优化??) 2.CORS 3.postMessage 4.websocket 5.Node中间件代理 6.nginx反向代理 7.window.name+iframe 8.location.hash+iframe 9.document.domain+iframe

juejin.cn/post/684490…

www.bilibili.com/video/BV1wT…

HTTP网络状态码和实战中的处理方案

前端性能优化(前缓存和弱缓存)