‘sort’,
‘reverse’
]
methodsToPatch.forEach(function (method) {
// cache original method
const original = arrayProto[method]
def(arrayMethods, method, function mutator (…args) {
const result = original.apply(this, args)
const ob = this.ob
let inserted
switch (method) {
case ‘push’:
case ‘unshift’:
inserted = args
break
case ‘splice’:
inserted = args.slice(2)
break
}
if (inserted) ob.observeArray(inserted) // 新增的数据需要进行观测
// notify change
ob.dep.notify()
return result
})
})
-
每个属性都拥有自己的
dep
属性,存放他所依赖的watcher,当属性变化后会通知自己对应的watcher去更新 -
默认在初始化时会调用render函数,此时会触发属性依赖收集
dep.depend
-
当属性发生修改时会触发
watcher
更新dep.notify()
问题核心:如何将template转换成render函数 ?
-
1.将template模板转换成
ast
语法树 -parserHTML
-
2.对静态语法做静态标记 -
markUp
diff
来做优化的 静态节点跳过diff
操作
3.重新生成代码 - codeGen
src/compiler/index.js:11
export const createCompiler = createCompilerCreator(function baseCompile (
template: string,
options: CompilerOptions
): CompiledResult {
const ast = parse(template.trim(), options) // 1.解析ast语法树
if (options.optimize !== false) {
optimize(ast, options) // 2.对ast树进行标记,标记静态节点
}
const code = generate(ast, options) // 3.生成代码
return {
ast,
render: code.render,
staticRenderFns: code.staticRenderFns
}
})
-
Vue的生命周期钩子就是回调函数而已,当创建组件实例的过程中会调用对应的钩子方法。
-
内部会对钩子函数进行处理,将钩子函数维护成数组的形式
src/core/instance/init.js:38
初始化合并
src/core/util/options.js:388
合并选项
function mergeHook (
parentVal: ?Array,
childVal: ?Function | ?Array
): ?Array {
const res = childVal // 儿子有
? parentVal
-
? parentVal.concat(childVal) // 父亲也有,那就是合并
-
Array.isArray(childVal) // 儿子是数组
? childVal
-
[childVal] // 不是数组包装成数组
-
parentVal
return res
-
? dedupeHooks(res)
- res
}
-
beforeCreate
在实例初始化之后,数据观测(data observer) 和 event/watcher 事件配置之前被调用。 -
created 实例已经创建完成之后被调用。在这一步,实例已完成以下的配置:数据观测(data observer),属性和方法的运算, watch/event 事件回调。这里没有$el
-
beforeMount
在挂载开始之前被调用:相关的 render 函数首次被调用。 -
mounted
el 被新创建的vm.$el
替换,并挂载到实例上去之后调用该钩子。 -
beforeUpdate
数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。 -
updated
由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。 -
beforeDestroy
实例销毁之前调用。在这一步,实例仍然完全可用。 -
destroyed
Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。 该钩子在服务器端渲染期间不被调用。 -
keep-alive
(activated 和 deactivated)
在哪发送请求都可以,主要看具体你要做什么事
-
Vue.mixin
的作用就是抽离公共的业务逻辑,原理类似“对象的继承”,当组件初始化时会调用mergeOptions
方法进行合并,采用策略模式针对不同的属性进行合并。如果混入的数据和本身组件中的数据冲突,会采用“就近原则”以组件的数据为准。 -
mixin中有很多缺陷 “命名冲突问题”、“依赖问题”、“数据来源问题”
src/core/global-api/mixin.js
- 每次使用组件时都会对组件进行实例化操作,并且调用data函数返回一个对象作为组件的数据源。这样可以保证多个组件间数据互不影响
function Vue() {}
function Sub() { // 会将data存起来
this.data = this.constructor.options.data;
}
Vue.extend = function(options) {
Sub.options = options;
return Sub;
}
let Child = Vue.extend({
data: { name: ‘zf’ }
});
// 两个组件就是两个实例, 希望数据互不干扰
let child1 = new Child();
let child2 = new Child();
console.log(child1.data.name);
child1.data.name = ‘jw’;
console.log(child2.data.name);
src/core/util/options.js:121
data的合并策略
strats.data = function (
parentVal: any,
childVal: any,
vm?: Component
): ?Function {
if (!vm) { // 组件在合并时并没有产生实例,所以会校验类型
if (childVal && typeof childVal !== ‘function’) {
process.env.NODE_ENV !== ‘production’ && warn(
'The “data” option should be a function ’ +
'that returns a per-instance value in component ’ +
‘definitions.’,
vm
)
return parentVal
}
return mergeDataOrFn(parentVal, childVal)
}
return mergeDataOrFn(parentVal, childVal, vm)
}
function mergedInstanceDataFn () {
// instance merge
const instanceData = typeof childVal === ‘function’
-
? childVal.call(vm, vm)
- childVal
const defaultData = typeof parentVal === ‘function’
-
? parentVal.call(vm, vm)
- parentVal
if (instanceData) {
return mergeData(instanceData, defaultData) // 合并两个对象
} else {
return defaultData
}
}
-
nextTick
中的回调是在下次 DOM 更新循环结束之后执行的延迟回调。 -
可用于获取更新后的 DOM。
-
Vue中数据更新是异步的,使用
nextTick
方法可以保证用户定义的逻辑在更新之后执行。
src/core/util/nextTick.js:89
小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注:前端)
总结:
-
函数式编程其实是一种编程思想,它追求更细的粒度,将应用拆分成一组组极小的单元函数,组合调用操作数据流;
-
它提倡着 纯函数 / 函数复合 / 数据不可变, 谨慎对待函数内的 状态共享 / 依赖外部 / 副作用;
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
Tips:
其实我们很难也不需要在面试过程中去完美地阐述出整套思想,这里也只是浅尝辄止,一些个人理解而已。博主也是初级小菜鸟,停留在表面而已,只求对大家能有所帮助,轻喷🤣;
我个人觉得: 这些编程范式之间,其实并不矛盾,各有各的 优劣势。
理解和学习它们的理念与优势,合理地 设计融合,将优秀的软件编程思想用于提升我们应用;
所有设计思想,最终的目标一定是使我们的应用更加 解耦颗粒化、易拓展、易测试、高复用,开发更为高效和安全;
的粒度,将应用拆分成一组组极小的单元函数,组合调用操作数据流;
- 它提倡着 纯函数 / 函数复合 / 数据不可变, 谨慎对待函数内的 状态共享 / 依赖外部 / 副作用;
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
Tips:
其实我们很难也不需要在面试过程中去完美地阐述出整套思想,这里也只是浅尝辄止,一些个人理解而已。博主也是初级小菜鸟,停留在表面而已,只求对大家能有所帮助,轻喷🤣;
我个人觉得: 这些编程范式之间,其实并不矛盾,各有各的 优劣势。
理解和学习它们的理念与优势,合理地 设计融合,将优秀的软件编程思想用于提升我们应用;
所有设计思想,最终的目标一定是使我们的应用更加 解耦颗粒化、易拓展、易测试、高复用,开发更为高效和安全;