vue源码解析实例(一)

 vue.js文件

config属性解析

var config = ({
    optionMergeStrategies: Object.create(null),
    //是否发出警告
    silent: false,
     //启动时显示生产模式提示消息
    productionTip: "development" !== 'production',
    //是否启用devtools
    devtools: "development" !== 'production',
    //是否记录性能
    performance: false,
    //用于监视程序错误的错误处理程序
    errorHandler: null,
    //用于监视程序警告的警告处理程序
    warnHandler: null,
    //忽略某些自定义元素
    ignoredElements: [],
    //v-on为自定义用户关键字
    keyCodes: Object.create(null),
    //检查是否保留了标记,以便不能将其注册为组件。  
    isReservedTag: no,
    //检查是否保留了属性,以便它不能用作组件属性。
    isReservedAttr: no,
    //检查标记是否为未知元素。
    isUnknownElement: no,
    //获取元素的名称空间
    getTagNamespace: noop,
    //解析特定平台的实际标记名称
    parsePlatformTagName: identity,
    //检查属性是否必须使用属性(例如value)绑定
    mustUseProp: no,
    //异步执行更新。用于Vue测试Utils,如果设置为false,这将显著降低性能
    async: true,
    //由于遗留原因而暴露
    _lifecycleHooks: LIFECYCLE_HOOKS
  });

 //生命周期

LIFECYCLE_HOOKS
var SSR_ATTR = 'data-server-rendered';
//这边有个vue SSR的定义。服务端渲染

  var ASSET_TYPES = [
    'component',
    'directive',
    'filter'
  ];
//组件可以拥有的资产类型列表,这边有几个过滤器,自定义,组件的定义,后面看到后打锚点

  var LIFECYCLE_HOOKS = [
    'beforeCreate',
    'created',
    'beforeMount',
    'mounted',
    'beforeUpdate',
    'updated',
    'beforeDestroy',
    'destroyed',
    'activated',
    'deactivated',
    'errorCaptured',
    'serverPrefetch'
  ];
//生命周期的钩子
解析简单的路径。
首先定义了一个正则。其中source属性返回一个字符串,该字符串包含regexp对象的源文本,并且它不包含两边的两个正斜杠和任何标志。
test() 方法检查字符串是否匹配bailRE
segments将path用split分割成字符串数组,一个循环(obj)是什么?
  var unicodeRegExp = /a-zA-Zu00B7u00C0-u00D6u00D8-u00F6u00F8-u037Du037F-u1FFFu200C-u200Du203F-u2040u2070-u218Fu2C00-u2FEFu3001-uD7FFuF900-uFDCFuFDF0-uFFFD/;

  

  var bailRE = new RegExp(("[^" + (unicodeRegExp.source) + ".$_\d]"));
  function parsePath (path) {
    if (bailRE.test(path)) {
      return
    }
    var segments = path.split('.');
    return function (obj) {
      for (var i = 0; i < segments.length; i++) {
        if (!obj) { return }
        obj = obj[segments[i]];
      }
      return obj
    }
  }
 

 

公开util

// exposed util methods.
    // NOTE: these are not considered part of the public API - avoid relying on
    // them unless you are aware of the risk.
    Vue.util = {
      warn: warn,
      extend: extend,
      mergeOptions: mergeOptions,
      defineReactive: defineReactive$$1
    };

1.warn

 var warn = noop;
    warn = function (msg, vm) {
      var trace = vm ? generateComponentTrace(vm) : '';

      if (config.warnHandler) {
        config.warnHandler.call(null, msg, vm, trace);
      } else if (hasConsole && (!config.silent)) {
        console.error(("[Vue warn]: " + msg + trace));
      }
    };
warn是一个function,初始化的时候,只定义了一个noop方法,如果在开发环境,这个warn是可以接收两个参数,一个是msg,一个是vm,msg不用说,大家都知道这里是一个提示信息,vm就是实例化的vue对象,或者是实例化的vue对象的某一个属性。
接下来是一个三元表达式trace,用来判断调用warn方法时,是否有传入了vm,如果没有,返回的是空,如果有,那么就返回generateComponentTrace这个function,这个方法初始化的值也是noop,什么都没有做,目的是解决流量检查问题
如果config.warnHandler被使用者变更成了值,不在是null,那么就把config.warnHandler的this指向null,其实就是指向的window,再把msg, vm, trace传给config.warnHandler
否则判断当前环境使用支持cono1.sle并且开启了警告,如果开启了,那就把警告提示信息打印出来
2.extend
/**
   * Mix properties into target object.
   */
  function extend (to, _from) {
    for (var key in _from) {
      to[key] = _from[key];
    }
    return to
  }

