0%

图床测试
中等大小:OrPPjY.jpg

性能优化进阶

面试:在代码执行之前,浏览器加载页面发生了什么?
=> 浏览器原理
=> 广度:DOM 渲染、存储…

打印当前页面耗时:

1
2
3
4
5
6
7
8
9
// index.html
<script>
javascript:(()=>{
const perfData = window.perfomance.timing
cosnt pageLoadTime = perData.loadEventEnd - perData.navigationStart // 时间戳之差

console.log('当前页面加载耗时:',pageLoadTime,'ms')
})
</script>
阅读全文 »

函数式编程

起源

历程:
命令式(脚本) => 面向对象式
命令式(脚本) => 函数式

解决代码复用的问题

原理特点

什么是函数式原理

  • 加法结合律 | 因式分解 | 完全平方工时

  • 水源 => 组合(水管 + 走线) => 花洒

理论思想

  1. 一等公民——函数 => 1.逻辑功能最终实现的落脚点 2.实现函数+拼接流程
  2. 声明式编程
  3. 惰性执行-衔接性,性能节约

实际开发

1.纯函数改造

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const _class = {
name: 'objective',
}
// 函数内部引入了外部变量
const score = (str) => _class.name + ':' + str
// 直接修改了输入参数
const changeClass = (obj, name) => (obj.name = name)

/***** ↓ 修改后 ↓ *****/
const _class = {
name: 'objective',
}

const score = (obj, str) => obj.name + ':' + str
const changeClass = (obj, name) => ({ ...obj, name })

changeClass(_class, 'functional')
score(_class, 'good')

2.流水线组装-加工&组装

  1. 加工 - 科里化
1
2
3
4
5
6
7
8
// f(x,y,z) => f(x)(y)(z)
const add = x => y => z=> return x+y+z;
add(1)(2)(3) // 6
// 要实现 体系=加工+组装,单个加工输入输出应该单值化 => 单元函数
const fetch = ajax(method,url,params);
const fetch = ajax.get(method);
const request = fetch(url);
组合(fetch,request);

面试题

手写构造可拆分传参的累加函数
add(1)(2)(3)(4)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 构造科里化结构
// 输入 处理外层arguments => 类数组处理
// 传入参数无线拓展 => 返回函数本身
// 主功能 => 累加
// 输出 支持从函数到产出的转换
const add = function (...nums) {
// input
let args = Array.prototype.slice.call(arguments)
// 内层
let inner = function (...nums) {
args.push(...arguments)
return inner
}
inner.toString = function () {
return args.reduce((prev, cur) => {
return prev + cur
})
}
return inner
}
  1. 流水线 - 组装函数
1
2
3
4
5
6
const compose = (f, g) => (x) => f(g(x))

const sum1 = (x) => x + 1
const sum2 = (x) => x + 2
const sum12 = compose(sum1, sum2)
sum12(1)

常见的三方库

lodash

rxjs

概念

JavaScript 在浏览器下一般三部分组成:
ECMAscript DOM BOM

W3C 是非标准化组织,制定浏览器规范

ECMAscript:是一种标准,用来标准化 JavaScript 语言,es6、es7 都是其标准化的产物。在浏览器中以 V8,JSCore 等引擎解析。

MDN:Mozilla Developer Network 规范文档

阅读全文 »

test

vue-cli

  • 基础:用于生成项目文件体系的搭建 + 用户交互
  • metadata 配置(元数据)
  • parser & render

vue-cli_2.x.x

/bin/vue-init 前置工作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 下载远程仓库 => 远程拉去github内的配置
const download = require('download-git-repo')
// 命令行处理工具
const program = require('commander')
// node下的文件操作系统中的existsSync - 监测是否存在该路径
const exists = require('fs').existsSync
// node自带的拼接路径的模块
const path = require('path')
// 命令行中的加载效果
const ora = require('ora')
// 获取用户根目录
const home = require('user-home')
// 绝对路径替换为波浪号
const tildify = require('tildify')
// 高亮
const chalk = require('chalk')
// **important** 用户与脚本命令行的交互 | 面试
const inquirer = require('inquirer')
// rm -rf js版本
const rm = require('rimraf').sync

面试题:如何使用本地模板,预设模板 而不是 github?

使用 –offline

如何获取用户参数

vue init webpack zhaowa-app

