vue源码

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)) + ")")
        }
    };
};
上一篇 下一篇

猜你喜欢

热点阅读