最近流传各大厂纷纷裁员,导致很多人“被迫”毕业,显然很多人还是想留级,无奈出现在名单中,只能感叹命运不公,不过拿了N+1,也算是很欣慰。
又得去面试了,接下来一起来巩固下vue的3道面试题吧!
computed 计算属性,有两种定义方式,一种是方法,另一种是 get,set 属性。并且 computed 监听的对象必须是已经在 data 定义的属性
Vue 在创建 computed 属性时候,会循环所有计算属性,每一个计算属性会创建一个 watch,并且在通过 defineProperty 监听,在 get 中,计算属性工作是做依赖收集,在 set 中,计算属性重要工作是重新执行计算方法
computed 是懒执行,也就是说第一次初始化之后,不会执行计算,下一次变更执行重新计算是在 set 中
computed 收集时机和 data 一样,是在组件挂载前,但是其收集对象是自己属性对应的 watch,而 data 本身所有数据对应一个 watch
具体可以查看 computed 的实现源码,这里移除服务端渲染相关逻辑
function initComputed(vm: Component, computed: Object) { const watchers = (vm._computedWatchers = Object.create(null)); for (const key in computed) { const userDef = computed[key]; const getter = typeof userDef === "function" ? userDef : userDef.get; if (process.env.NODE_ENV !== "production" && getter == null) { warn(`Getter is missing for computed property "${key}".`, vm); } // 计算属性独享watcher watchers[key] = new Watcher(vm, getter || noop, noop, computedWatcherOptions); // 在实例化Watcher后,开始对计算属性进行响应式处理 if (!(key in vm)) { defineComputed(vm, key, userDef); } else if (process.env.NODE_ENV !== "production") { if (key in vm.$data) { warn(`The computed property "${key}" is already defined in data.`, vm); } else if (vm.$options.props && key in vm.$options.props) { warn(`The computed property "${key}" is already defined as a prop.`, vm); } } }}接下来看 defineComputed 源码
if (typeof userDef === "function") { sharedPropertyDefinition.get = createComputedGetter(key); sharedPropertyDefinition.set = noop;} else { sharedPropertyDefinition.get = userDef.get ? createComputedGetter(key) : noop; sharedPropertyDefinition.set = userDef.set || noop;}Object.defineProperty(target, key, sharedPropertyDefinition);接下来看 createComputedGetter 函数,获取计算属性对应的 watcher,如果 dirty 是 true,则计算值,并收集依赖
function createComputedGetter(key) { return function () { // 获取到相应 key 的 computed-watcher var watcher = this._computedWatchers[key]; // 如果 computed 依赖的数据变化,dirty 会变成true,从而重新计算,然后更新缓存值 watcher.value if (watcher.dirty) { watcher.evaluate(); } if (Dep.target) { watcher.depend(); } return watcher.value; };}接下来,在 Watcher 类中找到 evaluate,执行 get 方法,并设置 dirty 为 false
evaluate () { this.value = this.get() this.dirty = false}get() 方法的定义如下,在这里执行计算过程,并返回。
Watcher.prototype.get = function () { // 改变 Dep.target pushTarget(); // getter 就是 watcher 回调 var value = this.getter.call(this.vm, this.vm); // 恢复前一个 watcher popTarget(); return value;};Dep.target = null;var targetStack = [];function pushTarget(_target) { if (Dep.target) { targetStack.push(Dep.target); } Dep.target = _target;}function popTarget() { Dep.target = targetStack.pop();}看完了 watcher.evaluate() 接下来看 depend() 方法定义
Watcher.prototype.depend = function () { var i = this.deps.length; while (i--) { dep.addSub(Dep.target); }};这里看出 watcher 的 deps 存储的就是 Dep.target 的数组,没错,就是依赖属性的收集,整个过程就到此完成。
vue-loader 是 Webpack 的 loader 模块,它使我们可以用 .vue 文件格式编写单文件组件。
单文件组件文件有三个部分,即模板(template)、脚本(script)和样式(style)。
vue-loader 模块允许 webpack 使用单独的加载器模块(例如 SASS 或 SCSS 加载器)提取和处理每个部分。该设置使我们可以使用 .vue 文件无缝编写程序。
vue-loader 模块还允许把静态资源视为模块依赖性,并允许使用 webpack 加载器进行处理。而且还允许在开发过程中进行热重装。
插件通常用来为 Vue 添加全局功能。有如下用途
Vue.prototype 上实现。Vue.js 的插件应该暴露一个 install 方法。这个方法的第一个参数是 Vue 构造器,第二个参数是一个可选的选项对象:
MyPlugin.install = function (Vue, options) { // 1. 添加全局方法或 property Vue.myGlobalMethod = function () { // 逻辑... } // 2. 添加全局资源 Vue.directive('my-directive', { bind (el, binding, vnode, oldVnode) { // 逻辑... } ... }) // 3. 注入组件选项 Vue.mixin({ created: function () { // 逻辑... } ... }) // 4. 添加实例方法 Vue.prototype.$myMethod = function (methodOptions) { // 逻辑... }}如果文中内容对你有帮助, 记得三连~ ?????? 如文中有错误,也欢迎大家指正修改!
更多前端面经,尽在 www.1024nav.com
禁止转发