vueJs源码解读0-2
来源:互联网 发布:sql%20server%202000 编辑:程序博客网 时间:2024/06/07 06:42
上篇文章已经对index.js中的基本调用情况做了说明,接下来的几篇将对各个函数做仔细的分析,能力有限,文章中不足之处,希望大家能够指正!
上篇中提到在instance/vue中使用了9个高阶函数来构建(install)Vue构造函数(并不会调用该构造函数的进行初始化的过程),一切等在使用new Vue({….})的时候将一个全新的对象作为函数内this的值,返回该新对象作为结果(函数 调用中构造函数调用的方法)
function Vue (options) { this._init(options)}
创建函数中函数申明的创建的方法(涉及知识函数声明的提升),this为函数方法调用的接收者,一般为构造函数调用的方式 new Vue()
initMixin(Vue)
Mixin-mix in( 混入加入) 可能是作者取这个名字的原因吧(只是妄加猜测,具体已作者本人意图为准)
import initMixin from ‘./internal/init’ 会在internal/init中就会存在default的export接下来的分析将会从这个开始着手
逐行代码的分析如
let uid = 0
设置了uid只在当前的块中有效,let具体可以在预热解读中有说明
export default function (Vue) {.....}
export default 匿名函数具体用法可以在预热解读中找到,接下来的也即是function中的内容,接收参数为Vue
Vue.prototype._init = function (options){ ..... }
Vue也即是传入进来的参数(函数名),函数会自带一个默认的prototype的属性在新建立之前几乎为空,当使用new创建Vue的实例的时候,会得到自动分配的原型对象,存在User的prototype例如我们使用 var vm=new Vue({})来初始化构造方法的时候(先查找自身的属性再去原型链中进行查找)
对于javaScript的继承机制基于原型链(ES5),javaScript的实例对象由构造函数与在实例件共享的原型对象组成,对于原型用的较多的1个创建的方法(m.prototype)与2个获取原型的方法(obj.getPrototypeOf(m)和obj. _ proto _).其中
options = options || {}
判断options是否为null,0,-0,undefined,false,”,NaN等情况(以上也即是js的7大假值),当options不为假则直接执行赋值,否则为{}。(涉及赋值运算符优先级,||运算时当左边为假才会执行右边;左右options的不一样);
this.$el = null this.$parent = options.parent this.$root = this.$parent? this.$parent.$root : this this.$children = [] this.$refs = {} // child vm references this.$els = {} // element references this._watchers = [] // all watchers as an array this._directives = [] // all directives
this实例化之后也即是Vue对象,未指定调用接收者为undefined;先来了解下基本的含义,在后面涉及到会仔细介绍:
$parent存在的话则为父实例; $root:当前组件树的根 Vue 实例。如果当前实例没有父实例为自身。$children 当前实例的直接子组件。
$refs:一个对象,包含注册有 v-ref 的子组件。\$els对象中包含注册有 v-el 的 DOM 元素。
// a uid this._uid = uid++ //上文中定义的let uid // a flag to avoid this being observed 设置标志避免被检测到 this._isVue = true // events bookkeeping 事件统计 this._events = {} // registered callbacks this._eventsCount = {} // for $broadcast optimization //$broadcast的优化 // fragment instance properties fragment实例属性 this._isFragment = false this._fragment = // @type {DocumentFragment} this._fragmentStart = // @type {Text|Comment} this._fragmentEnd = null // @type {Text|Comment} // lifecycle state 生命周期状态 this._isCompiled = this._isDestroyed = this._isReady = this._isAttached = this._isBeingDestroyed = this._vForRemoving = false this._unlinkFn = null
各个实例到底什么意思,相信也很困惑,这里只要稍微有印象即可在之后的分析与学习中会逐步解释
// context: // if this is a transcluded component, context // will be the common parent vm of this instance // and its host. 如果这是一个嵌入式的组件,上下文将是这个实例共有父实例(或宿主) this._context = options._context || this.$parent // scope: // if this is inside an inline v-for, the scope // will be the intermediate scope created for this // repeat fragment. this is used for linking props // and container directives. 如果这是在一个内联的v-for,将由这个循环的片段产生中间的作用域范围,被用在链接父组件的数据和指令容器 this._scope = options._scope // fragment: // if this instance is compiled inside a Fragment, it // needs to reigster itself as a child of that fragment // for attach/detach to work properly. 如果这个实例在某个片段里已经编译,需要在该片段上进行注册,利于attach或detach的正常工作 this._frag = options._frag if (this._frag) { this._frag.children.push(this) } // push self into parent / transclusion host 如果存在父实例则将其建立双方的链接 if (this.$parent) { this.$parent.$children.push(this) } // merge options. 合并options,含有一个mergeOptions的函数 options = this.$options = mergeOptions( this.constructor.options, options, this )
import { mergeOptions } from ‘../../util/index’
export * from './lang'export * from './env'export * from './dom'export * from './options' //optionsexport * from './component'export * from './debug'export { defineReactive } from '../observer/index'
export * 也即是将所有的标记过的均导出
在options.js中可以看到
/** * Merge two option objects into a new one. * Core utility used in both instantiation and inheritance. * 主要用于在实例化与继承 * @param {Object} parent * @param {Object} child * @param {Vue} [vm] - if vm is present, indicates this is * an instantiation merge. * options = this.$options = mergeOptions( this.constructor.options, options, this ) */export function mergeOptions (parent, child, vm) {}
下面均是该函数内的代码片段
guardComponents(child) guardProps(child)
function guardComponents (options){ ... }
对于guardComponents主要用作options中的组件构造,下文的代码为guardComponents中的代码
var vm = new Vue({ el: '...', data:{}, components: { 'a':{}, 'b':{} }})
if (options.components) { ...... }
如果在options中存在components的存在,则会进行下部分的代码
var components = options.components = guardArrayAssets(options.components)
赋值语句从右至左,使用guardArrayAssets函数将数组形式的转化为键值对的形式
guardArrayAssets:
function guardArrayAssets (assets) {//assets 也即是传递过来的options.components//1.components:{'s':{},'d':{}}//2.componets:[{'name':'...','id':'...'}]//3.? if (isArray(assets)) { var res = {} var i = assets.length var asset //数组循环取值组成键值对的形式 key值由id决定 while (i--) { asset = assets[i] var id = typeof asset === 'function' ? ((asset.options && asset.options.name) || asset.id) : (asset.name || asset.id) //id异常情况 if (!id) { process.env.NODE_ENV !== 'production' && warn( 'Array-syntax assets must provide a "name" or "id" field.' ) } else { //规整为key-value的形式 res[id] = asset } } return res } return assets}
可以看出有3种方式填写的option.components,主要目的是规整为字典的形式便于后面的直接调用
下面回到guardComponents
var components = options.components = guardArrayAssets(options.components)var ids = Object.keys(components)
这里用到了一个Object.keys方法,获取规整后的components的键值数组
The Object.keys() method returns an array of a given object’s own enumerable properties, in the same order as that provided by a for…in loop (the difference being that a for-in loop enumerates properties in the prototype chain as well).
返回一个枚举所有对象属性的数组,类似于for-in 枚举(并不保证按对象的顺序输各个属性 ,不可预测的顺序unpredicted order)
接下来飘逸与自然的for循环如下:
for (var i = 0, l = ids.length; i < l; i++) { var key = ids[i] if (commonTagRE.test(key) || reservedTagRE.test(key)) { process.env.NODE_ENV !== 'production' && warn( 'Do not use built-in or reserved HTML elements as component ' + 'id: ' + key ) continue } // record a all lowercase <-> kebab-case mapping for // possible custom element case error warning if (process.env.NODE_ENV !== 'production') { map[key.replace(/-/g, '').toLowerCase()] = hyphenate(key) } def = components[key] if (isPlainObject(def)) { components[key] = Vue.extend(def) } }
其中commonTagRE与reservedTagRE为options.js中导入的两个属性 import { commonTagRE, reservedTagRE } from './component'
export const commonTagRE = /^(div|p|span|img|a|b|i|br|ul|ol|li|h1|h2|h3|h4|h5|h6|code|pre|table|th|td|tr|form|label|input|select|option|nav|article|section|header|footer)$/iexport const reservedTagRE = /^(slot|partial|component)$/i
const为es6中的关键字,表示不可以修改常量只在当前模块中有效,想要在其他模块中引用也即是利用前面提到的export命令,不会提升,必须先申明后使用
变量的提升:某一作用域范围内
console.info(v) ==> var v
var v=’tev’ console.info(v)
v=’tev’
正则表达式中:
/i (忽略大小写)
/g (全文查找出现的所有匹配字符)
/m (多行查找)
/gi(全文查找、忽略大小写)
/ig(全文查找、忽略大小写)
键值中
process.env.NODE_ENV !== 'production' && warn( 'Do not use built-in or reserved HTML elements as component ' + 'id: ' + key )
不要使用保留的slot,partial,component与Html的标签作为键值
def = components[key] if (isPlainObject(def)) { components[key] = Vue.extend(def) }
使用vue.extend定义组件,如下例子将更好解释
components:{ 'my-component':{ template:'<div>A custom component!</div>' } },
html页面中使用<\my-component><\/\my-component>等同于
components:[{ // 'id':'my-component', 'name':'my-component', 'template':'<div>A custom component!</div>' } ],
等同于:
var MyComponent = Vue.extend({ template: '<div>A custom component!</div>'})Vue.component('my-component', MyComponent)
上面的代码中,这里涉及到两个isplainObject与Vue.extend,x下面将对其进分析
if (isPlainObject(def)) { components[key] = Vue.extend(def) }
import { isArray, isPlainObject,} from './lang'
/** * Strict object type check. Only returns true * for plain JavaScript objects. * * @param {*} obj * @return {Boolean} *///使用toString()方法判断类型,可以表面toString对null的判断方法,如下图所示var toString = Object.prototype.toStringvar OBJECT_STRING = '[object Object]'export function isPlainObject (obj) { return toString.call(obj) === OBJECT_STRING}/** * Array type check. * * @param {*} obj * @return {Boolean} *///也即是调用Array方法中的isArray方法export const isArray = Array.isArray
Vue.extend在global-api.js中在接下来的中会分析
感觉跑偏了很远这样流水式的分析要知道自己要回到哪个地方
mergeOptions
export function mergeOptions (parent, child, vm) {//在Options之前将options:components与props定义好 guardComponents(child) guardProps(child) ....}
Vue.prototype._init
Vue.prototype._init = function (options){ ... options = this.$options = mergeOptions( this.constructor.options, options, this )}
props的定义
A list/hash of attributes that are exposed to accept data from the parent component(从父组件中获得数据). It has a simple Array-based syntax (数组形式)and an alternative Object-based(对象形式) syntax that allows advanced configurations such as type checking, custom validation and default values(对象形式用于高级的设置如 类型检查,自定义验证,默认值等).
guardProps(child)将所有的props规格化为基于对象的格式(虽然支持数组与对象的两种形式),child也即是为init中传入的options props: ['size', 'myMessage'] props: [{'name':'size'},{'name':'myMessage'}], props: { // 只检测类型 size: Number, // 检测类型 + 其它验证 name: { type: String, required: true, // 双向绑定 twoWay: true } }
function guardProps (options) { var props = options.props var i, val if (isArray(props)) { //为数组类型 options.props = {} i = props.length while (i--) { val = props[i] if (typeof val === 'string') { //为String类型的时候将其值设置为空 'size':null options.props[val] = null } else if (val.name) { //取val.name options.props[val.name] = val } } } else if (isPlainObject(props)) { var keys = Object.keys(props) i = keys.length while (i--) { val = props[keys[i]] if (typeof val === 'function') { //{ 初始为Object类型 {} } props[keys[i]] = { type: val } } } } }
- vueJs源码解读0-2
- vueJs源码解读0-1
- vuejs(2)
- EventBus3.0源码解读
- EventBus3.0源码解读
- EventBus3.0源码解读
- tesseract源码解读0
- CppUnit源码解读(2)
- CYYMysql 源码解读 2
- jqzoom源码解读 2
- prototype-1.4.0源码解读
- prototype-1.4.0源码解读
- Android4.0 WiFi 源码解读
- vue源码解读预热-0
- mybatis源码解读(2)
- spring-session源码解读-2
- JUnit 4.8 源码解读2
- faster rcnn源码解读2
- 解析XML上拉加载下拉刷新
- 数据库脚本参考
- C语言基础 产生100(0-99)以内随机数
- android SeekBar的自定义样式设置
- java web session监听销毁跳转
- vueJs源码解读0-2
- JS中的prototype
- jsp自定义标签tld
- grep命令
- 新版YMODE协议
- OJ平台刷题记录1
- 汇总_开发者酒馆-不定期坑新
- hdu1505 City Game(DP)
- 注解<context:component-scan>