标签:操作 做了 rtt 重写 check pos utils core efault
let vm = new Vue({el: ‘#app‘,data: {a: 1,b: [1, 2, 3]}})
import { initMixin } from ‘./init‘import { stateMixin } from ‘./state‘import { renderMixin } from ‘./render‘import { eventsMixin } from ‘./events‘import { lifecycleMixin } from ‘./lifecycle‘import { warn } from ‘../util/index‘function Vue (options) {if (process.env.NODE_ENV !== ‘production‘ &&!(this instanceof Vue)) {warn(‘Vue is a constructor and should be called with the `new` keyword‘)}this._init(options)}initMixin(Vue)stateMixin(Vue)eventsMixin(Vue)lifecycleMixin(Vue)renderMixin(Vue)export default V
function Vue (options) {if (process.env.NODE_ENV !== ‘production‘ && // 这个 if 判断,是当你不用new操作符来实例化Vue构造函数时,会爆出警告!(this instanceof Vue)) {warn(‘Vue is a constructor and should be called with the `new` keyword‘)}this._init(options) // 主要就是这一句,}
initMixin(Vue)stateMixin(Vue)eventsMixin(Vue)lifecycleMixin(Vue)renderMixin(Vue)
// initMixin(Vue) src/core/instance/init.js **************************************************Vue.prototype._init = function (options?: Object) {}// stateMixin(Vue) src/core/instance/state.js **************************************************Vue.prototype.$dataVue.prototype.$set = setVue.prototype.$delete = delVue.prototype.$watch = function(){}// renderMixin(Vue) src/core/instance/render.js **************************************************Vue.prototype.$nextTick = function (fn: Function) {}Vue.prototype._render = function (): VNode {}Vue.prototype._s = _toStringVue.prototype._v = createTextVNodeVue.prototype._n = toNumberVue.prototype._e = createEmptyVNodeVue.prototype._q = looseEqualVue.prototype._i = looseIndexOfVue.prototype._m = function(){}Vue.prototype._o = function(){}Vue.prototype._f = function resolveFilter (id) {}Vue.prototype._l = function(){}Vue.prototype._t = function(){}Vue.prototype._b = function(){}Vue.prototype._k = function(){}// eventsMixin(Vue) src/core/instance/events.js **************************************************Vue.prototype.$on = function (event: string, fn: Function): Component {}Vue.prototype.$once = function (event: string, fn: Function): Component {}Vue.prototype.$off = function (event?: string, fn?: Function): Component {}Vue.prototype.$emit = function (event: string): Component {}// lifecycleMixin(Vue) src/core/instance/lifecycle.js **************************************************Vue.prototype._mount = function(){}Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) {}Vue.prototype._updateFromParent = function(){}Vue.prototype.$forceUpdate = function () {}Vue.prototype.$destroy = function () {}
import Vue from ‘./instance/index‘import { initGlobalAPI } from ‘./global-api/index‘import { isServerRendering } from ‘core/util/env‘initGlobalAPI(Vue)Object.defineProperty(Vue.prototype, ‘$isServer‘, { //为 Vue.prototype 添加$isServer属性get: isServerRendering})Vue.version = ‘__VERSION__‘ // 在VUE 身上挂载了 version的静态属性export default Vue
Vue.configVue.util = utilVue.set = setVue.delete = delVue.nextTick = util.nextTickVue.options = {components: {KeepAlive},directives: {},filters: {},_base: Vue}Vue.useVue.mixinVue.cid = 0Vue.extendVue.component = function(){}Vue.directive = function(){}Vue.filter = function(){}Vue.prototype.$isServerVue.version = ‘__VERSION__‘
1、覆盖 Vue.config 的属性,将其设置为平台特有的一些方法2、Vue.options.directives 和 Vue.options.components 安装平台特有的指令和组件3、在 Vue.prototype 上定义 __patch__ 和 $mount
// 安装平台特定的utilsVue.config.isUnknownElement = isUnknownElementVue.config.isReservedTag = isReservedTagVue.config.getTagNamespace = getTagNamespaceVue.config.mustUseProp = mustUseProp// 安装平台特定的 指令 和 组件Vue.options = {components: {KeepAlive,Transition,TransitionGroup},directives: {model,show},filters: {},_base: Vue}Vue.prototype.__patch__Vue.prototype.$mount
const mount = Vue.prototype.$mount
Vue.compile = compileToFunctions
1、Vue.prototype 下的属性和方法的挂载主要是在 src/core/instance 目录中的代码处理的2、Vue 下的静态属性和方法的挂载主要是在 src/core/global-api 目录下的代码处理的3、web-runtime.js 主要是添加web平台特有的配置、组件和指令,web-runtime-with-compiler.js 给Vue的 $mount 方法添加 compiler 编译器,支持 template。
Vue.prototype._init = function (options?: Object) {const vm: Component = this// a uidvm._uid = uid++let startTag, endTag/* istanbul ignore if */if (process.env.NODE_ENV !== ‘production‘ && config.performance && mark) {startTag = `vue-perf-init:${vm._uid}`endTag = `vue-perf-end:${vm._uid}`mark(startTag)}// a flag to avoid this being observedvm._isVue = true// merge optionsif (options && options._isComponent) {// optimize internal component instantiation// since dynamic options merging is pretty slow, and none of the// internal component options needs special treatment.initInternalComponent(vm, options)} else { // 大部分情况下是走了这个分支,也是vue第一步要做的事情,使用mergeOptions来合并参数选项vm.$options = mergeOptions(resolveConstructorOptions(vm.constructor),options || {},vm)}/* istanbul ignore else */if (process.env.NODE_ENV !== ‘production‘) {initProxy(vm)} else {vm._renderProxy = vm}// expose real selfvm._self = vminitLifecycle(vm)initEvents(vm)initRender(vm)callHook(vm, ‘beforeCreate‘)initInjections(vm) // resolve injections before data/propsinitState(vm)initProvide(vm) // resolve provide after data/propscallHook(vm, ‘created‘)/* istanbul ignore if */if (process.env.NODE_ENV !== ‘production‘ && config.performance && mark) {vm._name = formatComponentName(vm, false)mark(endTag)measure(`${vm._name} init`, startTag, endTag)}if (vm.$options.el) {vm.$mount(vm.$options.el)}}
vm.$options = mergeOptions(resolveConstructorOptions(vm.constructor),options || {},vm)
export function resolveConstructorOptions (Ctor: Class<Component>) { //ctor 就是 VUE 构造函数let options = Ctor.options // vue 构造函数身上的 options 属性if (Ctor.super) { // 判断是否定义了 Vue.super ,这个是用来处理继承的,我们后续再讲const superOptions = resolveConstructorOptions(Ctor.super)const cachedSuperOptions = Ctor.superOptionsif (superOptions !== cachedSuperOptions) {// super option changed,// need to resolve new options.Ctor.superOptions = superOptions// check if there are any late-modified/attached options (#4976)const modifiedOptions = resolveModifiedOptions(Ctor)// update base extend optionsif (modifiedOptions) {extend(Ctor.extendOptions, modifiedOptions)}options = Ctor.options = mergeOptions(superOptions, Ctor.extendOptions)if (options.name) {options.components[options.name] = Ctor}}}return options}
// 这是原来的代码vm.$options = mergeOptions(resolveConstructorOptions(vm.constructor),options || {},vm)// 实际上传过去的参数是下面这些vm.$options = mergeOptions(// Vue.options{components: {KeepAlive,Transition,TransitionGroup},directives: {model,show},filters: {},_base: Vue},// 调用Vue构造函数时传入的参数选项 options{el: ‘#app‘,data: {a: 1,b: [1, 2, 3]}},// thisvm)
function initData (vm: Component) {let data = vm.$options.data // 第一步还是要先拿到数据,vm.$options.data 这时候还是通过 mergeOptions 合并处理后的 mergedInstanceDataFn 函数data = vm._data = typeof data === ‘function‘? data.call(vm): data || {}if (!isPlainObject(data)) {data = {}process.env.NODE_ENV !== ‘production‘ && warn(‘data functions should return an object:\n‘ +‘https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function‘,vm)}// proxy data on instanceconst keys = Object.keys(data)const props = vm.$options.propslet i = keys.lengthwhile (i--) {if (props && hasOwn(props, keys[i])) {process.env.NODE_ENV !== ‘production‘ && warn(`The data property "${keys[i]}" is already declared as a prop. ` +`Use prop default value instead.`,vm)} else {proxy(vm, keys[i]) // 目的是在实例对象上对数据进行代理,这样我们就能通过 this.a 来访问 data.a 了}}// observe dataobserve(data)data.__ob__ && data.__ob__.vmCount++}
function proxy (vm: Component, key: string) {if (!isReserved(key)) {Object.defineProperty(vm, key, { // vm是实例,key是data属性上的属性,configurable: true,enumerable: true,get: function proxyGetter () {return vm._data[key]},set: function proxySetter (val) {vm._data[key] = val}})}}
observe(data)
var o = {};Object.definedProperty(o, ‘a‘, {value: ‘b‘})
configurable:true | false,enumerable:true | false,value:任意类型的值,writable:true | false
var obj = {}//第一种情况:writable设置为false,不能重写。Object.defineProperty(obj,"newKey",{value:"hello",writable:false});//更改newKey的值obj.newKey = "change value";console.log( obj.newKey ); //hello//第二种情况:writable设置为true,可以重写Object.defineProperty(obj,"newKey",{value:"hello",writable:true});//更改newKey的值obj.newKey = "change value";console.log( obj.newKey ); //change value
var obj = {}//第一种情况:enumerable设置为false,不能被枚举。Object.defineProperty(obj,"newKey",{value:"hello",writable:false,enumerable:false});//枚举对象的属性for( var attr in obj ){console.log( attr );}//第二种情况:enumerable设置为true,可以被枚举。Object.defineProperty(obj,"newKey",{value:"hello",writable:false,enumerable:true});//枚举对象的属性for( var attr in obj ){console.log( attr ); //newKey}
//-----------------测试目标属性是否能被删除------------------------var obj = {}//第一种情况:configurable设置为false,不能被删除。Object.defineProperty(obj,"newKey",{value:"hello",writable:false,enumerable:false,configurable:false});//删除属性delete obj.newKey; //可以用delete 关键字来删除某一个对象上的属性console.log( obj.newKey ); //hello//第二种情况:configurable设置为true,可以被删除。Object.defineProperty(obj,"newKey",{value:"hello",writable:false,enumerable:false,configurable:true});//删除属性delete obj.newKey;console.log( obj.newKey ); //undefined//-----------------测试是否可以再次修改特性------------------------var obj = {}//第一种情况:configurable设置为false,不能再次修改特性。Object.defineProperty(obj,"newKey",{value:"hello",writable:false,enumerable:false,configurable:false});//重新修改特性Object.defineProperty(obj,"newKey",{value:"hello",writable:true,enumerable:true,configurable:true});console.log( obj.newKey ); //报错:Uncaught TypeError: Cannot redefine property: newKey//第二种情况:configurable设置为true,可以再次修改特性。Object.defineProperty(obj,"newKey",{value:"hello",writable:false,enumerable:false,configurable:true});//重新修改特性Object.defineProperty(obj,"newKey",{value:"hello",writable:true,enumerable:true,configurable:true});console.log( obj.newKey ); //hello
var o = {}; // 不能是O.name=" dudu "了var val = ‘dudu‘; // o 对象上的属性是其他人家的一个变量Object.definedProperty(o,‘name‘,{ // Object.definedProperty( ) 方法通过定set get 方法,强行给拉郎配get:function(){ return val }; //get: return val 把人家变量给返回了,就是人家的人了set;function(value){ val = value } //set: val = value 把人家变量赋值为传进来的参数,就是人间人了})
var O = {};Object.definedProperty(o,"name",{set:function(){console.log(‘set‘)}; //在获取对象该属性的时候触发,get:function(){console.log(‘get‘)}; // 在设置对象该属性的时候触发 , 并不会真正的设置;因为冲突了value,默认是falue})
var data = {a: 1,b: {c: 2}}observer(data) // 在这里遍历改写了get,setnew Watch(‘a‘, () => {alert(9)})new Watch(‘a‘, () => {alert(90)})new Watch(‘b.c‘, () => {alert(80)})
class Watch {constructor (exp, fn) {// ……data[exp] // 触发了data 身上的get 方法}}
dep {subs: [watcher1,watcher2,watcher3], // subs 属性是一个数组,用来维护众多订阅器addSubs: function(){ this.subs.push( …… ) },notify: function() {for(let i = 0; i< this.subs.length; i++){this.subs[i].fn()}}}
class Dep {constructor () {this.subs = []}addSub () {this.subs.push(……)}notify () {for(let i = 0; i < this.subs.length; i++){this.subs[i].fn()}}}
function defineReactive (data, key, val) { // 这个函数就是用来重写对象属性的get set 方法observer(val) // 递归的调用从而遍历let dep = new Dep() // 在这里实例化一个dep实例Object.defineProperty(data, key, {enumerable: true,configurable: true,get: function () {dep.addSub() //每当有订阅者订阅,我就新增一个return val},set: function (newVal) {if(val === newVal){return}observer(newVal)dep.notify() // 新增}})}
Dep.target = null //类似于全局变量的一个东西,用来放 这次实例化的watcherfunction pushTarget(watch){Dep.target = watch}class Watch {constructor (exp, fn) {this.exp = expthis.fn = fnpushTarget(this) // 让Dep.target赋值为本次实例化的实例data[exp] //紧接着就触发get 方法}}
get: function () {dep.addSub() //好吧,我又被触发了一次,return val},
class Dep {constructor () {this.subs = []}addSub () {this.subs.push(Dep.target)}notify () {for(let i = 0; i < this.subs.length; i++){this.subs[i].fn()}}}
标签:操作 做了 rtt 重写 check pos utils core efault
原文地址:http://www.cnblogs.com/dujuncheng/p/6934786.html