上一篇: 簡(jiǎn)單的準(zhǔn)備工作
為了更加有代入感,我們直接就在 src/index.js 下按照平時(shí)項(xiàng)目工程的寫(xiě)法開(kāi)始井氢;
在 source/vue/index.js
import { initState } from './observer';
// 構(gòu)造函數(shù)
function Vue(options) {
this._init(options);
};
Vue.prototype._init = function(options) {
let vm = this;
// $options 表示 new Vue的時(shí)候傳入的參數(shù)
vm.$options = options;
initState(vm);
}
export default Vue;
接下來(lái)新建一個(gè) observer 文件夾产镐, 再寫(xiě)一個(gè) initState 的函數(shù)來(lái)完成初始化;
mkdir observer
cd observer
new-item index.js
// observer/index.js
import Observer from './observer';
export function initState(vm) {
let opts = vm.$options;
if (opts.data) {
// 初始化 data 屬性
initData(vm)
}
};
export function observer(data) {
if (typeof data !== 'object' || data == null) {
return;
}
return new Observer(data);
}
function initData(vm) {
let data = vm.$options.data;
// 有可能 是函數(shù)残吩,有可能是對(duì)象
data = vm._data = typeof data === 'function' ? data.call(vm) : data || {};
observer(vm._data);
};
走到這一步,很接近核心了倘核,接下來(lái)就是 基于 Object.defineProperty
實(shí)現(xiàn)響應(yīng)式數(shù)據(jù)泣侮;
// Powershell
new-item observer.js
// observer/observer.js
import { observer } from './index';
export function defineReactive(data, key, value) {
/**
這里是閉包的實(shí)際應(yīng)用, value 的引用在外部使用紧唱,
不會(huì)被收回旁瘫,每次更新數(shù)據(jù)都從 defineReactive 的作用域 VO 里面獲取value
*/
observer(value); // 有可能當(dāng)前value 是一個(gè)對(duì)象, 所以再調(diào)用一次 observer函數(shù)
return Object.defineProperty(data, key, {
get () {
return value;
},
set (newValue) {
if (newValue === value) return;
value = newValue;
}
})
}
class Observer {
constructor(data) {
this.walk(data)
}
walk(data) {
// 遍歷傳入的 對(duì)象琼蚯, 循環(huán)調(diào)用 defineReactive酬凳;
let keys = Object.keys(data);
for (let i = 0; i < keys.length; i++) {
let key = keys[i]
defineReactive(data, key, data[key]);
}
}
};
export default Observer;