React 基础回顾

1. React 介绍 React 是一个用于构建用户界面的 JavaScript 库,它只负责应用的视图层,帮助开发人员构建快速且交互式的 web 应用程序。 React 使用组件的方式构建用户界面。 2. JSX 语法 在 React 中使用 JSX 语法描述用户界面,它是一种 JavaScript 语法扩展。 在 React 代码执行之前,Babel 会将 JSX 语法转换为标准的 JavaScript API。 JSX 语法就是一种语法糖,让开发人员使用更加舒服的代码构建用户界面。 2.1 在 JSX 中使用表达式 const user = { firstName: 'Harper', lastName: 'Perez' } function formatName(user) { return user.firstName + ' ' + user.lastName; } const element = <h1>Hello, {formatName(user)}!</h1>; JSX 本身其实也是一种表达式,将它赋值给变量,当作参数传入,作为返回值都可以。 function getGreeting(user) { if (user) { return <h1>Hello, {formatName(user)}!...

2021年01月26日 · 士子☀  · 

VirtualDOM 及 Diff 算法

Virtual DOM 及 Diff 算法 1. JSX 到底是什么 使用 React 就一定会写 JSX,JSX 到底是什么呢?它是一种 JavaScript 语法的扩展,React 使用它来描述用户界面长成什么样子。虽然它看起来非常像 HTML,但它确实是 JavaScript 。在 React 代码执行之前,Babel 会对将 JSX 编译为 React API. <div className="container"> <h3>Hello React</h3> <p>React is great </p> </div> React.createElement( "div", { className: "container" }, React.createElement("h3", null, "Hello React"), React.createElement("p", null, "React is great") ); 从两种语法对比来看,JSX 语法的出现是为了让 React 开发人员编写用户界面代码更加轻松。 Babel REPL 2. DOM 操作问题 在现代 web 应用程序中使用 JavaScript 操作 DOM 是必不可少的,但遗憾的是它比其他大多数 JavaScript 操作要慢的多。 大多数 JavaScript 框架对于 DOM 的更新远远超过其必须进行的更新,从而使得这种缓慢操作变得更糟。...

2021年01月26日 · 士子☀  · 

React 设计原理解密及核心源码解读

React 基础回顾 笔记 Virtual DOM & Diff 算法 笔记 github

2021年01月23日 · 士子☀  · 

Vue.js + Vuex + TypeScript 实战项目开发与项目优化

说说 application/json 和 application/x-www-form-urlencoded 二者之间的区别。 application/x-www-form-urlencoded方式是Jquery的Ajax请求默认方式,这种方式的好处就是浏览器都支持,在请求发送过程中会对数据进行序列化处理,以键值对形式,例如: key1=value1&key2=value2的方式发送到服务器。如果用Jquery,它内部已经进行了处理,如果自己写原生的Ajax请求,就需要自己对数据进行序列化。 application/json,随着json规范的越来越流行,并且浏览器支持程度原来越好,许多开发人员将application/json作为请求content-type,告诉服务器请求的主体内容是json格式的字符串,服务器端会对json字符串进行解析,这种方式的好处就是前端人员不需要关心数据结构的复杂度,只要是标准的json格式就能提交成功,application/json数据格式越来越得到开发人员的青睐。 说一说在前端这块,角色管理你是如何设计的。 创建路由列表和菜单列表(左侧/顶部),两者格式相似,菜单就是多些图标啥的字段 将路由列表分为两部分:登录后才能看的(权限列表)和未登录也能看的(游客列表) 为权限列表里的每个路由添加角色数组字段,里面的角色才能访问此路由 在路由配置文件中添加跳转到新页面前的导航钩子,在里面根据用户登录后返回的角色信息,与权限列表进行比对,计算得出其所能访问的路由列表,保存到 vuex 中 通过 router.addRoutes() 方法,将两个列表拼接起来(Vue 框架) 同样对比计算得出可见的菜单列表,赋值并保存到 vuex 中 显示页面 @vue/cli 跟 vue-cli 相比,@vue/cli 的优势在哪? 首先说一些vue-cli这些工具的初衷吧: 这些工具就是为了让开发者能够开箱即用快速地进行应用开发而开发的,它们秉承的是“约定大于配置”思想,简单说就是"能不配置的就不配置,你就按照我的方式来,也不要去争论这个好不好,快速进行业务开发才是正经事". 它们不建议你去配置,但也不会拦着你去配置。 另外Webpack对初学者并不是十分友好,‘又长又臭’的配置,普通开发者很难写入定义良好,性能优化的配置。不然就不会各种cli工具冒出来了,比如parcel,create-react-app。这些工具都宣称零配置,目的就是让开发者能够愉快的进行代码开发。 详细讲一讲生产环境下前端项目的自动化部署的流程。 你在开发过程中,遇到过哪些问题,又是怎样解决的?请讲出两点。 需求不明确、自己对需求存在误区和不理解 对需求有不同见解的地方或者需要改进, 另外就是对设计有类似的问题。 针对新技术,你是如何过渡到项目中?

2021年01月23日 · 士子☀  · 

Vue.js 3.0 Composition APIs 及 3.0 原理剖析

Vue 3.0 性能提升主要是通过哪几方面体现的? 响应式系统升级:vue3使用了 proxy 重写了响应式系统,因为 proxy 可以对整个对象进行监听,所以不需要对整个对象深度遍历 编译优化:vue3中标记和提升所有的静态节点,diff过程中只需要对比动态节点 源码体积优化:vue3中移除了不经常使用的API,tree-sharking减小打包体积 Vue 3.0 所采用的 Composition Api 与 Vue 2.x使用的Options Api 有什么区别? Options Api: 包含一个描述组件选项(data,methods,props)的对象;开发复杂组件,同一个功能代码被拆分到不同选项中; Composition Api: 一组基于函数的API;可以灵活的组织组件的逻辑;更好的类型推导,容易集合TypeScript; Proxy 相对于 Object.defineProperty 有哪些优点? 可以监听动态属性的添加;可以监听到数组的索引和数组length属性;可以监听删除属性;多层属性嵌套,在访问属性过程中处理下一级属性 Vue 3.0 在编译方面有哪些优化? vue2中采用标记静态根节点,优化diff过程,来减少操作dom;vue3中标记和提升所有静态根节点,diff过程只需要对比动态节点;Fragments;静态提升;Patch flag;缓存事件处理函数 Vue.js 3.0 响应式系统的实现原理? reactive 接受一个参数,typeof判断这个参数是否是对象,不是对象直接返回这个参数,不能用reactive做响应式处理 是对象,创建响应拦截器handler,里面实现get/set/deleteProperty get:通过track收集依赖,通过Reflect.get获取当前key的值,注意这里如果key的值是个对象,要为该对象创建响应拦截器递归调用reactive set:先比较新旧value是否相等,相等直接返回,不想等,通过Reflect.set设置新的value,并通过trigger触发更新,最后记得返回boolean值,否则会报warn deleteProperty:当前对象有这个key值,删除这个key,并通过trigger触发更新,最后记得返回boolean值,否则会报warn effect 接受一个函数作为参数,记得把函数赋值给全局对象activeEffect,作用是访问响应式对象属性时区收集依赖 track 接受两个参数target和key 如果没有 activeEffect,则说明没有创建 effect 依赖 如果有 activeEffect,则去判断 WeakMap 集合中是否有 target 属性 WeakMap 集合中没有 target 属性,则 set(target, (depsMap = new Map())) WeakMap 集合中有 target 属性,则判断 target 属性的 map 值的 depsMap 中是否有 key 属性 depsMap 中没有 key 属性,则 set(key, (dep = new Set())) depsMap 中有 key 属性,则添加这个 activeEffect trigger 判断 WeakMap 中是否有 target 属性 WeakMap 中没有 target 属性,则没有 target 相应的依赖 WeakMap 中有 target 属性,则判断 target 属性的 map 值中是否有 key 属性,有的话循环触发收集的 effect()

2020年11月03日 · 士子☀  · 

Vuex 数据流管理及Vue.js 服务端渲染(SSR)

使用NuxtJS实现 RealWorld 全部功能 https://demo.realworld.io/#/ 要求:发布码云上,可以直接展示网页 仓库地址: https://gitee.com/caorushizi/realworld 预览:http://ziying.site/realworld/

2020年09月23日 · 士子☀  · 

搭建自己的SSR、静态站点生成(SSG)及封装 Vue.js 组件库

作业要求 使用 Gridsome 实现下面博客内容。 实现左侧前四个侧边栏的效果和内容。 项目地址 https://github-laziji.github.io/#/user/new/main 仓库地址: https://gitee.com/caorushizi/vblog 预览:http://ziying.site/vblog

2020年09月23日 · 士子☀  · 

Vue.js 源码剖析-响应式原理、虚拟 DOM、模板编译和组件化

一、简答题 1、请简述 Vue 首次渲染的过程。 Vue 初始化:初始化 vue 的实例成员、静态成员; new Vue():初始化结束之后,调用 vue 构造函数。构造函数中调用了 this._init() ,这个方法相当于vue的入口,最终调用 vm.$mount() ; 调用入口文件的 vm.$mount():这个方法主要是将模板编译成 render 函数。先判断是否传递了 render 选项,如果没有传递 render ,就把模板编译成 render 函数。这个过程是通过 compileToFunctions() 生成 render() 渲染函数 (new Function)。最后将 options.render = render; 调用runtime版本中的vm.$mount():在这个方法中会重新获取 el 调用 lifecycle.js 中的 mountComponent(this, el):方法中先判断是否有render选项,如果没有但是传入了模板,并且当前是开发环境的话会发送警告;触发 beforeMount ;然后定义 updateComponent ,这个方法中会调用 vm._render() 渲染虚拟dom ,调用 vm._update() 将虚拟dom转换成真实dom;然后创建 Watcher 实例,创建过程中传入了 updateComponent 会在 Watcher 内部调用 ,再调用 get() 方法;然后触发 mounted ,最终返回 vm ;...

2020年09月07日 · 士子☀  · 

手写 Vue Router、手写响应式实现、虚拟 DOM 和 Diff 算法

一、简答题 当我们点击按钮的时候动态给 data 增加的成员是否是响应式数据,如果不是的话,如何把新增成员设置成响应式数据,它的内部原理是什么。 let vm = new Vue({ el: '#el', data: { o: 'object', dog: {} }, method: { clickHandler () { // 该 name 属性是否是响应式的 this.dog.name = 'Trump' } } }) 不是响应式的,对于已经创建的实例,Vue不允许动态添加根级别的响应式属性 使用Vue.set(vm.dog, ‘name’, ‘dog_name’)或this.$set(this.dog, ‘name’, ‘dog_name’) this.$set在new Vue()时候就被注入到Vue的原型上,set方法内部仍是调用了defineReactive()方法进行响应式处理 请简述 Diff 算法的执行过程 diff的过程就是调用名为patch(el, vnode)/patch(oldVnode, vnode)的函数,比较新旧节点,一边比较一边给真实DOM打补丁 patch里会调用sameVnode(oldVnode, vonde),根据返回结果: true: 则执行patchVnode false: 则用vnode替换oldVnode patchVnode(oldNode, vnode, insertedVnodeQueue) 找到对应的真实DOM,成为el 判断vnode和oldVnode是否指向同一个对象,如果是,直接return 如果它们都有文本节点并且不相等,那么将el的文本节点设置为vnode的文本文本节点 如果oldVnode有子节点而vnode没有,则删除el的子节点 如果oldVnode没有子节点而vnode有,则将vnode的子节点真实化之后加到el 如果两者都有子节点,则执行updateChildren(parentElm, oldCh, newCh)函数比较子节点(key很重要) 二、编程题 模拟 VueRouter 的 hash 模式的实现,实现思路和 History 模式类似,把 URL 中的 # 后面的内容作为路由的地址,可以通过 hashchange 事件监听路由地址的变化。 let _Vue = null export default class VueRouter { static install (Vue) { // 1....

2020年09月07日 · 士子☀  · 

开发脚手架及封装自动化构建工作流

一、简答题 1、Webpack 的构建流程主要有哪些环节?如果可以请尽可能详尽的描述 Webpack 打包的整个过程。 根据用户在命令窗口输入的参数以及 webpack.config.js 文件的配置,得到最后的配置。 根据上一步得到的最终配置初始化得到一个 compiler 对象,注册所有的插件 plugins,插件开始监听 webpack 构建过程的生命周期的环节(事件),不同的环节会有相应的处理,然后开始执行编译。 根据 webpack.config.js 文件中的 entry 入口,开始解析文件构建 AST 语法树,找出依赖,递归下去。 递归过程中,根据文件类型和 loader 配置,调用相应的 loader 对不同的文件做不同的转换处理,再找出该模块依赖的模块,然后递归本步骤,直到项目中依赖的所有模块都经过了本步骤的编译处理。编译过程中,有一系列的插件在不同的环节做相应的事情,比如 UglifyPlugin 会在 loader 转换递归完对结果使用 UglifyJs 压缩覆盖之前的结果;再比如 clean-webpack-plugin ,会在结果输出之前清除 dist 目录等等。 递归结束后,得到每个文件结果,包含转换后的模块以及他们之间的依赖关系,根据 entry 以及 output 等配置生成代码块 chunk。 根据 output 输出所有的 chunk 到相应的文件目录。 2、Loader 和 Plugin 有哪些不同?请描述一下开发 Loader 和 Plugin 的思路。 答:Loader 专注实现资源模块的转换和加载(编译转换代码、文件操作、代码检查);Plugin 解决其他自动化工作(打包之前清除 dist 目录、拷贝静态文件、压缩代码等等) 二、编程题 1、使用 Webpack 实现 Vue 项目打包任务 具体任务及说明: 先下载任务的基础代码 百度网盘链接: https://pan....

2020年08月23日 · 士子☀  · 

开发脚手架及封装自动化构建工作流

简答题 1、谈谈你对工程化的初步认识,结合你之前遇到过的问题说出三个以上工程化能够解决问题或者带来的价值。 答:前端工程化课题提高开发效率,避免人工操作失误。可以开发业务工程脚手架,自动化构建,以及组件化、模块化等;可以使用工程化在发布生产前添加代码质量检查工具,提升开发时的效率以及在开发中不必要的错误; 2、你认为脚手架除了为我们创建项目结构,还有什么更深的意义? 提升效率,可以快速搭建一个基础项目架构;规范化 对技术选型、项目结构等做一些规范,以降低沟通成本 编程题 1、概述脚手架实现的过程,并使用 NodeJS 完成一个自定义的小型脚手架工具 答:1、创建一个仓库(目录) 2、通过npm init 初始化 3、创建一个入口js文件 4、package.json 文件增加"bin":“入口文件路径” 5、通过npm link命令连接全局 6、命令行运行脚手架命令 7、后面可以通过npm publish发布到npm仓库 2、尝试使用 Gulp 完成项目的自动化构建 package.json { "name": "pages-boilerplate", "version": "0.1.0", "private": true, "description": "Always a pleasure scaffolding your awesome static sites.", "keywords": [ "pages-boilerplate", "boilerplate", "pages", "zce" ], "homepage": "https://github.com/zce/pages-boilerplate#readme", "bugs": { "url": "https://github.com/zce/pages-boilerplate/issues" }, "repository": { "type": "git", "url": "git+https://github.com/zce/pages-boilerplate.git" }, "license": "MIT", "author": { "name": "zce", "email": "w@zce....

2020年08月05日 · 士子☀  · 

ES 新特性与 TypeScript、JS 性能优化

简答题 一、请说出下列最终的执行结果,并解释为什么。 var a = [] for (var i = 0; i < 10; i++) { a[i] = function () { console.log(i) } } a[6]() 最终结果是在控制台输出10;for循环中使用var定义变量没有块级作用域,在a[6]方式执行的时候会根据js的词法作用域向上查找找到的i是已经经过++操作的10; 二、请说出下列最终的执行结果,并解释为什么。 var tmp = 123 if (true) { console.log(tmp) let tmp } 最终结果会出现引用错误;在if的代码块中出现了let声明变量,所以在if代码块中就出现了tmp变量的暂时性死区,js的编译器会抛出引用错误; 三、结合ES6新语法,用最简单的方式找出数组中的最小值。 var arr = [12, 34, 32, 89, 4] Math.min(...arr) 四、请详细说明var, let, const三种声明的方式之间的具体差别。 var声明变量是会出现变量提升,而let和const不会;var可以重复定义,而let和const不行;let和var定义的变量可以被改变,而const不可以; 五、请说出下面代码最终输出的结果,并解释为什么。 var a = 10 var obj = { a: 20, fn () { setTimeout(() => { console....

2020年08月03日 · 士子☀  · 

ES 新特性与 TypeScript、JS 性能优化

ECMAScript 概述 最佳实践:不用var,主要使用const,配合let

2020年07月26日 · 士子☀  · 

函数式编程与JS异步编程、手写Promise

简答题 谈谈你是如何理解JS异步编程的,EventLoop、消息队列都是做什么的,什么是宏任务,什么是微任务? javascript 为了实现浏览器页面的交互,不得不使用单线程的方式渲染页面,以保证 dom 可以被正确的渲染。然而单线程就以为着浏览器有多个任务的时候需要排队依次执行,这样就会造成阻塞。event loop 主线程从消息队列中读取事件,这个过程是一直重复循环的,所以整个机制被称作event loop。消息队列是暂时存放异步任务的地方,我们的异步代码会存放到消息队列中,等到同步代码执行完毕以后,event loop会从消息队列中依次取出异步任务放到调用栈中再次执行。宏任务可以理解是每次执行栈执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行)。微任务可以理解是在当前 task 执行结束后立即执行的任务。也就是说,在当前task任务后,下一个task之前,在渲染之前。 代码题 一、将下面的异步代码使用Promise的方式改进 setTimeout(function () { var a = 'hello' setTimeout(function () { var b = 'lagou' setTimeout(function () { var c = 'I ❤️ U' console.log(a + b + c) }, 10) }, 10) }, 10) function genPromise (text) { return new Promise(resolve => { setTimeout(() => { resolve(text) }, 10) }) } (async () => { const a = await genPromise('hello') const b = await genPromise('lagou') const c = await genPromise('I ❤️ U') console....

2020年07月21日 · 士子☀  ·