读Vue源码的收获(持续更新中)

135 阅读1分钟

一、如何禁止对象属性的改变

通过set对对象的属性更改进行劫持,当对对象的属性进行改变的时候,提示警告。

  const dataDef = {}
  dataDef.get = function () { return this._data }
  const propsDef = {}
  propsDef.get = function () { return this._props }
  if (process.env.NODE_ENV !== 'production') {
    // 禁止对Vue.prototype.$data属性的更改
    dataDef.set = function () {
      warn(
        'Avoid replacing instance root $data. ' +
        'Use nested data properties instead.',
        this
      )
    }
    // 禁止对Vue.prototype.$props属性的更改
    propsDef.set = function () {
      warn(`$props is readonly.`, this)
    }
  }
  Object.defineProperty(Vue.prototype, '$data', dataDef)
  Object.defineProperty(Vue.prototype, '$props', propsDef)

二、Vue是如何实现原型(实例)属性和静态属性的

Vue的构造函数非常简单,其实就一行代码,如下

function Vue (options) {
  this._init(options)
}
  • Vue的实例属性

image.png

  • Vue的静态属性

image.png

  • Vue的实例属性和Vue的静态属性的最大区别是静态属性中是没办法获取Vue的实例vm(其实就是this) 比如:
function VTest() {
    this.a = 1
}
VTest.prototype.$Set = function() { 
    console.log('prototype',this.a);
    //可以打印出1
} //原型属性
VTest.Set = function() { 
    console.log('VTest', this.a);
    //打印不出1
} //静态属性

let VTestObj = new VTest()

VTestObj.$Set(); //会被实例化,类似于Vue实例的实例属性
VTest.Set(); //不会被实例化,其实就是Vue提供的全局API

三、Vue.use的作用

主要功能是封装自定义的原型属性比如Vue.prototype.$Toas或者全局注册组件Vue.component的功能,方便使用者,比如我们用element-ui的时候Vue.use(ElementUI);

  • 源码其实很简单
//源码
export function initUse (Vue: GlobalAPI) {
  Vue.use = function (plugin: Function | Object) { //Vue.use实现,支持函数或者对象
    const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))//防止重复注册
    if (installedPlugins.indexOf(plugin) > -1) { //如果已经注册,返回
      return this
    }

    // additional parameters
    const args = toArray(arguments, 1)
    args.unshift(this) //this其实就是Vue
    if (typeof plugin.install === 'function') { //函数的情景
      plugin.install.apply(plugin, args)
    } else if (typeof plugin === 'function') {
      plugin.apply(null, args)
    }
    installedPlugins.push(plugin)
    return this
  }
}
  • 如何用
含有install方法的对象
const LlsAlert = {}
LlsAlert.install = (Vue, options) => {
  Vue.prototype.$LlsAlert = (msg) => {
    alert(msg)
  }
}
Vue.use(Toast);

//单独注册Alert组件
import Alert from './src/main';
Alert.install = function(Vue) {
 Vue.component(Alert.name, Alert);
};
export default Alert;

四、如何创建一个原型不是Object的对象

Vue中对象的初始化很多使用了Object.create(null)语句,这种方式创建的对象,其原型为null,对象更纯净些