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