vue源码2
2018-09-06 本文已影响0人
小强不是蟑螂啊
//line 234
//定义noop函数,用来返回一个数组
function noop(a, b, c) {}
// 定义全局变量no为返回false的函数
var no = function (a, b, c) {
return false;
};
// 定义全局变量identity为返回同样参数的函数
var identity = function (_) {
return _
};
//将数组modules下的每个module的statickeys添加到数组,并用‘’,‘’切割成字符串
function genStaticKeys(modules) {
return modules.reduce(function (keys, m) {
return keys.concat(m.staticKeys || [])
}, []).join(',')
}
// 判断两个对象或者数组是否彻底相等
function looseEqual(a, b) {
//a和b类型和值都相同,返回true
if (a === b) {
return true
}
var isObjectA = isObject(a);
var isObjectB = isObject(b);
// 如果a和b都是对象
if (isObjectA && isObjectB) {
try {
var isArrayA = Array.isArray(a);
var isArrayB = Array.isArray(b);
// 如果a和b都是数组,判断两者的长度并且两个数组里每个索引子元素都要相等,递归调
用本函数
if (isArrayA && isArrayB) {
return a.length === b.length && a.every(function (e, i) {
return looseEqual(e, b[i])
})
// 如果a和b都不是数组,判断两者的属性个数相同并且每个属性也要相同,递归调用此函
数
} else if (!isArrayA && !isArrayB) {
var keysA = Object.keys(a);
var keysB = Object.keys(b);
return keysA.length === keysB.length && keysA.every(function (key) {
return looseEqual(a[key], b[key])
})
} else {
/* istanbul ignore next */
return false
}
} catch (e) {
/* istanbul ignore next */
return false
}
// 如果a和b都不是对象
} else if (!isObjectA && !isObjectB) {
return String(a) === String(b)
// 如果a和b只有一个是对象,另外一个不是
} else {
return false
}
}
// 判断val是不是数组arr的一个子元素
function looseIndexOf(arr, val) {
for (var i = 0; i < arr.length; i++) {
if (looseEqual(arr[i], val)) {
return i
}
}
return -1
}
//参数是一个函数fn,once确保fn只能被执行一次
function once(fn) {
var called = false;
return function () {
if (!called) {
called = true;
fn.apply(this, arguments);
}
}
}
var SSR_ATTR = 'data-server-rendered';
// 组件,指令,过滤器组成的数组
var ASSET_TYPES = [
'component',
'directive',
'filter'
];
//生命周期数组,其中activated,deactivated是有keep-alive组件包裹后,才能生效
var LIFECYCLE_HOOKS = [
'beforeCreate',
'created',
'beforeMount',
'mounted',
'beforeUpdate',
'updated',
'beforeDestroy',
'destroyed',
'activated',
'deactivated',
'errorCaptured'
];
//vue中的配置项,
var config = ({
// 自定义策略设置
optionMergeStrategies: Object.create(null),
// 阻止为生产环境提示
productionTip: "development" !== 'production',
// 是否允许使用vue-devtools检查代码
devtools: "development" !== 'production',
// 性能测试
performance: false,
// 错误解决方法
errorHandler: null,
//警告结局方法
warnHandler: null,
// 忽略一些变量名不能最为组件
ignoredElements: [],
// v-on自定义键名
keyCodes: Object.create(null),
//是否预设标签
isReservedTag: no,
//是否预设属性
isReservedAttr: no,
//是否未知标签
isUnknownElement: no,
//获取标签名
getTagNamespace: noop,
// 平台标签名字
parsePlatformTagName: identity,
//是否必须用prop
mustUseProp: no,
// 生命周期
_lifecycleHooks: LIFECYCLE_HOOKS
});
//字符串是否已$或者_开头
function isReserved(str) {
var c = (str + '').charCodeAt(0);
return c === 0x24 || c === 0x5F
}
//设置对象的属性的value值,是否enumberable,可改写
function def(obj, key, val, enumerable) {
Object.defineProperty(obj, key, {
value: val,
enumerable: !!enumerable,
writable: true,
configurable: true
});
}
// 匹配非字母,数字,下划线的字符
var bailRE = /[^\w.$]/;
// 解析路径,如果有非上述字符,返回
function parsePath(path) {
if (bailRE.test(path)) {
return
}
// 路径用'.'好切割成数组,返回一个函数,函数传入 的对象,一直取到数组以此作为属性的值,然后重设obj,接着往下取值。
// 这是取到最后一级obj属性,加入数组为[key1,key2,key3],那就是去obj[key1][key2][key3],第三层属性
var segments = path.split('.');
return function (obj) {
for (var i = 0; i < segments.length; i++) {
if (!obj) {
return
}
obj = obj[segments[i]];
}
return obj
}
}
//是否支持__proto__原型链
var hasProto = '__proto__' in {};
var inBrowser = typeof window !== 'undefined'; //是否在浏览器环境
var inWeex = typeof WXEnvironment !== 'undefined' && !!WXEnvironment.platform; //是否在微信平台
var weexPlatform = inWeex && WXEnvironment.platform.toLowerCase();
var UA = inBrowser && window.navigator.userAgent.toLowerCase(); //浏览器版本信息
var isIE = UA && /msie|trident/.test(UA); // 是否是ie
var isIE9 = UA && UA.indexOf('msie 9.0') > 0;
var isEdge = UA && UA.indexOf('edge/') > 0;
var isAndroid = (UA && UA.indexOf('android') > 0) || (weexPlatform === 'android');
var isIOS = (UA && /iphone|ipad|ipod|ios/.test(UA)) || (weexPlatform === 'ios');
var isChrome = UA && /chrome\/\d+/.test(UA) && !isEdge;
// Firefox has a "watch" function on Object.prototype... 火狐浏览器对象的原型链上都有watch函数
var nativeWatch = ({}).watch;
//第三个参数中的passive设为true来阻止默认监听函数, 这里设置了对象ops的passive, 如果支持, 那获取passive属性的时候, supportsPassiver已经被设置true了, 即这里设置全局变量supportsPassive 来判断是否支持 addeventListrer 的第三个参数的
var supportsPassive = false; // addeventListrer
if (inBrowser) {
try {
var opts = {};
Object.defineProperty(opts, 'passive', ({
get: function get() {
/* istanbul ignore next */
supportsPassive = true;
}
}));
window.addEventListener('test-passive', null, opts);
} catch (e) {}
}
// 是否js原生方法
function isNative(Ctor) {
return typeof Ctor === 'function' && /native code/.test(Ctor.toString())
}
// 是否支持symbol Reflect
var hasSymbol =
typeof Symbol !== 'undefined' && isNative(Symbol) &&
typeof Reflect !== 'undefined' && isNative(Reflect.ownKeys);
// 支持set,_set为set,不支持就用pollify去写,克隆一个无继承的对象,在其原型链上设置has,add,clear函数
var _Set;
if (typeof Set !== 'undefined' && isNative(Set)) {
_Set = Set;
} else {
_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;
}());
}
// 设置warn,tip等全局变量
var warn = noop;
var tip = noop;
var generateComponentTrace = (noop); // work around flow check //文件跟踪路径
var formatComponentName = (noop);
{
var hasConsole = typeof console !== 'undefined';
var classifyRE = /(?:^|[-_])(\w)/g;
这个正则对以v或者-_开头后面为字母数字下划线或者字符串将其第一个字母改为大写,并且去掉'-_'
var classify = function (str) {
return str
.replace(classifyRE, function (c) {
return c.toUpperCase();
})
.replace(/[-_]/g, '');
};
warn = function (msg, vm) {
var trace = vm ? generateComponentTrace(vm) : '';
if (config.warnHandler) {
config.warnHandler.call(null, msg, vm, trace);
} else if (hasConsole && (!config.silent)) {
console.error(("[Vue warn]: " + msg + trace));
}
};
tip = function (msg, vm) {
if (hasConsole && (!config.silent)) {88888888888888
console.warn("[Vue tip]: " + msg + (
vm ? generateComponentTrace(vm) : ''
));
}
};
//对组件的名字规则化,并返回组件名字的标签
formatComponentName = function (vm, includeFile) { //vm中的标签
如果vn的根路径等于本身,返回root标签
if (vm.$root === vm) {
return '<Root>'
}
options等于vm的options属性或者$options属性
var options = typeof vm === 'function' && vm.cid != null ?
vm.options :
vm._isVue ?
vm.$options || vm.constructor.options :
vm || {};
var name = options.name || options._componentTag;
var file = options.__file;
if (!name && file) {
var match = file.match(/([^/\\]+)\.vue$/);
name = match && match[1];
}
return (
(name ? ("<" + (classify(name)) + ">") : "<Anonymous>") +
(file && includeFile !== false ? (" at " + file) : '')
)
};
// 将数字n转成二进制,实现累加,比用for循环减少累加次数
var repeat = function (str, n) {
var res = '';
while (n) {
if (n % 2 === 1) {
res += str;
}
if (n > 1) {
str += str;
}
n >>= 1;
}
return res
};
// 组件树规则
generateComponentTrace = function (vm) {
如果参数vn存在Vue结构属性并且存在父组件
if (vm._isVue && vm.$parent) {
var tree = [];
var currentRecursiveSequence = 0;
while (vm) {
if (tree.length > 0) {
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.$parent;
}
return '\n\nfound in\n\n' + tree
.map(function (vm, i) {
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)) + ")")
}
};
};