携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情
主要是补充上一节初始化的方法细节
1. initProps
function initProps(vm: Component, propsOptions: Object) {
const propsData = vm.$options.propsData || {};
const props = (vm._props = {});
const keys = (vm.$options._propKeys = []);
const isRoot = !vm.$parent;
// root instance props should be converted
if (!isRoot) {
toggleObserving(false);
}
for (const key in propsOptions) {
keys.push(key);
const value = validateProp(key, propsOptions, propsData, vm);
/* istanbul ignore else */
if (process.env.NODE_ENV !== "production") {
const hyphenatedKey = hyphenate(key);
if (
isReservedAttribute(hyphenatedKey) ||
config.isReservedAttr(hyphenatedKey)
) {
}
defineReactive(props, key, value, () => {});
} else {
defineReactive(props, key, value);
}
if (!(key in vm)) {
proxy(vm, `_props`, key);
}
}
toggleObserving(true);
}
defineReactive方法处理数据响应
function defineReactive (
obj: Object,
key: string,
val: any,
customSetter?: ?Function,
shallow?: boolean
) {
const dep = new Dep()//收集依赖的类
// 用户可能直接调用了defineReactive 方法定义属性 Object.freeze()
const property = Object.getOwnPropertyDescriptor(obj, key)
if (property && property.configurable === false) {
return
}
// cater for pre-defined getter/setters
const getter = property && property.get
const setter = property && property.set
if ((!getter || setter) && arguments.length === 2) {
val = obj[key]
}
let childOb = !shallow && observe(val) // 递归观测
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter () {
const value = getter ? getter.call(obj) : val
if (Dep.target) {
dep.depend()
if (childOb) {
childOb.dep.depend() // 对象和数组本身是具备依赖收集的功能
if (Array.isArray(value)) {
dependArray(value)
}
}
}
return value
},
set: function reactiveSetter (newVal) {
const 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 (process.env.NODE_ENV !== 'production' && 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()
}
})
}
proxy方法做代理,vm可以直接读取到data里面的数据
//proxy(vm, `_props`, key);
function proxy(target: Object, sourceKey: string, key: string) {
sharedPropertyDefinition.get = function proxyGetter() {
return this[sourceKey][key];
};
sharedPropertyDefinition.set = function proxySetter(val) {
this[sourceKey][key] = val;
};
Object.defineProperty(target, key, sharedPropertyDefinition);
}
2. initMethods
function initMethods(vm: Component, methods: Object) {
const props = vm.$options.props;
for (const key in methods) {
vm[key] =
typeof methods[key] !== "function" ? noop : bind(methods[key], vm);
}
}
//bind方法是在shared/util.js里处理的方法
//如下:
function polyfillBind (fn: Function, ctx: Object): Function {
function boundFn (a) {
const l = arguments.length
return l
? l > 1
? fn.apply(ctx, arguments)
: fn.call(ctx, a)
: fn.call(ctx)
}
boundFn._length = fn.length
return boundFn
}
function nativeBind (fn: Function, ctx: Object): Function {
return fn.bind(ctx)
}
export const bind = Function.prototype.bind
? nativeBind
: polyfillBind
3. initData
function initData(vm: Component) {
let data = vm.$options.data;
data = vm._data = typeof data === "function" ? getData(data, vm) : data || {};
// proxy data on instance
const keys = Object.keys(data);
const props = vm.$options.props;
const methods = vm.$options.methods;
let i = keys.length;
while (i--) {
const key = keys[i];
if (props && hasOwn(props, key)) {
} else if (!isReserved(key)) {
proxy(vm, `_data`, key);
}
}
// observe data
observe(data, true /* asRootData */);
}
4. initComputed
function initComputed(vm: Component, computed: Object) {
// $flow-disable-line
const watchers = (vm._computedWatchers = Object.create(null));
// computed properties are just getters during SSR
const isSSR = isServerRendering();
for (const key in computed) {
const userDef = computed[key];
const getter = typeof userDef === "function" ? userDef : userDef.get;
if (!isSSR) {
// create internal watcher for the computed property.
watchers[key] = new Watcher(//computed和wotch都是实例化Watcher
vm,
getter || noop,
noop,
computedWatcherOptions
);
}
if (!(key in vm)) {
defineComputed(vm, key, userDef);
}
}
}
function createComputedGetter(key) {
return function computedGetter() {
const watcher = this._computedWatchers && this._computedWatchers[key];
if (watcher) {
if (watcher.dirty) {//dirty标识来处理是否调用callback
watcher.evaluate();
}
if (Dep.target) {
watcher.depend();
}
return watcher.value;
}
};
}
5. observe
export function observe (value: any, asRootData: ?boolean): Observer | void {
if (!isObject(value) || value instanceof VNode) { // 观测的人必须是一个对象
return
}
let ob: Observer | void
if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { // 并且不能是一个被观测过的属性
ob = value.__ob__
} else if (
shouldObserve && // 是否能被观测
!isServerRendering() &&
(Array.isArray(value) || isPlainObject(value)) &&
Object.isExtensible(value) && // 这个对象必须能被扩展
!value._isVue
) {
ob = new Observer(value) // 观测数据
}
if (asRootData && ob) {
ob.vmCount++
}
return ob
}
6. initWatch
function initWatch(vm: Component, watch: Object) {
for (const key in watch) {
// 循环所有的watch
const handler = watch[key]; // 如果是数组 循环创建watcher'
if (Array.isArray(handler)) {
for (let i = 0; i < handler.length; i++) {
createWatcher(vm, key, handler[i]);
}
} else {
createWatcher(vm, key, handler); // 如果是一个直接创建watcher
}
}
}
function createWatcher(
vm: Component,
expOrFn: string | Function,
handler: any,
options?: Object
) {
if (isPlainObject(handler)) {
// 有可能是对象类型 watch:{aaa:{handler(){},immediate:true)
options = handler;
handler = handler.handler;
}
if (typeof handler === "string") {
// watch可以是一个字符串
handler = vm[handler];
}
return vm.$watch(expOrFn, handler, options); // 最终调用的都是$watch
}
Vue.prototype.$watch = function (
expOrFn: string | Function,
cb: any,
options?: Object
): Function {
const vm: Component = this;
if (isPlainObject(cb)) {
return createWatcher(vm, expOrFn, cb, options);
}
options = options || {};
options.user = true; // 标识是用户watcher
// expOrFn 函数 或者是一个 表达式
const watcher = new Watcher(vm, expOrFn, cb, options); // 创建一个watcher
if (options.immediate) {
const info = `callback for immediate watcher "${watcher.expression}"`;
pushTarget();
invokeWithErrorHandling(cb, vm, [watcher.value], vm, info);
popTarget();
}
return function unwatchFn() {
// 返回一个取消观测方法
watcher.teardown();
};
};
}
小结
这次主要过了下初始化的一些方法,下一小结补充下一些细节方法。如重写数组的7个方法,Watcher类。