program.args[0] => ‘webpack’
// 是否包含斜杠 => 路径层级 =>非默认预制模板
const hasSlash = template.indexOf(‘/‘)>-1

// 项目名称
rawName = program.args[1]

//输入是否为空 => 是否以当前文件目录作为项目根目录
const inPlace = !rawName || ‘.’

//调整当前目录作为构建目录的根路径
const name = inPlace ….

//本地目录模板仓库路径拼接 /zhaowa/.vue-templates/webpack
const tmp = path.join(home,’…’)

/lib/generate.js

1
2
3
4
5
6
// 静态网页文件生成器
const Metalsmith
// 模板引擎
const Handlebars
// 多条件匹配工具
const multimatch

/lib/ask.js

解析传进来的模板有哪些要询问的

inquirer.prompt

/lib/filter.js 过滤不需要的

vue-cli_3.x.x

/lib/create.js

1
2
const creator = new Creator(name, targetDir, getPromptModules())
await creator.create(options)

/lib/Creator.js

1
module.exports = class Creator extends EventEmitter {}

流程

用户创建指令 -> 创建参数解析 -> 加载模板(远端/本地) – prompts –> 处理文件路径 -> 文件层级处理 -> 文件模板渲染(plugins) -> 产出包

如何书写 node 脚本工具

vue2 存在的问题

  • 代码结构:以整体的包为形式存在
  • 性能优化的空间:ObjectDefineProperty 对象的方法,要对数组进行操作的话需要再自己封装一层,且所有值都是响应式的(性能损耗)
  • 选项式的配置模式:不好维护庞大的项目,可维护性
  • 浏览器真的需要老版本吗

vue3 的问题

  • 太多的 breaking changes 太多不兼容的内容
  • 生态影响
  • 发布节奏太快
    阅读全文 »

引言

面试:观察者模式 & 发布订阅
观察者模式:(观察者,被观察者) 中心一对多 + 系统单点的灵活和拓展
发布订阅:(发布者,订阅者,发布订阅中心) 调度中心 => 将注册列表遍历然后发布给订阅者

view -> listner/binding/处理内容 -> model

追问:要实现这些方式,如何双向绑定

数据监听器Observe     <----     mvvm
            |                    |
            |                    |
            V                    |
通知数据变化Dep                   |
            | ↑                  |
            | 添加订阅            |
            V |                  |
连接双方的桥梁watcher<---   代码生成(指令归纳)
            |          |         |
            |   绑定函数/订阅数据  |
         更新视图       |         |
            |           -------- |
            V                    V
           view   <—更新视图—  compiler

源码 -> 原理 -> 他人源码思路

阅读全文 »

vue 进阶

特征一:模块化 => vue-template-compiler (编译态把 template 转换成 render())

插槽 - 面试考察点 => 对比形式

默认插槽

组件外部维护参数与结构,内部安排位置摆放

  • 追问 => 默认插槽的实现方式》 => 插槽聚合(渲染在一个地方 顺序渲染)
  • 追问 => 多个插槽会以何种形态渲染(合并) => 如何放在不同的地方?

具名插槽

用 name 表示当前身份,从而在组件内部区分

1
2
3
4
5
// 父组件
<template v-slot:header>{{header}}</template>
<template #header>{{header}}</template>
// 子组件
<slot name="header"/>
  • 具名插槽可以在指定位置分开布局 => 原理:name 索引了一段单个解析的命名空间,node 独立由这个单个解析空间进行渲染
  • 追问 => 以 node 渲染为单位 => 混合式传参?

作用域插槽

1
2
3
4
5
6
7
8
9
// 父组件
<template slot="content" slot-scope="{slotProps}">{{slotProps}} - {{others}}</template>
// 子组件
<slot name="content" :slotProps={{slotProps}}/>
data(){
return{
slotProps:'slot props'
}
}

外部可以做结构勾勒和参数合并,内部也可以提供参数混合

  • 父子参数共同向 slot 传递

模板的二次加工

  1. watch | computed => 配置里声明和书写
  2. 其余方法:
    a. 函数 - 过滤器 | 独立管道符 => 管道符和函数有什么区别?| 管道符能拿到实例嘛? (不能!)
    b. v-html => 递归调用渲染 node => 安全性风险
    c. 利用组件形式
1
2
3
4
5
6
7
8
9
10
11
12
13
// 过滤器
// template
<p>{{money | moneyFilter}}</p>
// script
data(){

},
filters:{
moneyFilter(param){
console.log(this)
return param > 99 ? 99 : param
}
}

