中级:vue、react、webpack、babel

138 阅读14分钟

一,vue与react 的区别

1,设计区别

1,react更偏向js,是在写js代码。不像vue有那么多规则。比如方法要定义在methods里,数据要放data里。
2,react更多是在写js,vue更帖向html,结构,script,样式分离。它的规则决定了更好上手。
3,react 是函数式编程(this.setState({})) ,vue是声明式编程 (this.data.count = ''4, react要自己做更多事,只给一个底层的框架,要自己实现很多,比如循环,map函数 与 v-for的。
    而vue更像把想要的都给你,给很多指令,watch,computed,这些都是react没有的。

如果非得说要选择哪一个框架,对我个人而言,更倾向react。但是一个项目的成功与否要取决很多条件,
公司的情况,人员的配置。我们应该选择成本比较低的合理方案。并不是越难越好。

2,生命周期。

ajax通常放在mouted阶段,DOM渲染完毕。更加顺畅,因为ajax与DOM渲染共用一个进程,

放在其他生命周期,并不能更快的请求,也是要等到同步代码、DOM渲染后,才去请求。

3,代码具体实现区别

1,vue的双向绑定,v-model。react要自己实现onChange,通过setState来改变。
2,setState中第二个参数回调函数,类似vue中,this.$nextTick()

4,分别适用什么业务?

1,react 社区更加完善,有很多非常好的组件,更适合大型应用。
2,vue声明式编程,更易简单入手,react需要更深入的知识,去写功能,属性和结构。
3,vue的状态管理是vuex。react的状态管理则有非常多的方案:redux、mobx等等。

三,vue

1, v-show 和 v-if 的区别

1,v-show 通过css控制。v-if是组件的渲染和销毁。
2,频繁切换 使用 v-show

2,v-for 中为何使用key

1key 一定要用,且不能用index,用业务标志。
2,diff算法中通过tag 和 key 来判断是否是sameNode。减少更新,影响渲染性能。

3,组件如何通信

1,父子组件:props
2, this.$emit
3, 自定义事件
4,vuex
5,依赖注入:provide,inject
6,边界情况:this.$root ,  this.$parent
7, slot插槽

4,描述组件渲染、更新过程

初次渲染:
1,将模版转为render函数
2,触发响应式,监听data属性getter / setter
3,执行render函数,生成虚拟DOM:vnode,通过patch(elem,vnode)渲染界面。
更新过程:
1,vue会将data所有的属性转为 getter/setter
2,每个vue实例都有一个watcher,监听getter/setter3,当data变化,触发setter,会通知watch,执行render函数,生成vnode,再patch,对应组件更新。

画图。**render函数生成的是vnode。渲染和更新都要触发render,从图中就能看出来。

5,data必须是个函数

data如果不是函数,实例化时候,会造成data共享。保持数据独立。

6,ajax应该放在哪个生命周期

mounted。
因为ajax是异步,js是单线程。放到mounted之前,并不会提前执行,也是要放到callback queue排队,
等同步代码执行完才执行。

7,如何实现自定义v-model

8,多个组件有相同逻辑,如何抽离?

1mixin2mixin的缺点:不清楚来源。
33.0改进:composition API

9,何时使用异步组件?

1,加载大组件。
2,路由组件。
32.x:import('./components/AsyncComponent.vue')
43.0: defineAsyncComponent( () => import('../../..') )

10,何时使用缓存组件 keep-alive

1,不需要重复渲染的时候
2,多个静态tab页
3,性能优化。

11,何时使用beforeDestroy

1,解绑自定义事件(addEventListen)
2,清除计时器

12,vuex中的action 和mutation的区别

1,action做异步操作,mutation不行。
2,mutation通常做一个操作。
3,action可以做多个mutation的集合。

13,如何配置vue-router

new VueRouter(  // 3.0: createRouter
   routes:[ 
        {
            path: '',
            component: import('../../..')
        }
    ]
)

14,用vnode描述DOM结构

{
    tag:'div',
    props: {
        className: '..',
        id: 'id'
    },
    children: [
        {
            tag: 'ul'
        },
        {
            tag: 'p'
        }
    ]
}

15,监听data变化的核心API

1, Object.defineProperty
    Object.defineProperty(object1, 'property1', {
      value: 42,
      writable: false,
      set:function(){},
      get: ...
    });
2, 无法深度监听,无法监听数组。方案:重新定义原型(不改变Array原生能力),重写push,pop方法。
3, 缺点:深度监听需要一次性递归到底。
4, 3.0new proxy({},{ // 原生支持数组
        set:function(){},
        get:function(){},
        deleteProperty:..
    })

16,diff算法

diff算法的目的是获得最新的vnode,vnode{children ,text,tag ,}patch最终即可生成html。

diff:将时间复杂度 O3 - O1
只比较统一层级,不做跨级比较
tag不相同,直接删除重建,不做深度比较
tag和key相同,则认为是相同节点,不继续比较。

17,$nextTick

1, 因为vue是异步渲染。
2,确保在DOM更新之后,获取最新DOM。

18,vue的常见性能优化

1,v-show 、v-if
2,computed 缓存
3,v-for 中使用key
4,异步(动态)组件
5,缓存组件
6,beforeDestroy中及时销毁
7data层级不能太深(影响深度监听,一次性递归)
8,SSR

19,原理:mvvm

1,mvvm 区别于传统组件,不是操作dom,抛弃jq。
2,数据驱动视图,让我们更专注数据(业务)
3,view(视图) - viewModel(监听事件,指令) - Model(数据模型,就是vue组件中的data)

20,虚拟DOM

因为DOM操作非常消耗性能,所以用js对象模拟DOM结构,来进行计算和对比,以最小的更新范围来更新DOM。
对比的过程就是diff算法。
核心API:
h():传入tag标签(属性,标签,值) 生成vnode。
patch(vnode,newVnode):对比  ,渲染或更新到DOM节点上
diff

21,vue原理的总结

几个核心:
模板编译生成vnode -> 虚拟DOM -> diff算法
模板编译:
1,vue template complier 返回with语句。 将模板编译为render函数
2,执行render函数,生成vnode
3,vnode最终通过虚拟Dom,diff算法,,最终生成html。
----* 所以vue-template最终是生成vnode 

回答原理:
回答几个大点,每个大点涉及哪些知识点或API,串联起来即可。

22,vuex与全局变量的区别

1,vuex的变量是响应式的
2,vuex的变量是可跟踪的,追踪它的变化
3,vuex是由统一的方法修改数据,全局变量可随意修改。
4,全局变量会造成命名污染

23,computed (计算属性)与 watch(侦听器)的区别

1,computed 是基于它的响应式依赖,当依赖改变时,才会重新求值
2,watch 监听的数据必须在data定义,当data发生变化时,触发。不能return值。
watch有三个属性:deep,handler,immdiate。

四,react

1,组件如何通信

1,父子组件 props
2,自定义事件
3,redux 和 context

2,context是啥

1,父组件,向其所有子孙组件传递信息
2,场景:一些公共信息的传递,如语言,主题。

3,shouldComponentUpdate

1,性能优化
2,应该配合 “不可变值” 一起使用,否则会报错
3, shouldComponentUpdate 返回false,不更新组件。返回true则更新。
3*, 一旦有数据变化,组件就会更新(不管该数据是否在组件内)

5,class组件与 函数组件的区别

1,如果组件只接收一个props,用函数组件
2,函数组件,没有state,没有生命周期。简易版的class组件。
3,函数组件更复合设计理念,函数式编程,react hooks提供了方案。

6,受控组件 与 非受控组件

受控组件就是:
1,自己用state控制表单的值。自定义实现onChange事件,来更新state。
非受控组件:
1,非受控组件,就是将数据交给DOM节点来处理。使用 React.createRef 来实现。

使用区别:
页面的数据,并不会随着表单的输入而改变。

7,何时使用异步组件

1,加载大组件。
2,路由懒加载。router: import
3APIlazy()、Suspend()
4,同vue一致,使用异步组件,webpack可以打成独立的bundle,按需加载。

8,组件公共逻辑如何抽离

1,高阶组件:HOC,只是一种模式,并不是新功能或API
2,Render Props 。将函数当作Props传递。

9,PureComponent

1,实现了浅比较的shouldComponentUpdate
2,用于性能优化
3,结合不可变值使用

10,react事件 与 DOM事件的区别

1,react事件,全部都挂载到document上。
2,react的event对象不是原生对象,是合成对象SyntneticEvent。
原因如下原理。

11,react的性能优化

1,不可变值 配合 shouleComponentUpdate
2, PureComponent 、memo
3, for循环使用key
4,自定义事件,计时器的及时销毁。useEffect可以返回一个销毁函数。
5,使用异步组件

12、redux (react-redux)

1,redux 提供createStore,接收reducer参数。集合了所有store(vuex)
2,react-redux 提供了Provide和connect。(mapStateToProps,mapDispatchToProps)
3,用connect连接的组件,props能接收到store,和dispatch
4,dispatch 触发reducer 接收一个action,和旧的state:
    dispatch(action(newState))
5, redux的设计思想,容器组件(维护state) 和 UI组件(只渲染)。

异步实现:
使用中间件:redux-thunk
先执行ajax,再dispatch同步action

13,redux的设计理念

为什么要引入这么多复杂的概念:action,reducer,dispatch,store?
因为大型应用state什么时候,如何改变,没法追述缘由。
1,action:用来描述state的变化(type,text),只是一个普通的对象。
2,reducer的目的就是连接变化,和旧的state,返回新的state。必须是纯函数
3,唯一改变state的方式就是触发action。

四,react原理

1,react原理汇总

1,函数式编程:不可变值, 纯函数(不改变对象本身)
2,vdom,diff算法
3,JSX本质
4,合成事件
5,setState,batchUpdate
6,组件渲染过程

2,JSX本质是什么

1,babel 默认会编译JSX。类似vue-template-complier编译vue-temppate,会生成render函数
2,编译后的JSX,是React.createElement(),会生成vnode ,其实就是VDom里面的 h 函数。
    参数:(标签,属性,子节点,子节点,..)
3,所以严格规定了 JSX里面,标签要小写,组件名要大写。不然createElement在解析的时候,没法识别是
组件或者标签。

3,合成事件

1,react所有事件都绑定到document。
2event不是原生的,是合成的原生对象。不同Vue事件,和DOM事件。syntneticEvent
3,原生对象挂在:event.nativeEvent.
event.currentTarget //指向当前对象,是假象。
实际,event.nativeDocument.currentTarget //指向document

为什么:
1, 更好的兼容性和跨平台
2,全部挂到document上,减少内存消耗,避免频繁解绑
3,方便事件统一管理,dispatchEvent(事务机制)

4,setState,batchUpdate

1,setState 一定要遵循不可变值。即在setState外面,不能改变state本身的值。
    在用一些函数的时候要注意,尽量用纯函数,不改变对象本身的值。如forEach,push,pop等会改变。
2,setState有同步的情况,也有异步的情况。
    a,直接使用的话,是异步的。当然可以在setState里传回调函数。
    b,在setTimeout 或 自定义DOM事件中,是同步的
3,因为在执行setUpdate的过程中,会判断是否处于 batch update阶段,
会存到dirtyComponent。否的话:遍历dirtyComponents,updateComponent,更新state,props。

4,setState也有可能会合并的情况,如果同时修改某个值。如果参数是函数,则不会合并。

batchUpdate:
batchUpdate 就是setState 走同步或者走异步的原因。
1,调用setState时,newState 是否处于batch UpState中。
(如何判断呢:isBatchingUpdates,是true或者false2,是true的话就是在batchUpdate中(异步)。newState就保存在dirtyComponent中
3,是false的话,就不是处于batchUpdate中(走同步代码)

5,组件渲染、更新过程

渲染:
1, 组件接收数据props 或 state2,render函数生成vnode。解析JSX就是createElement()
3,patch(ele,Vnode)。渲染到界面上。patch只是一个统称,vDOM一个核心渲染api。

更新:
1,通过setState将组件存到dirtyComponent中。
2,然后遍历所有的dirtyComponent,通过render函数生成vnode。
3,patch()

6,react-fiber  时间调度原理

背景:复杂组件diff算法复杂,同时又存在DOM操作,如(拖拽),会造成页面卡顿。
    因为DOM渲染和js公用一个线程。

diff算法分两步:计算js 和 渲染到DOM
react-fiber 就是优化 计算的这部分。

做法就是:
在DOM渲染的时候暂停,在DOM空闲时恢复。
react时间调度原理:利用 requestAnimationFrame 实现requestIdleCallback(计算一帧剩余的时间。)

五,组件设计

1,何为组件和状态设计

1,单考状态(state,data),单考组件没办法考察能力。
2,根据具体的业务场景,如何设计组件,设计数据,父子组件如何通信?
3,不应该像以前一样,拿到一个需求,就嘎嘎嘎干,做着做着就想着分组件,数据也乱加。

2,如何设计状态 和 组件

错误:以前都是思考组件,没想到数据,通过代码量来分组件。。

state设计:
1,用数据描述所有的内容
2,数据尽量结构化并且层级不能太多,便于遍历,查找 及性能优化。(对象,数组)。
    eg:字符串就不是结构化数据。
3,数据要可扩展,方便增加新功能。

组件设计:
1,要从功能上拆分层次。
2,组件原子化,尽量让组件只做一件事。功能很复杂。。组件很简单
3,容器组件(只管数据,操作数据) 和 UI组件(只管视图,只管交互,给我什么就展示什么)
    所以,通常容器组件是最外层,汇总。负责给其他子UI组件传数据。

六,webpack - 使用

1,webpack 如何配置多入口

场景:SPA?如果是要打包多页面应用。不同页面引用不同js
1,entry:{
    app:..,
    other
}
2, output : {
    filename: [name].[contentHash].js
}
3, plugins: [
    new HtmlWebpackPlugin({
        template: ...,
        chunk: ['app'] //只记载app解析出的相关js
    })
    new HtmlWebpackPlugin({
        template: ...,
        chunk: ['other'] //
    })]

2、如何抽离css,并且压缩

1,miniCssExtractPlugin
2,OptimizeCssAssetsPlugin

3,如何抽离公共代码、第三方代码。

* chunk 的概念指的是代码块。
因为第三方类库更新频率不高,这样浏览器可以直接从缓存读,不需要项目每次上线再获取一次。
new HtmlWebpackPlugin({            
    template: path.resolve(__dirname, '../other.html') ,            
    chunks: ['other', 'vender', 'common'] //指定引入哪些代码块  
      }),

4,webpack 如何实现异步加载js

webpack 默认异步支持。只要:
import'...')。会单独产出一个包(chunk)
使用:
异步:import('..').then().
同步 : import 'xx.js'

5, 如何理解chunk、module、bundle

module:一切皆模块:img,js,css。除了html
chunk :是多个模块的集合。webpack的分析过程产生的一些代码块。
bundle:最终输出的文件。
结合如下例子回答:官网首页图。
有产生chunk的地方: entry 、 splitChunk、异步加载
有引用chunk的地方:htmlWebpackPlugin

七,webpack - 性能优化

1,总结性回答

webpack的性能优化可以从两方面去回答:

a,优化开发的构建速度
    优化babel-loader :
        更快的编译es6。开启缓存,对于没有改变的不重新编译。cacheDirectory
        include / exclude
    noParse
    IgnorePlugin: 忽略没有用的文件。
        eg:忽略时间的多语言。
        new webpack.IgnorePlugin(/\.\/locale/, /moment/)    
    //适用项目较大,打包较慢。
    happyPack:
        多进程打包
    ParallelUglyPlugin
        多进程压缩js

    自动刷新、热更新:
        webpack-dev-Server
        HotModuleReplacementPlugin
    DllPlugin:提前打包较大的第三方库


b,优化产出的代码
    图片打包成base64
    抽离css
    hash ,利用浏览器缓存
    抽离第三方库
    抽离公共模块,防止重复引用
    异步加载(懒加载)
    IgnorePlugin    

-- 按需加载:通常在路由层控制。而不是一个组件加载一个js。有可能会造成多个网络开销。
component: () => import(/* webpackChunkName: "about" */ '../views/release/index.vue')webpackChunkName 就是打包出来的组件名称  
所有的异步加载组件,都将独立生成一个bundle

2,noParse

不需要解析哪些库:module: {       
     noParse: /loadsh/,  //不需要解析的库
}

3, DllPlugin

对一些不变的库,不需要重复构建,构建一次就好,然后进行引用。
eg:react,vue,react-dom,

new webpack.DllReferencePlugin({ //在开发中使用更合适        context: __dirname,        manifest: require('./dll/vue.manifest.json') })

4,webpack的资源持久化缓存

hash
contenthash:根据内容来计算hash值。

5,webpack打包应用的大小监测与分析

1,webpack chart  在线分析工具: 每一部分由哪些组成的。
webpack --profile --json > stats.json
2,source-map-explorer *.js //针对sourceMap文件进行分析,看到百分比。配置在script命令里
3,webpack-bundle-analyzer  先执行看结果。再对比优化后的结果

八,babal

1,babel-polyfill

a,根据浏览器当前情况,做兼容。自动以最新的语法解析。依赖于 core-js。集成了最新的语法。
配置:"useBuiltIns": 'usage' //polifill 按需引入。转哪些新语法,就引入哪些polyfill
babel-polyfill 是core-js 和 regeneretor 的集合
所以,在babel 7.4 之后,babel-polyfill被弃用,建议直接引入上面两个库。

九,小程序

生命周期:onHide,onReady、onSHow、onLoad
rpx 1rpx = 0.5px。建议以iphone的设计稿为基础,在此基础下1px = 2rpx。