functioninitData (vm) { var data = vm.$options.data; data = vm._data = typeof data === 'function' ? getData(data, vm) : data || {}; if (!isPlainObject(data)) { data = {}; warn( 'data functions should return an object:\n' + 'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function', vm ); } // proxy data on instance var keys = Object.keys(data); var props = vm.$options.props; var methods = vm.$options.methods; var i = keys.length; while (i--) { var key = keys[i]; { if (methods && hasOwn(methods, key)) { warn( ("Method \"" + key + "\" has already been defined as a data property."), vm ); } } if (props && hasOwn(props, key)) { warn( "The data property \"" + key + "\" is already declared as a prop. " + "Use prop default value instead.", vm ); } elseif (!isReserved(key)) { proxy(vm, "_data", key); } } // observe data observe(data, true/* asRootData */); }
上述源码 主要是判断一下 data 的 类型以及判断 data 定义的变量名是否在 props 及 methods 中是否也存在,之后调用 observe 方法给 data 对象添加数据监听
functionnormalizeProps (options, vm) { var props = options.props; if (!props) { return } var res = {}; var i, val, name; if (Array.isArray(props)) { // 判断 props 类型 第一种是传递数组 ['props1', 'props2'] i = props.length; while (i--) { val = props[i]; if (typeof val === 'string') { name = camelize(val); res[name] = { type: null }; } else { warn('props must be strings when using array syntax.'); } } } elseif (isPlainObject(props)) { // 判断 props 类型 第二种是传递带有类型检查的对象 for (var key in props) { val = props[key]; name = camelize(key); res[name] = isPlainObject(val) ? val : { type: val }; } } else { warn( "Invalid value for option \"props\": expected an Array or an Object, " + "but got " + (toRawType(props)) + ".", vm ); } options.props = res; }
functioninitProps (vm, propsOptions) { var propsData = vm.$options.propsData || {}; var props = vm._props = {}; // cache prop keys so that future props updates can iterate using Array // instead of dynamic object key enumeration. var keys = vm.$options._propKeys = []; var isRoot = !vm.$parent; // root instance props should be converted if (!isRoot) { toggleObserving(false); } var loop = function ( key ) { keys.push(key); var value = validateProp(key, propsOptions, propsData, vm); /* istanbul ignore else */ { var hyphenatedKey = hyphenate(key); if (isReservedAttribute(hyphenatedKey) || config.isReservedAttr(hyphenatedKey)) { warn( ("\"" + hyphenatedKey + "\" is a reserved attribute and cannot be used as component prop."), vm ); } defineReactive$$1(props, key, value, function () { if (!isRoot && !isUpdatingChildComponent) { warn( "Avoid mutating a prop directly since the value will be " + "overwritten whenever the parent component re-renders. " + "Instead, use a data or computed property based on the prop's " + "value. Prop being mutated: \"" + key + "\"", vm ); } }); } // static props are already proxied on the component's prototype // during Vue.extend(). We only need to proxy props defined at // instantiation here. if (!(key in vm)) { proxy(vm, "_props", key); } };
for (var key in propsOptions) loop( key ); toggleObserving(true); }
functioninitMethods (vm, methods) { var props = vm.$options.props; for (var key in methods) { { if (typeof methods[key] !== 'function') { warn( "Method \"" + key + "\" has type \"" + (typeof methods[key]) + "\" in the component definition. " + "Did you reference the function correctly?", vm ); } if (props && hasOwn(props, key)) { warn( ("Method \"" + key + "\" has already been defined as a prop."), vm ); } if ((key in vm) && isReserved(key)) { warn( "Method \"" + key + "\" conflicts with an existing Vue instance method. " + "Avoid defining component methods that start with _ or $." ); } } vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm); // 调用 函数的bind 方法,绑定 methods 方法的 this 到 Vue 实例上 } }