jsVue 2.5.1 源码学习 响应式入口observe
Posted yeujuan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jsVue 2.5.1 源码学习 响应式入口observe相关的知识,希望对你有一定的参考价值。
大体思路(七)
本节内容:
deps 依赖收集的数组对象 => Dep 构造函数
/** ==> observe()
* var ob
* ==> if --isObject
* ==> if -- shouldObserve isExtensible is_Vue 是否可扩展
* ==> ob = new Observe(value);
* == if ob.vmCount++
* ==> reutrn ob
* Observe(value)
* this.value = value
* this.vmCount = 0
* def(value,‘_ob_‘,this);
* ==> ,,,
* this.dep = new Dep()
* this.walk(value)
*
*
* Observe.prototype.walk = fucntion(obj)
* defindReactive(obj,key[i])
*
* //响应式系统的核心 将数据对象的属性转化成访问器属性:getter setter
* defindReactive(obj,key,val,shallow)
* // 深度观测
*
*
* Dep()
* this.subs=[]
*
* ==> is_Vue = true
*
*
*
*
* */
watch 解析字段(属性) => Watch 观察者 实例对象$watch()
vue.js 代码如下
1 // 大体思路(七) 2 // 本节内容: 3 // deps 依赖收集的数组对象 => Dep 构造函数 4 /** ==> observe() 5 * var ob 6 * ==> if --isObject 7 * ==> if -- shouldObserve isExtensible is_Vue 是否可扩展 8 * ==> ob = new Observe(value); 9 * == if ob.vmCount++ 10 * ==> reutrn ob 11 * Observe(value) 12 * this.value = value 13 * this.vmCount = 0 14 * def(value,‘_ob_‘,this); 15 * ==> ,,, 16 * this.dep = new Dep() 17 * this.walk(value) 18 * 19 * 20 * Observe.prototype.walk = fucntion(obj) 21 * defindReactive(obj,key[i]) 22 * 23 * //响应式系统的核心 将数据对象的属性转化成访问器属性:getter setter 24 * defindReactive(obj,key,val,shallow) 25 * // 深度观测 26 * 27 * 28 * Dep() 29 * this.subs=[] 30 * 31 * ==> is_Vue = true 32 * 33 * 34 * 35 * 36 * */ 37 // watch 解析字段(属性) => Watch 观察者 实例对象$watch() 38 39 40 (function (global, factory) 41 // 兼容 cmd 42 typeof exports === ‘object‘ && module !== ‘undefined‘ ? module.exports = factory() : 43 // Amd 44 typeof define === ‘function‘ && define.amd ? define(factory) : global.Vue = factory(); 45 )(this, function () 46 var uip = 0; 47 48 function warn(string) 49 console.error(‘Vue Wran:‘ + string) 50 51 52 function warnNonpresent(target, key) 53 warn(‘属性方法‘ + key + ‘未在实例对象上定义,渲染功能正在尝试访问这个不存在的属性!‘) 54 55 56 function resolveConstructorOptions(Con) 57 var options = Con.options; 58 // 判断是否为vm的实例 或者是子类 59 return options 60 61 var hasOwnPropeerty = Object.prototype.hasOwnProperty 62 63 function hasOwn(obj, key) 64 return hasOwnPropeerty.call(obj, key) 65 66 67 function makeMap(str, expectsLoweraseC) 68 if (expectsLoweraseC) 69 str = str.toLowerCase() 70 71 var map = Object.create(null) 72 var list = str.split(‘,‘) 73 for (var i = 0; i < list.length; i++) 74 map[list[i]] = true 75 76 return function (key) 77 return map[key] 78 79 80 81 var isbuiltInTag = makeMap(‘slot,component‘, true) 82 var ishtmlTag = makeMap( 83 ‘html,body,base,head,link,meta,style,title,‘ + 84 ‘address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,‘ + 85 ‘div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,‘ + 86 ‘a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,‘ + 87 ‘s,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,‘ + 88 ‘embed,object,param,source,canvas,script,noscript,del,ins,‘ + 89 ‘caption,col,colgroup,table,thead,tbody,td,th,tr,‘ + 90 ‘button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,‘ + 91 ‘output,progress,select,textarea,‘ + 92 ‘details,dialog,menu,menuitem,summary,‘ + 93 ‘content,element,shadow,template,blockquote,iframe,tfoot‘ 94 ); 95 var isSVG = makeMap( 96 ‘svg,animate,circle,clippath,cursor,defs,desc,ellipse,filter,font-face,‘ + 97 ‘foreignObject,g,glyph,image,line,marker,mask,missing-glyph,path,pattern,‘ + 98 ‘polygon,polyline,rect,switch,symbol,text,textpath,tspan,use,view‘, 99 true 100 ); 101 var ASSET_TYPES = [ 102 ‘component‘, 103 ‘directive‘, 104 ‘filter‘ 105 ]; 106 107 var LIFECYCLE_HOOKS = [ 108 ‘beforeCreate‘, 109 ‘created‘, 110 ‘beforeMount‘, 111 ‘mounted‘, 112 ‘beforeUpdate‘, 113 ‘updated‘, 114 ‘beforeDestroy‘, 115 ‘destroyed‘, 116 ‘activated‘, 117 ‘deactivated‘, 118 ‘errorCaptured‘ 119 ]; 120 var noop = function () 121 var isReservedTag = function (key) 122 return isHTMLTag(key) || isSVG(key) 123 124 // 检测data的属性名称是否为 _ 或者$ 开始的,这些的话是vue的其他属性的值。 125 function isReserved(key) 126 var c = key.charCodeAt(0) 127 return c === 0x24 || c === 0x5F 128 129 // 检查是否为对象 130 function isObject(val) 131 return val !== null && typeof val === ‘object‘ 132 133 134 function validataComponentName(key) 135 //检测component 的自定义名称是否合格 136 // 只能是字母开头或下划线,必须是字母开头 137 if (!(/^[a-zA-Z][\w-]*$/g.test(key))) 138 warn(‘组件的名称必须是字母或中横线,必须由字母开头‘) 139 140 // 1. 不能为内置对象,2.不能是html ,和avg的内部标签 141 if (isbuiltInTag(key) || isReservedTag(key)) 142 warn(‘不能为html标签或者avg的内部标签‘) 143 144 145 146 function checkComonpents(child) 147 for (var key in child.components) 148 validataComponentName(key) 149 150 151 // 配置对象 152 var config = 153 // 自定义的策略 154 optionMergeStrategies: 155 156 var strats = config.optionMergeStrategies 157 strats.el = function (parent, child, key, vm) 158 159 if (!vm) 160 warn(‘选项‘ + key + ‘只能在vue实例用使用‘) 161 162 return defaultStrat(parent, child, key, vm) 163 164 165 function mergeData(to, form) 166 // 终极合并 167 if (!form) 168 return to 169 170 // 具体合并。 171 172 173 function mergeDataorFn(parentVal, childVal, vm) 174 // 合并 parentVal childVal 都是函数 175 if (!vm) 176 if (!childVal) 177 return parentVal 178 179 if (!parentVal) 180 return childVal 181 182 return function mergeDataFn(parentVal, childVal, vm) //只是一个函数 什么样的情况下调用 加入响应式系统 183 // 合并子组件对应的data 和 父组件对应的data 184 return mergeData( 185 typeof parentVal === ‘function‘ ? parentVal.call(this, this) : parentVal, // -----忘记写 186 typeof childVal === ‘function‘ ? childVal.call(this, this) : childVal) // -----忘记写 187 188 else // vue实例 189 return function mergeInstanceDataFn() //只是一个函数 什么样的情况下调用 加入响应式系统 190 var InstanceData = typeof childVal === ‘function‘ ? childVal.call(vm, vm) : childVal; // -----忘记写 191 var defaultData = typeof parentVal === ‘function‘ ? parentVal.call(vm, vm) : parentVal; // -----忘记写 192 if (InstanceData) 193 return mergeData(InstanceData, defaultData) 194 else // -----忘记写 195 return defaultData 196 197 198 199 200 201 strats.data = function (parent, child, key, vm) 202 if (!vm) 203 // console.log(typeof child === ‘function‘) 204 if (child && !(typeof child === ‘function‘)) 205 warn(‘data必须返回是一个function‘) 206 207 return mergeDataorFn(parent, child) 208 209 return mergeDataorFn(parent, child, vm) 210 211 // 生命周期策略的合并,值等于一个function 如果是有两个,放到一个数组里面。 212 function mergeHook(parentVal, childVal, key, vm) 213 // console.log(key) 214 // console.log(parentVal.concat(childVal) ) 215 return childVal ? parentVal ? parentVal.concat(childVal) : 216 Array.isArray(childVal) ? childVal : [childVal] : parentVal 217 218 LIFECYCLE_HOOKS.forEach(function (key) 219 strats[key] = mergeHook 220 ); 221 // 检测是否为object 222 function isPlainObject(obj) 223 return Object.prototype.toString.call(obj) === ‘[object Object]‘ 224 225 226 function assetObjectType(obj) 227 if (!isPlainObject(obj)) 228 warn(‘选项的值‘ + obj + ‘无效:必须是一个对象的‘) 229 230 231 // 对parent实现链式调用。 232 function extend(to, form) 233 for (key in form) 234 235 to[key] = form[key] 236 237 return to 238 239 // 实现Assets 的策略合并 conmponents filter diretive 240 function mergeAssets(parentVal, childVal, key, vm) 241 var parent = Object.create(parentVal || null) // 保证子类的每个值的指向都是一个新的object。否则回出现相互引用的现象。 242 if (childVal) 243 assetObjectType(childVal) 244 return extend(parent, childVal) 245 246 return parent 247 248 ASSET_TYPES.forEach(function (key) 249 strats[key + ‘s‘] = mergeAssets 250 ) 251 // 实现watch的策略和并,将相同的属性放到一个数组里面。 252 strats.watch = function (parentVal, childVal, key, vm) 253 if (!childVal) 254 return Object.create(parentVal) 255 256 var res = 257 res = extend(res, parentVal) 258 for (var key in childVal) 259 var parent = res[key] 260 var child = childVal[key] 261 res[key] = parent ? Array.isArray(parent) ? parent.concat(child) : [parent].concat(child) : 262 Array.isArray(child) ? child : [child]; 263 264 return res 265 266 // 实现props指令的合并策略 267 strats.props = function (parentVal, childVal, key, vm) 268 if (!childVal) 269 return parentVal 270 271 var res = Object.create(null) 272 extend(res, parentVal) 273 if (childVal) 274 extend(res, childVal) 275 276 return res 277 278 279 function defaultStrat(parent, child, key, vm) 280 return child === undefined ? parent : child; 281 282 var cmalizeRE = /-(\w)/g 283 284 function camelize(val) 285 return val.replace(cmalizeRE, function (c, m) 286 return m ? m.toUpperCase() : "" 287 ) 288 289 290 function normalizeProps(options) 291 var props = options.props 292 if (!props) 293 return 294 295 var i, val, name 296 var res = 297 if (Array.isArray(props)) 298 i = props.length 299 while (i--) 300 val = props[i] 301 if (toString.call(val) === ‘[object String]‘) 302 name = camelize(val) 303 res[name] = 304 type: null 305 306 else 307 warn(‘使用数组愈发时props成员‘ + val + ‘必须时一个数组‘) 308 309 310 311 312 else if (isPlainObject(props)) 313 for (var key in props) 314 val = props[key] 315 name = camelize(key) 316 res[name] = isPlainObject(val) ? val : 317 type: val 318 319 320 else 321 warn(‘选项props的值必须是一个对象或者是数组‘) 322 323 options.props = res 324 325 326 function mormalizeDirectives(options) 327 var dir = options.directives 328 var res = 329 if (!dir) 330 return 331 332 if (dir) 333 for (var key in dir) 334 var val = dir[key] 335 var name = camelize(key) 336 if (isPlainObject(val)) 337 res[name] = val 338 339 if (toString.call(val) === ‘[object Function]‘) 340 res[name] = 341 bind: val, 342 upata: val 343 344 345 346 347 options.directives = res 348 349 350 351 function mergeOptions(parent, child, vm) 352 var options = 353 // 检测是component 是否是合法的 354 checkComonpents(child) 355 // 规范props 356 normalizeProps(child) 357 // 规范 dirctives 358 mormalizeDirectives(child) 359 360 // console.log(parent, child) 361 for (key in parent) 362 magerField(key) 363 364 for (key in child) 365 if (!hasOwn(parent, key)) // parent 中循环过地方不进行循环 366 magerField(key) // ----忘记写 367 368 369 370 // 默认合并策略 371 function magerField(key) 372 // 自定义策略 默认策略 373 // console.log(key) 374 var result = strats[key] || defaultStrat // ---忘记写 375 options[key] = result(parent[key], child[key], key, vm) 376 377 // console.log(options) 378 return options 379 380 381 var allowedGlobals = makeMap( 382 ‘Infinity,undefined,NaN,isFinite,isNaN,‘ + 383 ‘parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,‘ + 384 ‘Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,‘ + 385 ‘require‘ // for Webpack/Browserify 386 ); 387 388 function isNative(Ctor) 389 return typeof Ctor !== undefined && /native code/.test(toString.call(Ctor)) 390 391 var hasproxy = typeof Proxy !== undefined && isNative(Proxy) 392 var hasHeadler = 393 has: function (target, key) 394 var val = key in target 395 // key 是否是全局对象 或者内置方法 _ 396 var isAllowed = allowedGlobals(key) || (typeof key === ‘string‘ && key.charAt(0) === ‘_‘) 397 if (!val && !isAllowed) 398 warnNonpresent(target, key) 399 400 return val || !isAllowed 401 402 403 var getHeadler = 404 get: function (target, key) 405 if (typeof key === ‘string‘ && !(key in target)) 406 warnNonpresent(target, key) 407 408 return target[key] 409 410 411 412 // 数据代理 413 function initProxy(vm) 414 var options = vm.$options 415 // 判断是否是es6 是否存在Proxy 416 if (hasproxy) 417 // 渲染函数拦截那些操作。 1. has 查询 2. get 或者 418 var headler = options.render && options.render._withStripeed ? 419 getHeadler : 420 hasHeadler; 421 vm._renderPorxy = new proxy(vm, headler) 422 else 423 // 如果不支es6 Proxy 424 vm._renderPorxy = vm 425 426 427 428 429 // 初始化当前实例的$children 和$parent 的指向 430 function initLifeCycle(vm) 431 var options = vm.$options 432 // 当前组件 父实例 433 var parent = options.parent // 组件的实例对象 434 // 是否抽象组件 435 if (parent && !parent.abstrat) 436 while (parent.$options.abstrat && parent.$parent) 437 parent = parent.$options.parent 438 439 parent.$children.push(vm) 440 441 vm.$parent = parent 442 vm.$root = parent ? parent.$root : vm; 443 444 vm.$children = []; 445 vm.$refs = ; 446 447 vm._watcher = null; 448 vm._inactive = null; 449 vm._directInactive = false; 450 vm._isMounted = false; // 是否挂载 451 vm._isDestroyed = false; // 是否销毁 452 vm._isBeingDestroyed = false; // 是否正在销毁 453 454 455 456 function callHook(vm, hook) 457 var options = vm.$options 458 var obj = options[hook] 459 if (obj) 460 for (var i = 0; i < obj.length; i++) 461 obj[i].call(vm) 462 463 464 465 466 467 function getData(data, vm) 468 return data.call(vm, vm) 469 470 471 //共享的访问器对象 472 var sharedProperty = 473 enumerable: true, 474 configurable: true, 475 get: noop, 476 set: noop 477 ; 478 479 function proxy(vm, data, key) 480 481 sharedProperty.get = function () 482 // console.log("我监听到你访问了我") 483 return this[data][key] 484 , 485 sharedProperty.set = function (newVal) 486 console.log("我设置了data的值" + key + "==" + newVal) 487 this[data][key] = newVal 488 489 490 Object.defineProperty(vm, key, sharedProperty) 491 492 493 function initData(vm) 494 var opts = vm.$options 495 var data = vm.$options.data 496 // 通过之前strats 里面合成好的数据,data是一个function ,为了独立数据调用的空间。拿到data的值。 497 data = vm._data = typeof data === ‘function‘ ? getData(data, vm) : data || 498 if (!isPlainObject(data)) 499 data = 500 warn(‘data选项应该是object对象‘) 501 502 // data methods props 里面属性名称不能相同 503 var props = opts.props 504 var methods = opts.methods 505 for (let key in data) 506 if (props && hasOwn(props, key)) 507 warn("props " + key + "选项已经定义为data的属性.") 508 else if (methods && hasOwn(methods, key)) 509 warn("methods: " + key + "选项已经定义为data的属性.") 510 else if (!isReserved(key)) 511 proxy(vm, "_data", key) 512 513 514 515 observe(data, true) 516 517 var shouldObserve = true 518 var toggleObserving = function (value) 519 shouldObserve = value 520 521 522 function Dep() 523 this.subs = [] 524 525 Dep.prototype.addSub = function (sub) 526 this.subs.push(sub) 527 528 Dep.prototype.depend = function () 529 console.log("收集依赖"); //Watch 观察者 530 531 Dep.prototype.notify = function () 532 var subs = this.subs.slice() 533 for (var i = 0; i < subs.length; i++) 534 subs[i].updata() // 数据更新的操作 Watch 535 536 537 Dep.target = null 538 539 function def(obj, key, val) // data._ob_ 实例对象 指向 Observer 540 Object.defineProperty(obj, key, 541 value: val, 542 enumerable: false, //不可枚举 543 configrable: true 544 ) 545 546 547 function Observe(value) 548 this.value = value; 549 this.vmCount = 0; 550 this.dep = new Dep() //回调列表 依赖在什么情况调用 551 def(value, ‘_ob_‘, this) 552 this.walk(value) 553 554 // 加入响应式系统 添加 setter getter 555 function defindReactive(obj, key, val, shallow) 556 var dep = new Dep() // 收集依赖 回调列表 557 var property = Object.getOwnPropertyDescriptor(obj, key) 558 var getter = property && property.get 559 var setter = property && property.set 560 // getter 和 setter 都不存在。或者都存在则为 true ===》 (!getter || setter) 561 // console.log((!getter || setter),arguments) 562 if ((!getter || setter) && arguments.length === 2) 563 val = obj[key] // 深度观测 564 565 var childOb = !shallow && observe(val) 566 Object.defineProperty(obj, key, 567 get: function () 568 var value = getter ? getter.call(obj) : val 569 if (Dep.target) 570 dep.depend() // 收集依赖 571 if (childOb) 572 childOb.dep.depend() // 收集依赖 573 574 575 return value 576 , 577 set: function (newVal) 578 var value = setter ? setter.call(obj) : val 579 // is NaN !== NaN 580 if (newVal === value || (value !== value && newVal !== newVal)) 581 return 582 583 if (setter) 584 setter.call(obj, newVal) 585 else 586 val = newVal 587 588 console.log(‘我监听到data变化‘ + newVal) 589 // 如果改变的新值为 object 或者Array 就在进行深度检测,递归。 590 childOb = !shallow && observe(val) 591 dep.notify() //通知依赖更新 592 593 594 ) 595 596 Observe.prototype.walk = function (value) 597 var keys = Object.keys(value) 598 for (var i = 0; i < keys.length; i++) 599 defindReactive(value, keys[i]) 600 601 602 // 响应式系统 603 function observe(value, asRootData) 604 var ob 605 if (!isObject(value)) 606 return; 607 608 if (shouldObserve && (Array.isArray(value) || isPlainObject(value)) && Object.isExtensible(value) && !value._isVue) 609 ob = new Observe(value) 610 611 console.log(ob) 612 if (ob && asRootData) 613 ob.vmCount++ 614 615 616 return ob 617 618 619 function initState(vm) 620 var opts = vm.$options 621 // 初始化props 622 if (opts.props) 623 initProps(vm, opts.props) 624 625 // 初始化methods 626 if (opts.methods) 627 initMethods(vm, opts.methods) 628 629 // 初始化computed 630 if (opts.computed) 631 initComputed(vm, opts.computed) 632 633 // 初始化data 如果存在就initData 634 if (opts.data) 635 initData(vm) 636 else 637 // 放在响应式系统里面 638 observe(vm._data = , true) 639 640 641 642 function initMinxin(options) 643 Vue.prototype._init = function (options) 644 var vm = this 645 // 记录生成的vue实例对象 646 vm._uip = uip++ // //-------忘记写 647 // 是否可扩展 648 vm.is_Vue = true; 649 //合并选项 650 vm.$options = mergeOptions(resolveConstructorOptions(vm.constructor), options, vm) 651 // // 初始化数值代理 652 initProxy(vm) 653 // 初始化当前实例的$children 和$parent 的指向 654 initLifeCycle(vm) 655 // 调用beforeCreate 的钩子函数 656 callHook(vm, ‘beforeCreate‘) 657 // 初始化数据 658 initState(vm) 659 660 661 662 function Vue(options) 663 // 安全机制 664 if (!(this instanceof Vue)) //-------忘记写 665 warn(‘Vue是一个构造函数,必须是由new关键字调用‘) 666 667 this._init(options) 668 669 initMinxin() // 初始化选项1: 规范 2: 合并策略。 670 Vue.options = 671 components: 672 transtions: , 673 keepAlive: , 674 solt: , 675 transtionsGroup: 676 , 677 directives: , 678 _bash: Vue 679 680 681 function initExend(Vue) 682 Vue.extend = function (extendOptions) 683 extendOptions = extendOptions || // -----忘记写 684 var Super = this 685 var Child = function VueComponent(options) 686 this._init(options) 687 688 Child.prototype = Object.create(Super.prototype) 689 Child.prototype.constructor = Child // 改变constructor 的指向 690 Child.options = mergeOptions(Super.options, extendOptions) 691 // 子类继承父类的静态方法。 692 Child.extend = Vue.extend 693 // console.log(new Child()) 694 return Child 695 696 697 initExend(Vue) 698 return Vue 699 )
html代码如下
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <meta http-equiv="X-UA-Compatible" content="ie=edge"> 7 <title>第七课</title> 8 </head> 9 <body> 10 <div id="app"> 11 <huml></huml> 12 </div> 13 <script src="vue.js"></script> 14 <!-- <script src="vue2.5.1.js"></script> --> 15 <script type="text/javascript"> 16 var componentA = 17 el: "#app" 18 19 var vm = new Vue( 20 el:"#app", 21 data: 22 message: "hello Vue", 23 key: "wodow", 24 test: 1, 25 list: 26 b:1 27 28 , 29 beforeCreate: function() 30 console.log(‘我钩子函数beforeCreate‘) 31 , 32 components: 33 humle: componentA 34 35 ) 36 vm.test = 2; 37 console.log(vm) 38 </script> 39 </body> 40 </html>
以上是关于jsVue 2.5.1 源码学习 响应式入口observe的主要内容,如果未能解决你的问题,请参考以下文章