这个方法是用于做继承操作的,接收两个值to, _from,将属性_from混合到目标对象to中,如果to存在_from中的属性,则直接覆盖,最后返回新的to

3.mergeOptions

将两个选项对象合并为一个新对象,用于实例化和继承的核心实用程序(这是一个很重要的方法,在后面多处会用到,所以建议大家仔细看这里)

/**
   * Merge two option objects into a new one.
   * Core utility used in both instantiation and inheritance.
   */
  function mergeOptions (parent,child,vm) {
    {
      checkComponents(child);
//检查组件是否是有效的名字---不能是h5元素标签
    }

    if (typeof child === 'function') {
      child = child.options;
    }
//如果child是一个function的话,则把child自己指向child的options属性

    normalizeProps(child, vm);
//camelize:
//把名称格式为“xx-xx”的变为“xxXx”,这里接收的是当前的props属性值,一个字符串

    normalizeInject(child, vm);
    normalizeDirectives(child);

//normalizeProps:规范属性,确保所有的props的规范都是基于对象的

    // Apply extends and mixins on the child options,
    // but only if it is a raw options object that isn't
    // the result of another mergeOptions call.
    // Only merged options has the _base property.
    if (!child._base) {
      if (child.extends) {
        parent = mergeOptions(parent, child.extends, vm);
      }
      if (child.mixins) {
        for (var i = 0, l = child.mixins.length; i < l; i++) {
          parent = mergeOptions(parent, child.mixins[i], vm);
        }
      }
    }

    var options = {};
    var key;
    for (key in parent) {
      mergeField(key);
    }
    for (key in child) {
      if (!hasOwn(parent, key)) {
        mergeField(key);
      }
    }
    function mergeField (key) {
      var strat = strats[key] || defaultStrat;
      options[key] = strat(parent[key], child[key], vm, key);
    }
    return options
  }

4.defineReactive(拦截属性)

function defineReactive$$1 (
    obj,
    key,
    val,
    customSetter,
    shallow
  ) {
    var dep = new Dep();

    var property = Object.getOwnPropertyDescriptor(obj, key);
// getOwnPropertyDescriptor 返回描述对象
    if (property && property.configurable === false) {
      return
    }
//property.configurable === false,不可扩展

    // cater for pre-defined getter/setters
    var getter = property && property.get;
    var setter = property && property.set;
    if ((!getter || setter) && arguments.length === 2) {
      val = obj[key];
    }

    var childOb = !shallow && observe(val);
    Object.defineProperty(obj, key, {
      enumerable: true,
      configurable: true,
      get: function reactiveGetter () {
        var value = getter ? getter.call(obj) : val;
//有没有自定义的get函数
        if (Dep.target) {
          dep.depend();
          if (childOb) {
            childOb.dep.depend();
            if (Array.isArray(value)) {
              dependArray(value);
            }
          }
        }
        return value
      },
      set: function reactiveSetter (newVal) {
        var value = getter ? getter.call(obj) : val;
        /* eslint-disable no-self-compare */
        if (newVal === value || (newVal !== newVal && value !== value)) {
          return
        }
        /* eslint-enable no-self-compare */
        if (customSetter) {
          customSetter();
        }
        // #7981: for accessor properties without setter
        if (getter && !setter) { return }
        if (setter) {
          setter.call(obj, newVal);
        } else {
          val = newVal;
        }
        childOb = !shallow && observe(newVal);
        dep.notify();
      }
    });
  }

 Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。

这里,其实就是用来实现响应式数据的核心之一,主要做的事情就是数据的更新, Object.defineProperty() 
多多关照,多多指教,共同成长 ---嘉煠
原文地址:https://www.cnblogs.com/jiayeyuan/p/14447567.html