-
Notifications
You must be signed in to change notification settings - Fork 1.8k
/
vue.js
15907 lines (14269 loc) · 705 KB
/
vue.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*!
* Vue.js v2.5.16
* (c) 2014-2018 Evan You
* Released under the MIT License.
* development 开发
* production 生产
/*
* 兼容 amd cmd 模块写法
* */
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global.Vue = factory());
}(this, (function () {
'use strict';
/* */
//Object.freeze()阻止修改现有属性的特性和值,并阻止添加新属性。
var emptyObject = Object.freeze({});
// these helpers produces better vm code in JS engines due to their
// explicitness and function inlining
// these helpers produces better vm code in JS engines due to their
// explicitness and function inlining
//判断数据 是否是undefined或者null
function isUndef(v) {
return v === undefined || v === null
}
//判断数据 是否不等于 undefined或者null
function isDef(v) {
return v !== undefined && v !== null
}
//判断是否真的等于true
function isTrue(v) {
return v === true
}
// 判断是否是false
function isFalse(v) {
return v === false
}
/**
* Check if value is primitive
* //判断数据类型是否是string,number,symbol,boolean
*/
function isPrimitive(value) {
//判断数据类型是否是string,number,symbol,boolean
return (
typeof value === 'string' ||
typeof value === 'number' ||
// $flow-disable-line
typeof value === 'symbol' ||
typeof value === 'boolean'
)
}
/**
* Quick object check - this is primarily used to tell
* Objects from primitive values when we know the value
* is a JSON-compliant type.
*/
function isObject(obj) {
//判断是否是对象
return obj !== null && typeof obj === 'object'
}
/**
* Get the raw type string of a value e.g. [object Object]
*/
//获取toString 简写
var _toString = Object.prototype.toString;
function toRawType(value) {
//类型判断 返会Array ,Function,String,Object,Re 等
return _toString.call(value).slice(8, -1)
}
/**
* Strict object type check. Only returns true
* for plain JavaScript objects.
*/
function isPlainObject(obj) {
//判断是否是对象
return _toString.call(obj) === '[object Object]'
}
function isRegExp(v) {
//判断是否是正则对象
return _toString.call(v) === '[object RegExp]'
}
/**
* Check if val is a valid array index.
*/
/**
* Check if val is a valid array index.
* 检查VAL是否是有效的数组索引。
*/
function isValidArrayIndex(val) {
//isFinite 检测是否是数据
//Math.floor 向下取整
var n = parseFloat(String(val));
//isFinite 如果 number 是有限数字(或可转换为有限数字),那么返回 true。否则,如果 number 是 NaN(非数字),或者是正、负无穷大的数,则返回 false。
return n >= 0 && Math.floor(n) === n && isFinite(val)
}
/**
* Convert a value to a string that is actually rendered.
*/
function toString(val) {
//将对象或者其他基本数据 变成一个 字符串
return val == null
? ''
: typeof val === 'object'
? JSON.stringify(val, null, 2)
: String(val)
}
/**
* Convert a input value to a number for persistence.
* If the conversion fails, return original string.
*/
function toNumber(val) {
//字符串转数字,如果失败则返回字符串
var n = parseFloat(val);
return isNaN(n) ? val : n
}
/**
* Make a map and return a function for checking if a key
* is in that map.
*
* //map 对象中的[name1,name2,name3,name4] 变成这样的map{name1:true,name2:true,name3:true,name4:true}
* 并且传进一个key值取值,这里用到策略者模式
*/
function makeMap(str,
expectsLowerCase) {
var map = Object.create(null); //创建一个新的对象
var list = str.split(','); //按字符串,分割
for (var i = 0; i < list.length; i++) {
map[list[i]] = true; //map 对象中的[name1,name2,name3,name4] 变成这样的map{name1:true,name2:true,name3:true,name4:true}
}
return expectsLowerCase
? function (val) {
return map[val.toLowerCase()];
} //返回一个柯里化函数 toLowerCase转换成小写
: function (val) {
return map[val];
} //返回一个柯里化函数 并且把map中添加一个 属性建
}
/**
* Check if a tag is a built-in tag.
* 检查标记是否为内置标记。
*/
var isBuiltInTag = makeMap('slot,component', true);
/**
* Check if a attribute is a reserved attribute.
* 检查属性是否为保留属性。
* isReservedAttribute=function(vale){ map{key:true,ref:true,slot-scope:true,is:true,vaule:undefined} }
*/
var isReservedAttribute = makeMap('key,ref,slot,slot-scope,is');
/**
* Remove an item from an array
* //删除数组
*/
function remove(arr, item) {
if (arr.length) {
var index = arr.indexOf(item);
if (index > -1) {
return arr.splice(index, 1)
}
}
}
/**
* Check whether the object has the property.
*检查对象属性是否是实例化还是原型上面的
*/
var hasOwnProperty = Object.prototype.hasOwnProperty;
function hasOwn(obj, key) {
return hasOwnProperty.call(obj, key)
}
/**
* Create a cached version of a pure function.
*/
/**
* Create a cached version of a pure function.
* 创建纯函数的缓存版本。
* 创建一个函数,缓存,再return 返回柯里化函数
* 闭包用法
*/
/***********************************************************************************************
*函数名 :cached
*函数功能描述 : 创建纯函数的缓存版本。 创建一个函数,缓存,再return 返回柯里化函数 闭包用法
*函数参数 : fn 函数
*函数返回值 : fn
*作者 :
*函数创建日期 :
*函数修改日期 :
*修改人 :
*修改原因 :
*版本 :
*历史版本 :
***********************************************************************************************/
/*
* var aFn = cached(function(string){
*
* return string
* })
* aFn(string1);
* aFn(string2);
* aFn(string);
* aFn(string1);
* aFn(string2);
*
* aFn 函数会多次调用 里面就能体现了
* 用对象去缓存记录函数
* */
function cached(fn) {
var cache = Object.create(null);
return (function cachedFn(str) {
var hit = cache[str];
return hit || (cache[str] = fn(str))
})
}
/**
* Camelize a hyphen-delimited string.
* 用连字符分隔的字符串。
* camelize = cachedFn(str)=>{ var hit = cache[str];
return hit || (cache[str] = fn(str))}
调用一个camelize 存一个建进来 调用两次 如果建一样就返回 hit
横线-的转换成驼峰写法
可以让这样的的属性 v-model 变成 vModel
*/
var camelizeRE = /-(\w)/g;
var camelize = cached(function (str) {
return str.replace(camelizeRE, function (_, c) {
return c ? c.toUpperCase() : '';
})
});
/**
* Capitalize a string. 将首字母变成大写。
*/
var capitalize = cached(function (str) {
return str.charAt(0).toUpperCase() + str.slice(1)
});
/**
* Hyphenate a camelCase string.
* \B的用法
\B是非单词分界符,即可以查出是否包含某个字,如“ABCDEFGHIJK”中是否包含“BCDEFGHIJK”这个字。
*/
var hyphenateRE = /\B([A-Z])/g;
var hyphenate = cached(function (str) {
//大写字母,加完减号又转成小写了 比如把驼峰 aBc 变成了 a-bc
//匹配大写字母并且两面不是空白的 替换成 '-' + '字母' 在全部转换成小写
return str.replace(hyphenateRE, '-$1').toLowerCase();
});
/**
* Simple bind polyfill for environments that do not support it... e.g.
* PhantomJS 1.x. Technically we don't need this anymore since native bind is
* now more performant in most browsers, but removing it would be breaking for
* code that was able to run in PhantomJS 1.x, so this must be kept for
* backwards compatibility.
* 改变this 上下文
* 执行方式
*/
/* istanbul ignore next */
//绑定事件 并且改变上下文指向
function polyfillBind(fn, ctx) {
function boundFn(a) {
var 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, ctx) {
return fn.bind(ctx)
}
//bing 改变this上下文
var bind = Function.prototype.bind
? nativeBind
: polyfillBind;
/**
* Convert an Array-like object to a real Array.
* 将假的数组转换成真的数组
*/
function toArray(list, start) {
start = start || 0;
var i = list.length - start;
var ret = new Array(i);
while (i--) {
ret[i] = list[i + start];
}
return ret
}
/**
* Mix properties into target object.
* * 浅拷贝
*/
/***********************************************************************************************
*函数名 :extend
*函数功能描述 : 浅拷贝
*函数参数 : to 超类, _from 子类
*函数返回值 : 合并类
*作者 :
*函数创建日期 :
*函数修改日期 :
*修改人 :
*修改原因 :
*版本 :
*历史版本 :
***********************************************************************************************/
//对象浅拷贝,参数(to, _from)循环_from的值,会覆盖掉to的值
function extend(to, _from) {
for (var key in _from) {
to[key] = _from[key];
}
return to
}
/**
* Merge an Array of Objects into a single Object.
*
*/
/***********************************************************************************************
*函数名 :toObject
*函数功能描述 : 和并对象数组合并成一个对象
*函数参数 : arr 数组对象类
*函数返回值 :
*作者 :
*函数创建日期 :
*函数修改日期 :
*修改人 :
*修改原因 :
*版本 :
*历史版本 :
***********************************************************************************************/
function toObject(arr) {
var res = {};
for (var i = 0; i < arr.length; i++) {
if (arr[i]) {
extend(res, arr[i]);
}
}
return res
}
/**
* Perform no operation.
* Stubbing args to make Flow happy without leaving useless transpiled code
* with ...rest (https://flow.org/blog/2017/05/07/Strict-Function-Call-Arity/)
*/
function noop(a, b, c) {
}
/**
* Always return false.
* 返回假的
*/
var no = function (a, b, c) {
return false;
};
/**
* Return same value
*返回相同值
*/
var identity = function (_) {
return _;
};
/**
* Generate a static keys string from compiler modules.
*
* [{ staticKeys:1},{staticKeys:2},{staticKeys:3}]
* 连接数组对象中的 staticKeys key值,连接成一个字符串 str=‘1,2,3’
*/
function genStaticKeys(modules) {
return modules.reduce(
function (keys, m) {
//累加staticKeys的值变成数组
return keys.concat(m.staticKeys || [])
},
[]
).join(',') //转换成字符串
}
/**
* Check if two values are loosely equal - that is,
* if they are plain objects, do they have the same shape?
* 检测a和b的数据类型,是否是不是数组或者对象,对象的key长度一样即可,数组长度一样即可
*/
function looseEqual(a, b) {
if (a === b) {
return true
} //如果a和b是完全相等 则true
var isObjectA = isObject(a);
var isObjectB = isObject(b);
if (isObjectA && isObjectB) { //如果a和都是对象则让下走
try {
var isArrayA = Array.isArray(a);
var isArrayB = Array.isArray(b);
if (isArrayA && isArrayB) { //如果a和b都是数组
// every 条件判断
return a.length === b.length && a.every(function (e, i) { //如果a长度和b长度一样的时候
return looseEqual(e, b[i]) //递归
})
} else if (!isArrayA && !isArrayB) { //或者a和b都不是数组
var keysA = Object.keys(a); // 获取到a的key值 变成一个数组
var keysB = Object.keys(b); // 获取到b的key值 变成一个数组
//他们的对象key值长度是一样的时候 则加载every 条件函数
return keysA.length === keysB.length && keysA.every(function (key) {
//递归 a和b的值
return looseEqual(a[key], b[key])
})
} else {
//如果不是对象跳槽循环
/* istanbul ignore next */
return false
}
} catch (e) {
//如果不是对象跳槽循环
/* istanbul ignore next */
return false
}
} else if (!isObjectA && !isObjectB) { //b和a 都不是对象的时候
//把a和b变成字符串,判断他们是否相同
return String(a) === String(b)
} else {
return false
}
}
// 判断 arr数组中的数组 是否和val相等。
// 或者 arr数组中的对象,或者对象数组 是否和val 相等
function looseIndexOf(arr, val) {
for (var i = 0; i < arr.length; i++) {
if (looseEqual(arr[i], val)) {
return i
}
}
return -1
}
/**
* Ensure a function is called only once.
* 确保该函数只调用一次 闭包函数
*/
function once(fn) {
var called = false;
return function () {
if (!called) {
called = true;
fn.apply(this, arguments);
}
}
}
//ssr标记属性
var SSR_ATTR = 'data-server-rendered';
var ASSET_TYPES = [
'component', //组建指令
'directive', //定义指令 指令
'filter' //过滤器指令
];
var LIFECYCLE_HOOKS = [
'beforeCreate', // 生命周期 开始实例化 vue 指令
'created', //生命周期 结束实例化完 vue 指令
'beforeMount', //生命周期 开始渲染虚拟dom ,挂载event 事件 指令
'mounted', //生命周期 渲染虚拟dom ,挂载event 事件 完 指令
'beforeUpdate', //生命周期 开始更新wiew 数据指令
'updated', //生命周期 结束更新wiew 数据指令
'beforeDestroy', //生命周期 开始销毁 new 实例 指令
'destroyed', //生命周期 结束销毁 new 实例 指令
'activated', //keep-alive组件激活时调用。
'deactivated', //deactivated keep-alive组件停用时调用。
'errorCaptured' // 具有此钩子的组件捕获其子组件树(不包括其自身)中的所有错误(不包括在异步回调中调用的那些)。
];
/* */
var config = ({
/**
* Option merge strategies (used in core/util/options)
*/
// $flow-disable-line
//合并对象 策略
optionMergeStrategies: Object.create(null),
/**
* Whether to suppress warnings.
* * 是否禁止警告。
*/
silent: false,
/**
* Show production mode tip message on boot?
* 在引导时显示生产模式提示消息?
* webpack打包判断执行环境是不是生产环境,如果是生产环境会压缩并且没有提示警告之类的东西
*/
productionTip: "development" !== 'production',
/**
* Whether to enable devtools
* 是否启用DevTools
*/
devtools: "development" !== 'production',
/**
* Whether to record perf
* 是否记录PERF
*/
performance: false,
/**
* Error handler for watcher errors
*监视器错误的错误处理程序
*/
errorHandler: null,
/**
* Warn handler for watcher warns
* 观察加警告处理。
*/
warnHandler: null,
/**
* Ignore certain custom elements
* 忽略某些自定义元素
*/
ignoredElements: [],
/**
* Custom user key aliases for v-on
* 用于V-on的自定义用户密钥别名 键盘码
*/
// $flow-disable-line
keyCodes: Object.create(null),
/**
* Check if a tag is reserved so that it cannot be registered as a
* component. This is platform-dependent and may be overwritten.
* 检查是否保留了一个标签,使其不能注册为组件。这是平台相关的,可能会被覆盖。
*/
isReservedTag: no,
/**
* Check if an attribute is reserved so that it cannot be used as a component
* prop. This is platform-dependent and may be overwritten.
* 检查属性是否被保留,使其不能用作组件支持。这是平台相关的,可能会被覆盖。
*/
isReservedAttr: no,
/**
* Check if a tag is an unknown element.
* Platform-dependent.
* Check if a tag is an unknown element. Platform-dependent.
* 检查标签是否为未知元素依赖于平台的检查,如果标签是未知元素。平台相关的
*
*/
isUnknownElement: no,
/**
* Get the namespace of an element
* 获取元素的命名空间
*/
getTagNamespace: noop,
/**
* Parse the real tag name for the specific platform.
* 解析真实的标签平台
*/
parsePlatformTagName: identity,
/**
* Check if an attribute must be bound using property, e.g. value
* Platform-dependent.
* 检查属性是否必须使用属性绑定,例如依赖于依赖于平台的属性。
*/
mustUseProp: no,
/**
* Exposed for legacy reasons
* 因遗产原因暴露
* 声明周期对象
*/
_lifecycleHooks: LIFECYCLE_HOOKS
})
/* */
/**
* Check if a string starts with $ or _
* 检查一个字符串是否以$或者_开头
*/
function isReserved(str) {
var c = (str + '').charCodeAt(0);
return c === 0x24 || c === 0x5F
}
/**
* Define a property.
* 用defineProperty 定义属性
* 详细地址 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
第一个参数是对象
第二个是key
第三个是vue
第四个是 是否可以枚举
*/
function def(obj, key, val, enumerable) {
Object.defineProperty(obj, key, {
value: val, //值
enumerable: !!enumerable, //定义了对象的属性是否可以在 for...in 循环和 Object.keys() 中被枚举。
writable: true, //可以 改写 value
configurable: true //configurable特性表示对象的属性是否可以被删除,以及除writable特性外的其他特性是否可以被修改。
});
}
/**
* Parse simple path.
* 解析。
*/
var bailRE = /[^\w.$]/; //匹配不是 数字字母下划线 $符号 开头的为true
function parsePath(path) {
console.log(path)
if (bailRE.test(path)) { //匹配上 返回 true
return
}
//匹配不上 path在已点分割
var segments = path.split('.');
return function (obj) {
for (var i = 0; i < segments.length; i++) {
//如果没有参数则返回
if (!obj) {
return
}
//将对象中的一个key值 赋值给该对象 相当于 obj = obj[segments[segments.length-1]];
obj = obj[segments[i]];
}
//否则返回一个对象
return obj
}
}
/* */
// can we use __proto__?
var hasProto = '__proto__' in {};
// Browser environment sniffing
//判断设备和浏览器
var inBrowser = typeof window !== 'undefined';
//如果不是浏览器
var inWeex = typeof WXEnvironment !== 'undefined' && !!WXEnvironment.platform; //weex 环境 一个 vue做app包的框架
var weexPlatform = inWeex && WXEnvironment.platform.toLowerCase();//weex 环境 一个 vue做app包的框架
//window.navigator.userAgent属性包含了浏览器类型、版本、操作系统类型、浏览器引擎类型等信息,通过这个属性来判断浏览器类型
var UA = inBrowser && window.navigator.userAgent.toLowerCase(); //获取浏览器
var isIE = UA && /msie|trident/.test(UA); //ie
var isIE9 = UA && UA.indexOf('msie 9.0') > 0; //ie9
var isEdge = UA && UA.indexOf('edge/') > 0; //ie10 以上
var isAndroid = (UA && UA.indexOf('android') > 0) || (weexPlatform === 'android'); //安卓
var isIOS = (UA && /iphone|ipad|ipod|ios/.test(UA)) || (weexPlatform === 'ios'); //ios
var isChrome = UA && /chrome\/\d+/.test(UA) && !isEdge; //谷歌浏览器
// Firefox has a "watch" function on Object.prototype...
var nativeWatch = ({}).watch;
//兼容火狐浏览器写法
var supportsPassive = false;
if (inBrowser) {
try {
var opts = {};
Object.defineProperty(opts, 'passive', ({
get: function get() {
/* istanbul ignore next */
supportsPassive = true;
}
})); // https://github.com/facebook/flow/issues/285
window.addEventListener('test-passive', null, opts);
} catch (e) {
}
}
// this needs to be lazy-evaled because vue may be required before
// vue-server-renderer can set VUE_ENV
//vue 服务器渲染 可以设置 VUE_ENV
var _isServer;
//判断是不是node 服务器环境
var isServerRendering = function () {
if (_isServer === undefined) {
/* istanbul ignore if */
//如果不是浏览器 并且global 对象存在,那么有可能是node 脚本
if (!inBrowser && typeof global !== 'undefined') {
//
// detect presence of vue-server-renderer and avoid
// Webpack shimming the process
//_isServer 设置是服务器渲染
_isServer = global['process'].env.VUE_ENV === 'server';
} else {
_isServer = false;
}
}
return _isServer
};
// detect devtools
//检测开发者工具。
var devtools = inBrowser && window.__VUE_DEVTOOLS_GLOBAL_HOOK__;
/* istanbul ignore next */
function isNative(Ctor) {
//或者判断该函数是不是系统内置函数
//判断一个函数中是否含有 'native code' 字符串 比如
// function code(){
// var native='native code'
// }
// 或者
// function code(){
// var native='native codeasdfsda'
// }
return typeof Ctor === 'function' && /native code/.test(Ctor.toString())
}
//判断是否支持Symbol 数据类型
var hasSymbol =
//Symbol es6新出来的一种数据类型,类似于string类型,声明唯一的数据值
typeof Symbol !== 'undefined' && isNative(Symbol) &&
// Reflect.ownKeys
// Reflect.ownKeys方法用于返回对象的所有属性,基本等同于Object.getOwnPropertyNames与Object.getOwnPropertySymbols之和。
typeof Reflect !== 'undefined' && isNative(Reflect.ownKeys);
var _Set;
/* istanbul ignore if */ // $flow-disable-line
//ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
// Set 本身是一个构造函数,用来生成 Set 数据结构。
//判断是否有set这个方法
if (typeof Set !== 'undefined' && isNative(Set)) {
// use native Set when available.
_Set = Set;
} else {
// a non-standard Set polyfill that only works with primitive keys.
//如果没有他自己写一个
_Set = (function () {
function Set() {
this.set = Object.create(null);
}
Set.prototype.has = function has(key) {
return this.set[key] === true
};
Set.prototype.add = function add(key) {
this.set[key] = true;
};
Set.prototype.clear = function clear() {
this.set = Object.create(null);
};
return Set;
}());
}
var warn = noop;
var tip = noop;
var generateComponentTrace = (noop); // work around flow check 绕流检查
var formatComponentName = (noop);
{
//判断是否有console 打印输出属性
var hasConsole = typeof console !== 'undefined';
var classifyRE = /(?:^|[-_])(\w)/g;
//非捕获 匹配不分组 。 就是可以包含,但是不匹配上
//过滤掉class中的 -_ 符号 并且把字母开头的改成大写
var classify = function (str) {
return str.replace(classifyRE,
function (c) {
return c.toUpperCase();
}).replace(/[-_]/g, '');
};
/***********************************************************************************************
*函数名 :warn
*函数功能描述 : 警告信息提示
*函数参数 : msg: 警告信息, vm:vue对象
*函数返回值 : void
*作者 :
*函数创建日期 :
*函数修改日期 :
*修改人 :
*修改原因 :
*版本 :
*历史版本 :
***********************************************************************************************/
warn = function (msg, vm) {
//vm 如果没有传进来就给空, 不然给执行generateComponentTrace 收集 vue错误码
var trace = vm ? generateComponentTrace(vm) : '';
//warnHandler 如果存在 则调用他
if (config.warnHandler) {
config.warnHandler.call(null, msg, vm, trace);
} else if (hasConsole && (!config.silent)) {
//如果config.warnHandler 不存在则 console 内置方法打印
console.error(("[Vue warn]: " + msg + trace));
}
};
//也是个警告输出方法
tip = function (msg, vm) {
if (hasConsole && (!config.silent)) {
//
console.warn("[Vue tip]: " + msg + (
vm ? generateComponentTrace(vm) : ''
));
}
};
/***********************************************************************************************
*函数名 :formatComponentName
*函数功能描述 : 格式组件名
*函数参数 : msg: 警告信息, vm:vue对象
*函数返回值 : void
*作者 :
*函数创建日期 :
*函数修改日期 :
*修改人 :
*修改原因 :
*版本 :
*历史版本 :
***********************************************************************************************/
formatComponentName = function (vm, includeFile) {
if (vm.$root === vm) {
return '<Root>'
}
/*
* 如果 vm === 'function' && vm.cid != null 条件成立 则options等于vm.options
* 当vm === 'function' && vm.cid != null 条件不成立的时候 vm._isVue ? vm.$options || vm.constructor.options : vm || {};
* vm._isVue为真的时候 vm.$options || vm.constructor.options ,vm._isVue为假的时候 vm || {}
* */
var options =
typeof vm === 'function' && vm.cid != null
? vm.options : vm._isVue ? vm.$options || vm.constructor.options : vm || {};
var name = options.name || options._componentTag;
console.log('name=' + name);
var file = options.__file;
if (!name && file) {
//匹配.vue 后缀的文件名
//如果文件名中含有vue的文件将会被匹配出来 但是会多虑掉 \符号
var match = file.match(/([^/\\]+)\.vue$/);
name = match && match[1];
}
//可能返回 classify(name)
//name 组件名称或者是文件名称
/*
* classify 去掉-_连接 大些字母连接起来
* 如果name存在则返回name
* 如果name不存在那么返回‘<Anonymous>’+ 如果file存在并且includeFile!==false的时候 返回" at " + file 否则为空
*
* */
return (
(name ? ("<" + (classify(name)) + ">") : "<Anonymous>") +
(file && includeFile !== false ? (" at " + file) : '')
)
};
/*
*重复 递归 除2次 方法+ str
* */
var repeat = function (str, n) {
var res = '';
while (n) {
if (n % 2 === 1) {
res += str;
}
if (n > 1) {
str += str;
}
n >>= 1;
//16 8
//15 7 相当于除2 向下取整2的倍数
//console.log( a >>= 1)
}
return res
};
/***********************************************************************************************
*函数名 :generateComponentTrace
*函数功能描述 : 生成组建跟踪 vm=vm.$parent递归收集到msg出处。
*函数参数 : vm 组建
*函数返回值 :
*作者 :
*函数创建日期 :
*函数修改日期 :
*修改人 :
*修改原因 :
*版本 :
*历史版本 :
***********************************************************************************************/
generateComponentTrace = function (vm) {
if (vm._isVue && vm.$parent) { //如果_isVue 等于真,并且有父亲节点的
var tree = []; //记录父节点
var currentRecursiveSequence = 0;
while (vm) { //循环 vm 节点
if (tree.length > 0) {//tree如果已经有父节点的
var last = tree[tree.length - 1];
if (last.constructor === vm.constructor) { //上一个节点等于父节点 个人感觉这里用户不会成立
currentRecursiveSequence++;
vm = vm.$parent;
continue
} else if (currentRecursiveSequence > 0) { //这里也不会成立
tree[tree.length - 1] = [last, currentRecursiveSequence];
currentRecursiveSequence = 0;
}
}
tree.push(vm); //把vm添加到队列中
vm = vm.$parent;
}
return '\n\nfound in\n\n' + tree
.map(function (vm, i) {
//如果i是0 则输出 ‘---->’
//如果i 不是0的时候输出组件名称
return ("" + (i === 0 ?
'---> ' : repeat(' ', 5 + i * 2)) +
(
Array.isArray(vm) ?
((formatComponentName(vm[0])) + "... (" + (vm[1]) + " recursive calls)")
: formatComponentName(vm)
)
);
})
.join('\n')
} else {
//如果没有父组件则输出一个组件名称
return ("\n\n(found in " + (formatComponentName(vm)) + ")")
}
};
}
/* */
/* */
var uid = 0;
/**
* A dep is an observable that can have multiple dep是可观察到的,可以有多个
* directives subscribing to it.订阅它的指令。
*
*/