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() 方法检查字符串是否匹配bailREsegments将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()