查漏补缺系列前端基础补充
Posted Vicky沛沛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了查漏补缺系列前端基础补充相关的知识,希望对你有一定的参考价值。
主要是根据自己没有掌握好以及还没有了解的部分进行补充。github地址。github会实时更新,可以下载用markdown查看。
关于碎碎念:长期工作以来,有些东西比如react fiber、react hooks这些其实都听过,但是由于工作上使用场景比较有限,以及个人精力有限等原因,没有详细去了解其中原理。这次查漏补缺的时候,去看了一下fiber、diff以及hooks等,在它们产生的原因背景、解决了哪些实际问题、在前端的哪些方面进行了优化、以及简单的实现方式等方面进行了了解之后,确实觉得在一定程度上让自己对前端的技术发展,前端的优化等方面有了更深层次的思考。也确实有意思!smileyqp继续加油呀!
文章目录
1、require和import的区别
- 规范:require是node的commonjs规范;import是ES6的模块化规范
- 可否动态:require支持动态导入;import不支持动态导入
- 导入方式:require输出的是一个值的拷贝;import输出的是一个值的引用
- 位置:import可以在import模块引入之前使用,但是require只能在引用之后使用
- 是否可以在模块中使用:import不可以在代码块中引用,只能在模块顶层使用;但是require可以在代码块中使用
7.16
2、webpack和babel
1、为什么要使用
- ES6模块化,浏览器暂时不支持
- ES6语法,浏览器不完全支持
- 压缩代码,整合代码让网页加载更快
webpack、babel都是将ES6转译的
babel是将ES的高级语法向低级语法转变的一个工具
webpack是一个打包的工具
2、babel基础插件的功能和区别
安装插件
babel-loader
只是babel提供个webpack的一个插件,真正去做ES6到ES5转译的是bable-core这个核心babel-core
定义了浏览器一些可能不兼容的语法babel/preset-env
babel只转化不兼容的语法,不转化新的API。语法指的是比如箭头函数等等,API指的是比如Promise、Set等等新的APIbabel/pollyfill
类似于补丁包,提供新的API的转化
3、基础配置(主要是style等的loader等)
/**
* webpack配置要向外暴露一个对象,用commonjs的规范进行,因为webpack内部是基于node来进行的处理
*/
const path = require('path');
const htmlWebpackPlugin = require('html-webpack-plugin')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const MiniCssExtracPlugin = require('mini-css-extract-plugin')
const webpack = require('webpack');
const optimize = require('webpack');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
function resolve(dir) //传入一个目录名称,就返回当前目录名称所在的绝对路径
return path.resolve(__dirname,dir)
module.exports =
//模式
mode:'production',
//入口:入口可以是字符串、对象、数组,都是可以的
entry:
main:resolve('src/index.js')
,
//出口
output:
path:resolve('dist'),
filename:'bundle.js',
publicPath:'/' //解决图片路径问题;所有生成的URL链接左侧用/开头;即相对路径
,
//模块加载器;按照顺序从下往上执行。enfore可以改变这个顺序
module:
rules:[
enforce:'pre', //前置loader最先执行;pre:最先执行;post:最后执行
test: /\\.m?js$/,
include:resolve('src'),
loader:'eslint-loader',
options:
formatter:'eslint-friendly-formatter' //友好格式化
,
//处理ES6到ES5
test: /\\.m?js$/, //指定对哪些文件进行处理,正则
exclude: /(node_modules|bower_components)/, //不包括哪些文件
include:resolve('src'), //包括哪些文件
use:[ //使用;可以使用对象、数组;写对象只有 一个loader,并且loader还有配置以及指定一些额外信息;对象是数组的简写,数组中可以有任意多的loader,但是数组这种方式不可以写配置
loader: 'babel-loader', //babel也可以专门用配置文件babel.config.js或者.babelrc进行配置,也可以这两个配置文件都不屑直接在wbpack的这个地方进行配置即可
// options:
// presets: ['@babel/preset-env'] //这边的配置也可以在babel.config.js中写
//
]
,
//处理图片
test: /\\.(jpe?g|png|webp|gif)$/, //指定对哪些文件进行处理,正则
use:[ //使用;可以使用对象、数组;写对象只有 一个loader,并且loader还有配置以及指定一些额外信息;对象是数组的简写,数组中可以有任意多的loader,但是数组这种方式不可以写配置
loader: 'url-loader', //babel也可以专门用配置文件babel.config.js或者.babelrc进行配置,也可以这两个配置文件都不屑直接在wbpack的这个地方进行配置即可。处理图片、字体、音视频等
options:
limit: 1024*15, //把小于15kb的进行base64处理
name:'img/[name].[ext]' //文件路径;相对于所有文件下面的;[name]文件名[ext]后缀扩展名
]
,
//处理css
test: /\\.css$/, //指定对哪些文件进行处理,正则
exclude: /(node_modules|bower_components)/, //不包括哪些文件
include:resolve('src'), //包括哪些文件
use:[ //使用;可以使用对象、数组;写对象只有 一个loader,并且loader还有配置以及指定一些额外信息;对象是数组的简写,数组中可以有任意多的loader,但是数组这种方式不可以写配置
MiniCssExtracPlugin.loader, //代替style-loader
// 'style-loader', //style-loader将js中的css放到style标签中去 配置多个loader整体的顺序是从下往上,从右往左。所以应该是css-loader放在style-loader的下面
'css-loader', //css-loader将css内容打包到js中去
'postcss-loader', //预处理css的,要在css前进行,因此由于loader加载顺序,放在css-loader的下面或者右边
]
,
//处理less
test: /\\.less$/, //指定对哪些文件进行处理,正则
exclude: /(node_modules|bower_components)/, //不包括哪些文件
include:resolve('src'), //包括哪些文件
use:[ //使用;可以使用对象、数组;写对象只有 一个loader,并且loader还有配置以及指定一些额外信息;对象是数组的简写,数组中可以有任意多的loader,但是数组这种方式不可以写配置
MiniCssExtracPlugin.loader, //代替style-loader
// 'style-loader', //style-loader将js中的css放到style标签中去 配置多个loader整体的顺序是从下往上,从右往左。所以应该是css-loader放在style-loader的下面
'css-loader', //css-loader将css内容打包到js中去
'postcss-loader',
'less-loader',
]
,
//处理stylus
test: /\\.(styl|stylus)$/, //指定对哪些文件进行处理,正则
exclude: /(node_modules|bower_components)/, //不包括哪些文件
include:resolve('src'), //包括哪些文件
use:[ //使用;可以使用对象、数组;写对象只有 一个loader,并且loader还有配置以及指定一些额外信息;对象是数组的简写,数组中可以有任意多的loader,但是数组这种方式不可以写配置
MiniCssExtracPlugin.loader,
// 'style-loader', //style-loader将js中的css放到style标签中去 配置多个loader整体的顺序是从下往上,从右往左。所以应该是css-loader放在style-loader的下面
'css-loader', //css-loader将css内容打包到js中去
'postcss-loader',
'stylus-loader'
]
]
,
//插件
plugins:[
//向页面中引入打包的js或者css代码
new HtmlWebpackPlugin(
template:'public/index.html' //指定以哪个为模板
),
//清除打包文件夹
new CleanWebpackPlugin(['dist']),
// new webpack.ProvidePlugin(
// jQuery: "jquery", //配置jquery
// $: "jquery"
// )
//从js中抽取css单独打包;一旦抽取了css就不需要cssloader了,需要换成这个插件里面的loader。单独打包css
new MiniCssExtracPlugin(
filename:'css/[name].css'
),
],
//开发服务器
devServer:
open:true //自动打开浏览器访问
,
//优化配置
optimization:
minimizer:[new OptimizeCssAssetsPlugin()]
7.19
4、css伪类实现三角形
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div
position:relative;
width:100px;
height:50px;
margin:100px auto;
box-shadow:0 0 2px green;
div:before
content:"";
position:absolute;
left: 100px;
top: 15px;
border-bottom:10px solid transparent;
border-left:10px solid green;
border-top:10px solid transparent;
</style>
</head>
<body>
<div></div>
</body>
</html>
5、什么是高阶组件?以及高阶组件的使用。高阶组件&高阶函数
高阶组件
是传入一个组件,返回一个组件。
connect
是一个返回高阶组件的高阶函数。接收组件,产出一个被Provider包裹的组件
高阶函数:
sort、filter
6、React生命周期
挂载中mounting
componentWillmount
componentDidMount
更新中updating
- componentWillReceiveProps
- componentWillUpdate
- componentDidUpdate
- shouldComponentUpdate
更新完成unmounting
- componentDidUnmount
7、setState同步还是异步?为什么会有这种情况产生?
异步,由于考虑性能原因,react会将多个state的操作合并,所以如果要是对state进行多次的setState操作的话,本质上是会进行Object.assign操作将多个操作合并到一起的。所以,如果是要防止这种情况产生,可以使用传入函数的方法进行state的设置,以及使用callback回调函数的方法,拿到修改后的值。
- setState是同步还是异步处理
- 异步处理,多次setState的时候,他们会将setState操作合并成一次进行处理。即会对其进行Object.assign操作处理
- 为什么setState要设计成异步
- 性能优化,多次操作合并成一次有利于提高性能
- setState除了可以接受一个对象之外还可以接收一个函数
this.setState((state)=>
return count:state.count+1
)
- setState传入的第二个参数是回调函数,可以在这里面获取state就是更新后的state
8、react diff有没有了解过
react的diff算法会帮我们计算出虚拟dom中真正变化的部分,并且只针对该部分进行实际的dom操作,而并非重新渲染整个页面。
diff策略
- Tree diff:跨层级dom操作:web UI中跨层级的dom操作比较少,可以忽略不计。
- 树进行分层比较,两棵树只会对同一层次的节点进行比较
- **出现了跨层级的怎么办?**跨层级的不会跨层级移动,只会整个删除并且重建(十分影响性能,因此官方并不推荐跨层级操作)
- Component diff:树形结构:拥有相同类的两个组件会生成相似的树形结构,拥有不同类的两个组件会生成不同的树形结构
- 同一类型的组件,继续按照diff策略进行比较
- 如果不是同一类型的,那么它就会被判定为dirty component,从而替换整个组件下的所有子节点
- 对于同一类型的组件,可能它的虚拟dom没有任何的变化。如果能确切知道这点,那么可以节省大量的diff运算时间,因此react允许用户通过shouldComponentUpdate来判断这个组件是否需要被update
- Element diff:同层级id区分:对于同一层级的一组节点,他们可以通过唯一的id进行区分
- 当处于同一层级的时候,react提供了三种操作,insert、move、remove。插入、移动、删除三种操作。
- **为什么要设置key?**因为同一级别元素,如果不设置key的话,如果将元素的位置进行了移动,会将元素进行删除重建工作,如果设置了key的话就只是remove的移动操作。相较于而言的话,移动操作的性能比删除重建高很多。
9、React fiber是什么?机制是什么?
React Fiber,这篇文章虽然比较久,但是十分通俗易懂。
React Fiber中一次更新会分成多次分片进行。React Fiber是React开发团队为了提高react的性能,解决由于js单线程,并且渲染线程和js执行线程共用同一个线程,导致的由于react diff等过程造成的页面卡顿的问题。因此,react从时间维度上进行了分片处理,将diff操作即reconcilation(协调)这个过程拆分成小的任务。通过合理的机制来调度时间,让reconcilation这个过程变成可控可中断的。适时地交出CPU的使用权限,让浏览器及时地跟用户进行交互。fiber的查分单位是fiber tree也就是按照虚拟的dom节点进行查分的,它的实现实际上是使用链表去实现的。
10、平常使用过React Hook了吗?它跟react class有什么区别呢?请简要介绍一下
(hooks还是很有意思,之后有必要写个demo具体使用一下)
组件之间复用状态逻辑很困难
比如复用同一个组件的时候由于判断状态逻辑等的不一致,会在生命周期中写大量不想管的代码,导致组件复杂
7.20
11、手写new的实现
var p = _new(Person,'aaa')
function _new(Fn,...args) //Fn是当前要new的类
var obj = new Object();
obj.__proto__ = Fn.prototype;
Fn.call(obj,...args)
return obj;
12、手写Promise加载一张图片
function loadImg(url)
return new Promise((resolved,rejected)=>
let img = document.createElement('img')
img.onload(function()
console.log('loaded')
resolved(url)
)
img.onerror(function()
console.log('error')
rejected(new Error('图片加载失败'))
)
img.src = url;
)
loadImg('http://...').then((res)=>
console.log(res)
)
13、Promise相关题目
【re】题目输出
const first = () =>(new Promise((resolve,reject)=>
console.log(3)
let p = new Promise((resolve,reject)=>
console.log(7)
setTimeout(()=>
console.log(5)
resolve(6) //一个promise值能执行一个resolve;这个在定时器中,比下面后执行,因此是执行下面的
,0)
resolve(1)
)
resolve(2)
p.then((arg)=>
console.log(arg)
)
))
first().then((arg)=>
console.log(arg)
)
console.log(4)
//3 7 4 1 2 5
如何实现链式调用?
比如实现:b.then().then().then()
- then方法:返回这个对象实例
- then方法:返回this
class Test
then()
console.log('test')
return this;
class Test1
then()
console.log('test1')
return new Test();
手写Promise的实现(then的链式调用)
promise特点分析:
- Promise参数函数会立即执行
- promise在then的回调函数中可以拿到resolve的值
- promise可以有多个then并且依次链式调用执行
- promise可以嵌套多个then,并且then中也是可以返回Promise
- resolved状态的promise调用then会立即执行
- 二次调用resolve不会产生影响
实现思路
- promise是一个对象,一般通过new进行实例化
- promise的then是可以链式调用的,因此要有then的链式调用的实现
- 根据列出的特定实现
- 实现Promise的构造方法和then方法
let State =
pending:'pending',
resolved:'resolved',
rejected:'rejected'
const noop = () =>
class myPromise
constructor(exclutor)
exclutor(this._resolve.bind(this),this._reject.bind(this)) //Promise回调函数立即执行
_state = State.pending;
_value;
_resolve(val)
this._val = val;
this._state = State.resolved;
//如果是resolved就去执行then中传入的回调方法,并且将resolve返回值给它
while(_resArr.length !== 0)
const item = _resArr.shift()
item(this._val)
_reject()
this._state = State.rejected;
_resArr = []
then(onRes,onRej = noloop)
const newPromise = new MyPromise(()=>)
this._resArr.push(onRes)
return newPromise; //返回Promise实现链式回调
14、闭包
闭包的两大作用
- 保护
- 保存
闭包在哪些地方应用到了?
- bind函数
(function()
function mybind(context=window,...args)
let _this = this;
return function(...innerArgs)
_this.call(context,...innerArgs.concat(args))
Function.prototype.mybind = mybind;
()
let obj =
name:'smileyqp'
document.body.onclick = fn.mybind(obj,100,200)
- 函数的柯里化:也就是应用闭包的思想。函数的柯里化也就是预处理。最简单的函数柯里化的demo:
function fn(a)
return function(b)
return a+b
fn(1)(2)
- 遍历:定时器中打印遍历的index
- 做一个cache工具:只对外提供api进行数据操作,不能直接对数据进行操作
function createCache()
const data = //闭包中的数据,被隐藏
return
set:(key,val)
data[key] = val;
,
get:(key)
return date[key]
15、https的ssl认证过程
- 客户端访问https链接
- 服务端发送公钥(证书)给客户端
- 客户端验证服务端的证书
- 是否合法、是否过期
- 客户端生成随机字符串,并且用服务端发送过来的公钥进行加密
- 服务端接收加密信息,并且用私钥解密随机数,通过传入随机数的对称加密对数据进行加密
- 服务器向客户端传输对称加密后的内容
- 客户端根据家本地存储的随机数进行解密
16、三次握手、四次挥手
三次握手
保证双方都知道对方的消息发送和消息接收的能力正常
- 客户端向服务端发送数据包
- 服务端向客户端回复
- 客户端给服务端回复
四次挥手
- 客户端向服务端发出断开链接消息
- 服务端向客户端发送接收到断开消息,并处于等待断开状态
- 服务端告诉客户端准备断开了
- 客户端恢复好的可以断开
7.20第一期完结撒花🎉🎉🎉嘻嘻嘻,接下来的话应该是再系统地一个系列review以及study啦!Fighting!
期间有一段时间没有更新,因为觉得有些没有必要再记录。现在回顾其实也忘记了自己这段时间有些什么进步成长或者学到了什么。之后坚持每天都有能够看得见的输入输出。即使是review复盘也坚持有迹可循。
8.2
1、Generator生成器函数
generator是ES6提供的一个生成器,执行generator可以返回一个迭代器,这个迭代器上有next方法。调用next后会返回两个属性value喝done。value是yield的返回值,done是表示迭代器是否有迭代完成,false表示没有迭代完成。
//具体使用方式
function* fn()
yield 1;
yield 2;
yield 3;
return 4;
const gen = fn(); //返回的是一个迭代器,可以调用next方法
console.log(gen.next()) // value: 1, done: false
console.log(gen.next()) // value: 2, done: false
console.log(gen.next()) // value: 3, done: false
console.log(gen.next()) // value: 4, done: true
如何判断一个函数是否是生成器函数?
Object.prototype.toString.call(function* ()) //=>"[object GeneratorFunction]"
generator函数和async和await有什么区别?
- await会等待promise执行完成之后才会去执行后面的代码,并且async函数会一次执行完毕
- generator函数是一步一步进行执行的,调用一次next函数执行一次下面的代码
- yield不会等待promise执行完毕的,获取promise中的结果还需要then来等待获取,只要调用next就会执行下面的代码
//async await demo
async function afunc()
const data = await new Promise((resolve,reject)=>
setTimeout(()=>
resolve(1)
,1000)
)
console.info(data)
await console.info(2)
//generator demo
function* gfunc()
yield new Promise((res,rej)=>
setTimeout(()=>
res(1)
,1000)
)
yield console.info(2)
const gen = gfunc()
//第一次执行next的时候,promise处于pending状态,只有手动then去等待promise执行完成之后才能拿到resolve的值
gen.next().value.then((data)=>console.info(data))
gen.next()
//先打印2 再打印1
2、for of遍历迭代器
for of
创建一个循环,遍历可迭代的对象。可以遍历String、Map、Set、generator生成器等等
3、react和vue的组件通信
共同点:
- 属性传递
- 发布订阅
- redux/vuex
- 本地存储
不同点:
-
react
- 属性
- 回调函数(属性方式将方法传给子组件,子组件调用传过来的函数)
-
vue
- 属性
- 发布订阅
3、Promise all以及Promise all的替代实现方式
Promise all传入promise数组,生成新的Promise实例,并且传入的promise数组所有的都返回了resolve才会执行之后的then,并且then接收的参数是所有resolve的值组成的数组。如果返回reject要在 cache中捕获错误
var p1 = Promise.resolve(1),
p2 = Promise.resolve(2),
p3 = Promise.resolve(3);
Promise.all([p1, p2, p3]).then(function (results)
console.log(results); // [1, 2, 3]
);
-
计数器
- 每次resolve,计数器加一,直到所有的完成了,返回resolve三个结果组成的数组
-
嵌套回调
- Promise中,上一次Promise返回的then中调用下一个,依次到最后一个promise的then,返回结果数组
以上是关于查漏补缺系列前端基础补充的主要内容,如果未能解决你的问题,请参考以下文章