jsx 更自由的 all in js

  • 面试题:
    1. 语法糖的实现
    2. jsx 的优点和劣势
      1. vue 编译:(_beforeMount_)template => render() => (_Mounted_)vm.render()
      2. template 编译,带有 dom 渲染优化,性能节约
      3. 直接写 render 函数不受 vue 语法限制,不依赖于 vue 的 api

特征二:组件化

1
2
3
4
5
6
Vue.component('component', {
template: '<h1></h1>',
})
new Vue({
el: '#app',
})
    1. 抽象复用
    1. 精简 & 聚合

混入 mixin - 逻辑混入

    1. 应用:公共逻辑功能的继承
    1. 面试:合并策略 生命周期
    • 变量补充形式上 => 额外补充、不会覆盖
    • 生命周期 => minxin 在引用该 mixin 组件之前执行
    • 同样引用的两个 mixin => 根据引用顺序安排加载顺序

继承拓展 extends - 逻辑上的共同拓展

    1. 核心逻辑的继承
    1. 合并策略
    • 不会覆盖
    • 生命周期 => 不论是业务代码还是 mixin 都在 extents 生命周期之后
    • 只有一个

插件系统

1
2
3
4
5
6
7
8
9
10
import element from 'element'

//Vue.use(element)
createApp(app).use(element, {
isA: true,
})
// => install:(()=>{})

// vue.prototype.$abc => this.$abc
// app.globalProperties.$abc

Vue 3 - compositionAPI

vue 基础

理论

面试题:对 MVVM 的了解

  • Web 应用发展史
    1. 语义化模板
    2. MVC - model view controller
    3. MVVM - model view viewModel
      1. 数据本身会通过 model 挂在在 viewModel,vm 会劫持数据并同步至渲染层
      2. 视图层发生外部变化,会同样回调给 vw,返回给 model

写法

vue 如何利用 mvvm 开发?

数据双向绑定

  1. 利用花括号,构筑了数据与 vm 的双向绑定关系 =》 buildTemplate | compile
  2. 通过视图绑定监听事件来处理数据 =》v-model === :value @input => 节点处理流程

buildTemplate =》 render()

生命周期

面试题:vue 的生命周期

创建阶段: beforeCreate => created => beforeMount => mounted

更新阶段: beforeUpdate => updated

销毁阶段: beforeDestroy =》 destroyed

beforeCreate: new Vue() - 创建实例阶段
created: data | props | method | computed - 数据创建

beforeMount: vDom(虚拟节点) - 数据操作以及虚拟 dom 的变化 但不能涉及 dom
mounted: Dom 更新

beforeUpdate: vDom - 完成更新,dom 还未更新
updated: dom 完成更新 =》 谨慎做更新数据操作

beforeDestroy:实例尚未销毁 - 清空 eventBus setTimeOut
destroyed:完全销毁

补充:key =》 diff =》 dom diff =》 节点 id

监听

面试题:computed 和 watch

相同点:

  1. 基于 vue 的依赖收集机制进行采集
  2. 都是被依赖的变化所触发,从而进行处理回调

不同点:

  1. 入/出:computed 多入单出,watch 单入多出
  2. 性能:computed 存在缓存,不收调用次数的性能损耗;watch 只在监听的值变化时,不包含生成 immediate
  3. computed 关注结果,watch 关注过程

问:computed 缓存和响应式如何实现的?

完整过程:

  1. 流程:new Vue() => 初始化 computed(initState) => createComputedGetter(key) => mount
  2. 劫持:getter 属性变化区分是否是最新状态 dirty
  3. target depend <==> 原值和依赖之间的关系链

指令 & 条件

条件

v-if | v-show
v-else | v-else-if

v-for

v-for & v-if 在同一节点使用时

vue2.x v-for 会优先作用
vue3.x v-if 总是优先于 v-for

v-model v-once v-text v-html v-bind

自定义指令

事件 - v-on

修饰符

.stop .prevent .once .capture .self .passive

事件的设计 - 为何 vue 把事件设计在模板上而不是 js 中

  1. 模板定位视图绑定的触发源 + 触发源寻找触发事件的逻辑 —— 方便定位
  2. js 与视图绑定解耦 —— 更便于测试隔离
  3. vm 销毁,自动解绑事件 —— 便于回收

组件化

一般组件 + 动态组件 => 插件