为了账号安全,请及时绑定邮箱和手机立即绑定

3道常见的vue面试题,你都会了吗?

标签:
Html5 CSS3 Vue.js

最近流传各大厂纷纷裁员,导致很多人“被迫”毕业,显然很多人还是想留级,无奈出现在名单中,只能感叹命运不公,不过拿了N+1,也算是很欣慰。

computed 实现原理

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,如果 dirtytrue,则计算值,并收集依赖

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 方法,并设置 dirtyfalse

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);
  }
};

这里看出 watcherdeps 存储的就是 Dep.target 的数组,没错,就是依赖属性的收集,整个过程就到此完成。

vue-loader 的作用

vue-loader 是 Webpack 的 loader 模块,它使我们可以用 .vue 文件格式编写单文件组件。

单文件组件文件有三个部分,即模板(template)、脚本(script)和样式(style)。

vue-loader 模块允许 webpack 使用单独的加载器模块(例如 SASS 或 SCSS 加载器)提取和处理每个部分。该设置使我们可以使用 .vue 文件无缝编写程序。

vue-loader 模块还允许把静态资源视为模块依赖性,并允许使用 webpack 加载器进行处理。而且还允许在开发过程中进行热重装。

Vue 插件的功能

插件通常用来为 Vue 添加全局功能。有如下用途

  1. 添加全局方法或者 property。如:vue-custom-element
  2. 添加全局资源:指令/过滤器/过渡等。如 vue-touch
  3. 通过全局混入来添加一些组件选项。如 vue-router
  4. 添加 Vue 实例方法,通过把它们添加到 Vue.prototype 上实现。
  5. 一个库,提供自己的 API,同时提供上面提到的一个或多个功能。如 vue-router

如何自定义 Vue 插件

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) {
    // 逻辑...
  }
}

写在最后

如果文中内容对你有帮助, 记得三连~ 🎉🎉🎉 如文中有错误,也欢迎大家指正修改!

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消