程序员

前端面试整理,CSS,JS,HTTP,REACT等持续更新

2020-06-28  本文已影响0人  Taco_King

undefined , null

null是对象原型链的终点,null == undefined

CSS

position

position: static | relative | absolute | sticky | fixed

animation transition

animation: name | duration | timing-function | delay |
iteration-count | direction | fill-mode | play-state

transition: property name | duration | timing function | delay

transition从:hover延伸出来;animation从flash延伸出来

圣杯布局,双飞翼布局(淘宝UED)

解决:中间栏div内容不被遮挡问题

区别:三栏全部float浮动;圣杯布局,为了中间div内容不被遮挡,将中间div设置了左右padding-left和padding-right后,将左右两个div用相对布局position: relative并分别配合right和left属性,以便左右两栏div移动后不遮挡中间div;双飞翼布局,为了中间div内容不被遮挡,直接在中间div内部创建子div用于放置内容,在该子div里用margin-left和margin-right为左右两栏div留出位置。简单说起来就是”双飞翼布局比圣杯布局多创建了一个div,但不用相对布局了“

因为浏览器渲染引擎在构建和渲染渲染树是异步的(谁先构建好谁先显示),方便SEO

回流,重绘

浏览器使用流式布局模型。浏览器会把HTML解析成DOM,把CSS解析成CSSOM,DOM和CSSOM合并就产生了Render Tree。有了RenderTree,我们就知道了所有节点的样式,然后计算他们在页面上的大小和位置,最后把节点绘制到页面上。由于浏览器使用流式布局,对Render Tree的计算通常只需要遍历一次就可以完成,但table及其内部元素除外,他们可能需要多次计算,通常要花3倍于同等元素的时间,这也是为什么要避免使用table布局的原因之一。回流必将引起重绘,重绘不一定会引起回流

  1. 当Render Tree中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程称为回流,如何引发回流

    • 页面首次渲染,浏览器窗口改变大小,元素尺寸或位置发生改变,元素内容变化(文字数量或图片大小等等),元素字体大小变化,DOM操作,激活CSS伪类(例如::hover),查询某些属性或调用某些方法

    • scrollTo(),getComputedStyle(),scrollIntoView()、scrollIntoViewIfNeeded(),getBoundingClientRect()

  2. 当页面中元素样式的改变并不影响它在文档流中的位置时(例如:color、background-color、visibility等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘

如何避免

  1. 避免使用table布局
  2. 尽可能在DOM树的最末端改变class
  3. 避免设置多层内联样式
  4. 将动画效果应用到position属性为absolute或fixed的元素上
  5. 避免使用CSS表达式(例如:calc())
  6. 避免频繁操作样式,最好一次性重写style属性,或者将样式列表定义为class并一次性更改class属性
  7. 避免频繁操作DOM,创建一个documentFragment,在它上面应用所有DOM操作,最后再把它添加到文档中
  8. 先为元素设置display: none,操作结束后再把它显示出来。因为在display属性为none的元素上进行的DOM操作不会引发回流和重绘
  9. 避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来
  10. 对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流

居中

  1. 水平居中
<!--行内元素:文本text、图像img、按钮超链接等 -->
.center {
    text-align: center;
}
<div class="center">水平居中</div>

<!--块级定宽元素 -->
.center {
    width: 200px;
    margin: auto;
}
<div class="center">水平居中</div>

<!--块级不定宽元素,table -->
.center {
    display: table;
    margin: auto;
}
<div class="center">水平居中</div>

<!--块级不定宽元素,inline-block -->
.center {
    text-align: center;

    >div {
        display: inline-block;
    }
}
<div class="center"><div>inline-block<div></div>

<!--块级不定宽元素,flex -->
.center {
    text-align: flex;
    justify-content: center;
}
<div class="center"><div>flex<div></div>
  1. 垂直居中
<!--单行文本 line-height=height或者padding-top=padding-bottom-->
.colCenter {
    height: 24px;
    line-height: 24px;
}
<div class="colCenter">垂直居中</div>

<!--多行文本,利用table -->
.colCenter {
    width: 200px;
    height: 200px;
    display: table;

    >div {
        display: table-cell;
        vertical-align: middle;
    }
}
<div class="colCenter"><div>垂直居中<div></div>

<!--块级元素,flex -->
.colCenter {
    width: 200px;
    height: 200px;
    display: flex;
    align-items: center;
}
<div class="colCenter"><div>垂直居中<div></div>

除此之外,还可以利用padding和margin等计算居中

块格式化上下文(Block Formatting Context,BFC)

是Web页面的可视CSS渲染的一部分,是块盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域。触发条件如下:

作用:清除浮动,浮动塌陷,外边距塌陷,元素重叠

canvas和svg的区别,适用场景

JS

数据类型:number,string,null,boolean,undefined,object(Array,Function,RegExp,Date)

类型判断:

原型链:

function F(){};
F.prototype.__proto__ = Object.prototype;
Array.prtotype.__proto__ = Object.prototype;
Object.prototype.__proto__ = null;

F.__proto__ = Function.prototype;

var f = new F();
f.__proto__ = F.prototype;

call,apply,bind

改变函数执行时的上下文,改变函数运行时的this指向

map/set,weakMap/weakSet

Set和Map都可以用来生成新的 Map

// 去重,Set接受数组或者类数组为参数
var arr = new Set([1,2,3,2,4])
[...arr]  // [1,2,3,4]

// WeakSet 中的对象都是弱引用,垃圾回收机制不考虑 WeakSet 对该对象的引用,WeakSet不可遍历
const a = [[1, 2], [3, 4]];
const ws = new WeakSet(a);
// WeakSet {[1, 2], [3, 4]} 注意,是a数组的成员成为 WeakSet 的成员,而不是a数组本身。这意味着,数组的成员只能是对象。

const map = new Map([
  ['name', '张三'],
  ['title', 'Author']
]);
map.set('name','jin');

// WeakMap结构与Map结构类似,也是用于生成键值对的集合
// WeakMap只接受对象作为键名(null除外),不接受其他类型的值作为键名;WeakMap的键名所指向的对象,不计入垃圾回收机制,WeakMap 弱引用的只是键名,而不是键值

// 基本上,如果你要往对象上添加数据,又不想干扰垃圾回收机制,就可以使用 WeakMap。一个典型应用场景是,在网页的 DOM 元素上添加数据,就可以使用WeakMap结构。当该 DOM 元素被清除,其所对应的WeakMap记录就会自动被移除。另一个用处是部署私有属性

堆栈:

栈内存一般储存基础数据类型,遵循后进先出的原则,大小固定并且有序;堆内存一般储存引用数据类型,JavaScript不允许直接访问堆内存中的位置,因此当我们要访问堆内存中的引用数据类型时,实际上我们首先是从栈中获取了该对象的地址引用(或者地址指针),然后再从堆内存中读取我们需要的数据

执行上下文

执行栈(先进后出)

eventloop事件循环

"主线程"(执行栈)和任务队列<先进先出>(主要是各种I/O操作)的通信,被称为事件循环

  1. node环境 还是 浏览器环境
  2. 任务队列(task queue):分为3,4
  3. 宏任务task(macro-task):script(整体代码),setTimeout,setInterval,setImmediate,I/O,UI render
  4. 微任务jobs(micro-task):process.nextTick,Promise,Async/Await(实际就是promise),MutationObserver(html5新特性)
  5. 事件循环机制:主线程 ->所有微任务 ->宏任务(先进先执行,如果里面有微任务,则下一步先执行微任务,否则继续执行宏任务)

node 11之后的特性已经向浏览器看齐了。两者最主要的区别在于浏览器中的微任务是在每个相应的宏任务中执行的,而nodejs中的微任务是在不同阶段之间执行的

垃圾回收机制

  1. 引用计数:0引用时会被回收,IE 6, 7 使用引用计数方式对 DOM 对象进行垃圾回收。该方式常常造成对象被循环引用时内存发生泄漏
  2. 标记-清除算法:这个算法把“对象是否不再需要”简化定义为“对象是否可以获得”,因为“有零引用的对象”总是不可获得的,垃圾回收器将定期从根开始,找所有从根开始引用的对象,对堆内存从头到尾进行线性的遍历,进行标记,而没有被标记的对象就被清除

浅拷贝:遍历对象赋值,只能用作基本数据类型的拷贝

深拷贝:递归浅拷贝

function deepCopy(a,b){
    let c = b || {};
    for(let i in a){
        if(typeof a[i] == 'object'){
            c[i] = a[i].constructor === Array ? [] : {};
            deepCopy(a[i],c[i]);
        }else{
            c[i] = a[i];
        }
    }
    
    return c;
}
var parent = {
    name: 'king',
    animals: {
        dogs: 2,
        cat: 1
    },
    area: ['A','B']
}
var obj = deepCopy(parent,{});

json序列化和反序列化的缺点

new

Person (){

}
var obj = new Object();
obj.__proto__ = Person.prototype;
Person.call(obj)

构造函数和class(语法糖)的区别

class Parent {
    constructor(name,age) {
        this.name = name;
        this.age = age;
    }
    say(){
        console.log('hello')
    }
}

// 等价于
function Parent(name,age){
    this.name = name;
    this.age = age;
}
Parent.prototype.say = function (){
    console.log('hello');
}

var child = new Parent('king',12);

类的数据类型就是函数,类本身就指向构造函数;使用的时候,也是直接对类使用new命令,跟构造函数的用法完全一致;Object.assign方法可以很方便地一次向类添加多个方法;prototype对象的constructor属性,直接指向“类”的本身,这与 ES5 的行为是一致的;

function和箭头函数

手动实现字符串单词统计,’sdsdfdewrwescvv’,统计各个出现次数

var str = 'sdsdfdewrwescvv';
let obj = {};
for (i = 0; i<str.length; i++){
    if(obj[str[i]]){
        obj[str[i]]++;
    }else{
        obj[str[i]] = 1;
    }
}
console.log(obj);

promise,generator,async/await 对比

promise手动实现

1. 设置三种状态,一但开始不能暂停,且状态只能被修改一次,pending,rejected,resolved(fulfilled)

2. 两个参数,resolve(),reject(),函数执行之后改变状态,执行的时候如果传递参数,就是then的参数

3. 回调函数,then(resolved,rejected(可选)),返回新promise实例,以便继续链式调用,注意是异步操作,使用settimeout实现

4. catch异常回调,Promise.prototype.catch()方法是.then(null, rejection)或.then(undefined, rejection)的别名,用于指定发生错误时的回调函数。

用async/await实现promise.all

1. promise.all的参数数组里面的promise,如果自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()的catch方法

2. 参数数组里面的实例只要有一个变为rejected,或者都为fulfilled,就会调用回调函数

3. async函数返回的 Promise 对象,必须等到内部所有await命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到return语句或者抛出错误。也就是说,只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数

在await之后增加手动判断,抛出异常

es 6 module和cmd中的模块require有什么区别

继承

function Parent(){
    this.color = ['red','yellow']
}
function child() {}
child.prototype = new Parent();

var eg1 = new child();
eg1.color.push('white');
var eg2 = new child();
console.log(eg2)  // ["red", "yellow", "white"]

原型链方案存在的缺点:多个实例对引用类型的操作会被篡改
function Person(){
    this.color = ['red','yellow']
}
Person.prototype.say=function(){
    console.log('hi')
}
function child(){
    Person.call(this);
}
var eg1 = new child();
eg1.color.push('white');
console.log(eg1.say)  // undefined
var eg2 = new child();
console.log(eg2)  // ["red", "yellow"]

比前一种更耗内存,影响性能,每次都要执行建立Person实例
不能继承原型方法
把前两种组合一下

function Person(){
    this.age = 11;
    this.color = ['red','yellow']
}
Person.prototype.say=function(){
    console.log('hi')
}
function child(){
    Person.call(this);
}
child.prototype = new Parent();

child.prototype.constructor = child;
var eg1 = new child();

eg1同时继承child 和person

缺点: 子类实例中会存在两份相同的属性/方法
即后来的Object.create内置函数,其原理为
function Person(o){
    var child = function(){};
    child.prototype = o;
    return new child();
}

但实际上new具体做了什么操作

var son = new Person();

当这段代码运行的时候,内部实际上执行的是:

// 创建一个空对象
var other = new Object();
// 将空对象的原型赋值为构造函数的原型
other.__proto__ = Person.prototype;
// 改变this指向
Person.call(other);

缓存 SessionStorage,localStorage,Cookie

存储方式

存储大小

过期时间

作用域

节流和防抖

设计模式,观察者,发布订阅模式

跨域

  1. jsonp: 利用 script 标签没有跨域限制的漏洞,网页可以得到从其他来源动态产生的 JSON 数据。JSONP请求一定需要服务器做支持才可以;兼容性好,仅支持get方法且不安全,容易遭XSS攻击。实现方式可以返回一个promise对象,需要创建一个script标签,把API地址赋值给src

  2. cors: 服务端设置 Access-Control-Allow-Origin 就可以开启 CORS;简单请求GET,POST,HEAD,且Content-Type为text/plain,multipart/form-data,application/x-www-form-urlencoded;复杂请求会在正式通信之前增加一次预检option请求,通过该请求来知道服务端是否允许跨域请求

  3. postMessage:允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递。

  4. websocket:用socket.io比原生websocket API好用,server安装ws,调用时new WebSocket('ws://localhost:3000')

  5. node中间件代理(两次跨域)

  6. nginx反向代理:搭建一个中转nginx服务器,用于转发请求,只需修改nginx配置,将前后端地址用ngnix转发到同一个下,支持所有浏览器,支持session,不影响服务器性能;每次修改nginx.conf之后需要执行ngnix -s reload生效;listen为代理地址,location.proxy_pass为前端真实访问地址

  7. document.domain+iframe;location.hash+iframe;window.name+iframe

CORS支持所有类型的HTTP请求,是跨域HTTP请求的根本解决方案;用得比较多的跨域方案是cors和nginx反向代理;JSONP只支持GET请求,JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据;不管是Node中间件代理还是nginx反向代理,主要是通过同源策略对服务器不加限制

http

概念:超文本传输​​协议(HTTP)是一个用于传输超媒体文档(例如 HTML)的应用层协议。它是为 Web 浏览器与 Web 服务器之间的通信而设计的,但也可以用于其他目的。HTTP 遵循经典的客户端-服务端模型,客户端打开一个连接以发出请求,然后等待它收到服务器端响应。HTTP 是无状态协议,这意味着服务器不会在两个请求之间保留任何数据(状态)。该协议虽然通常基于 TCP/IP 层,但可以在任何可靠的传输层上使用;也就是说,不像 UDP,它是一个不会静默丢失消息的协议。RUDP——作为 UDP 的可靠化升级版本——是一种合适的替代选择

http特性:

1.HTTP 是无连接无状态的

2.HTTP 一般构建于 TCP/IP 协议之上,默认端口号是 80

3.HTTP 可以分为两个部分,即请求和响应。

HTTP各版本特性及区别

1.http0.9– 单行协议:请求由单行指令构成,以唯一可用方法GET开头,其后跟目标资源的路径(一旦连接到服务器,协议、服务器、端口号这些都不是必须的);响应也极其简单的:只包含响应文档本身。

2.http1.0:协议版本信息现在会随着每个请求发送(HTTP/1.0被追加到了GET行);状态码会在响应开始时发送;引入了HTTP头的概念;Content-Type让请求具备了传输除纯文本HTML文件以外其他类型文档的能力

3.http1.1:连接可以复用,节省了多次打开TCP连接加载网页文档资源的时间;增加管线化技术,允许在第一个应答被完全发送之前就发送第二个请求,以降低通信延迟;支持响应分块;引入额外的缓存控制机制;引入内容协商机制,包括语言,编码,类型等,并允许客户端和服务器之间约定以最合适的内容进行交换;感谢Host头,能够使不同域名配置在同一个IP地址的服务器上

4.http2.0:HTTP/2是二进制协议而不是文本协议。不再可读,也不可无障碍的手动创建,改善的优化技术现在可被实施;这是一个复用协议。并行的请求能在同一个链接中处理,移除了HTTP/1.x中顺序和阻塞的约束;压缩了headers。因为headers在一系列请求中常常是相似的,其移除了重复和传输重复数据的成本;其允许服务器在客户端缓存中填充数据,通过一个叫服务器推送的机制来提前请求

5.http3.0: 将弃用TCP协议,改为使用基于UDP协议的QUIC协议实现,该协议旨在使网页传输更快

TCP,UDP

http请求:

  1. get:GET方法请求一个指定资源的表示形式. 使用GET的请求应该只被用于获取数据.
  2. post:POST方法用于将实体提交到指定的资源,通常导致在服务器上的状态变化或副作用
  3. head: HEAD方法请求一个与GET请求的响应相同的响应,但没有响应体.
  4. put:PUT方法用请求有效载荷替换目标资源的所有当前表示。
  5. delete:DELETE方法删除指定的资源。
  6. connect:CONNECT方法建立一个到由目标资源标识的服务器的隧道
  7. options:OPTIONS方法用于描述目标资源的通信选项
  8. trace:TRACE方法沿着到目标资源的路径执行一个消息环回测试。
  9. patch:PATCH方法用于对资源应用部分修改

常见的状态码:

http与https的区别

  1. https协议需要到ca申请证书,一般免费证书较少,需要付费
  2. http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议
  3. http默认80端口,https默认443端口
  4. http是无状态连接;https协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,安全性更高

对称加密,非对称加密

  1. 对称加密:一般小于256bit,密钥越大,加密越强,但是加密与解密的时间越长;加密与解密用的是同样的密钥;缺点:密钥的管理和分配
  2. 非对称加密:最常用的非对称加密算法是RSA算法;通过一堆密钥:公钥和私钥,私钥由一方安全保管,公钥可以发送给任何请求他的人,只有私钥才能解密,而且不需要将私钥通过网络发送出去,大大提高网络安全性

在浏览器地址栏输入URL之后回车的过程

ajax和fetch区别

  1. ajax本质是利用XMLHttpRequest来实现,fetch采用了Promise的异步处理机制

cdn原理

负载均衡,缓存,dns解析

浏览器缓存策略

如果命中,都是从客户端缓存中加载资源,而不是从服务器加载资源数据;强缓存不发请求到服务器,协商缓存会发请求到服务器

react生命周期变更,以及使用方式;为什么变化,为什么取消了那几个生命周期

v16.3去掉componentWillMount,componentWillReceiveProps,componentWillUpdate;新增static getDerivedStateFromProps(props, state),getSnapshotBeforeUpdate(prevProps, prevState)

  1. componentWillMount是在组件挂载之前调用,在此方法中调用setstate是不会触发render的,如果是初始化数据尽量写在constructor中,如果是请求数据,建议放在componentDidMount中

  2. componentWillReceiveProps:容易导致父子组件陷入死循环渲染,

  3. componentWillUpdate:因为props或者state更新而引起多次调用,而componentDidUpdate就只会被调用一次

  4. getDerivedStateFromProps 会在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。它应返回一个对象来更新 state,如果返回 null 则不更新任何内容。

  5. getSnapshotBeforeUpdate() 在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期的任何返回值将作为参数传递给 componentDidUpdate()。此用法并不常见,但它可能出现在 UI 处理中,如需要以特殊方式处理滚动位置的聊天线程等

setstate的同步异步说明

虚拟DOM

reactDOM.render()

react事件机制,以及优点

优点: 只需要注册一个事件即可,节省内存开销;可以统一在组件挂载和卸载时做处理;可以手动控制事件流程,特别是对state的批处理

react事件最好不要和原生事件混用,原生事件中如果执行了stopPropagation方法,则会导致其他react事件失效。因为所有元素的事件将无法冒泡到document上

diff算法,用key的原因

  1. React diff 与 传统diff 的不同是 React通过优化将复杂度O(n^3)提升至O(n)

  2. React 通过三个方面对tree diff, component diff, element diff 进行了优化

  3. 在开发时,尽量保持稳定的DOM结构,并且减少将最后的节点移动到首部的操作,能够优化渲染性能

fiber是什么,优点是什么

react 15在页面元素很多,且需要频繁刷新的场景下,React 15 会出现掉帧的现象,当我们调用setState更新页面的时候,React 会遍历应用的所有节点,计算出差异,然后再更新 UI。整个过程是一气呵成,不能被打断的。如果页面元素很多,整个过程占用的时机就可能超过 16 毫秒,就容易出现掉帧的现象;从Stack Reconciler到Fiber Reconciler,源码层面其实就是干了一件递归改循环的事情

旧版 React 通过递归的方式进行渲染,使用的是 JS 引擎自身的函数调用栈,它会一直执行到栈空为止。而Fiber实现了自己的组件调用栈,它以链表的形式遍历组件树,可以灵活的暂停、继续和丢弃执行的任务。实现方式是使用了浏览器的requestIdleCallback这一 API

ref相关的

react优化方式

上一篇下一篇

猜你喜欢

热点阅读