vue.js 源代码学习笔记 ----- instance state
/* @flow */ import Dep from '../observer/dep'
import Watcher from '../observer/watcher' import {
set,
del,
observe,
observerState,
defineReactive
} from '../observer/index' import {
warn,
bind,
noop,
hasOwn,
isReserved,
handleError,
validateProp,
isPlainObject
} from '../util/index' const sharedPropertyDefinition = {
enumerable: true,
configurable: true,
get: noop,
set: noop
} export function proxy (target: Object, sourceKey: string, key: string) {
sharedPropertyDefinition.get = function proxyGetter () {
return this[sourceKey][key]
}
sharedPropertyDefinition.set = function proxySetter (val) {
this[sourceKey][key] = val
}
Object.defineProperty(target, key, sharedPropertyDefinition)
} export function initState (vm: Component) {
vm._watchers = []
const opts = vm.$options
if (opts.props) initProps(vm, opts.props)
if (opts.methods) initMethods(vm, opts.methods)
if (opts.data) {
initData(vm)
} else {
observe(vm._data = {}, true /* asRootData */)
}
if (opts.computed) initComputed(vm, opts.computed)
if (opts.watch) initWatch(vm, opts.watch)
} const isReservedProp = { key: 1, ref: 1, slot: 1 } function initProps (vm: Component, propsOptions: Object) {
const propsData = vm.$options.propsData || {}
const props = vm._props = {}
// cache prop keys so that future props updates can iterate using Array
// instead of dynamic object key enumeration.
const keys = vm.$options._propKeys = []
const isRoot = !vm.$parent
// root instance props should be converted
observerState.shouldConvert = isRoot
for (const key in propsOptions) {
keys.push(key)
const value = validateProp(key, propsOptions, propsData, vm)
/* istanbul ignore else */
if (process.env.NODE_ENV !== 'production') {
if (isReservedProp[key]) {
warn(
`"${key}" is a reserved attribute and cannot be used as component prop.`,
vm
)
}
defineReactive(props, key, value, () => {
if (vm.$parent && !observerState.isSettingProps) {
warn(
`Avoid mutating a prop directly since the value will be ` +
`overwritten whenever the parent component re-renders. ` +
`Instead, use a data or computed property based on the prop's ` +
`value. Prop being mutated: "${key}"`,
vm
)
}
})
} else {
defineReactive(props, key, value)
}
// static props are already proxied on the component's prototype
// during Vue.extend(). We only need to proxy props defined at
// instantiation here.
if (!(key in vm)) {
proxy(vm, `_props`, key)
}
}
observerState.shouldConvert = true
} function initData (vm: Component) {
let data = vm.$options.data
data = vm._data = typeof data === 'function'
? getData(data, vm)
: data || {}
if (!isPlainObject(data)) {
data = {}
process.env.NODE_ENV !== 'production' && warn(
'data functions should return an object:\n' +
'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',
vm
)
}
// proxy data on instance
const keys = Object.keys(data)
const props = vm.$options.props
let i = keys.length
while (i--) {
if (props && hasOwn(props, keys[i])) {
process.env.NODE_ENV !== 'production' && warn(
`The data property "${keys[i]}" is already declared as a prop. ` +
`Use prop default value instead.`,
vm
)
} else if (!isReserved(keys[i])) {
proxy(vm, `_data`, keys[i])
}
}
// observe data
observe(data, true /* asRootData */)
} function getData (data: Function, vm: Component): any {
try {
return data.call(vm)
} catch (e) {
handleError(e, vm, `data()`)
return {}
}
} const computedWatcherOptions = { lazy: true } function initComputed (vm: Component, computed: Object) {
const watchers = vm._computedWatchers = Object.create(null) for (const key in computed) {
const userDef = computed[key]
let getter = typeof userDef === 'function' ? userDef : userDef.get
if (process.env.NODE_ENV !== 'production') {
if (getter === undefined) {
warn(
`No getter function has been defined for computed property "${key}".`,
vm
)
getter = noop
}
}
// create internal watcher for the computed property.
watchers[key] = new Watcher(vm, getter, noop, computedWatcherOptions) // component-defined computed properties are already defined on the
// component prototype. We only need to define computed properties defined
// at instantiation here.
if (!(key in vm)) {
defineComputed(vm, key, userDef)
}
}
} export function defineComputed (target: any, key: string, userDef: Object | Function) {
if (typeof userDef === 'function') {
sharedPropertyDefinition.get = createComputedGetter(key)
sharedPropertyDefinition.set = noop
} else {
sharedPropertyDefinition.get = userDef.get
? userDef.cache !== false
? createComputedGetter(key)
: userDef.get
: noop
sharedPropertyDefinition.set = userDef.set
? userDef.set
: noop
}
Object.defineProperty(target, key, sharedPropertyDefinition)
} function createComputedGetter (key) {
return function computedGetter () {
const watcher = this._computedWatchers && this._computedWatchers[key]
if (watcher) {
if (watcher.dirty) {
watcher.evaluate()
}
if (Dep.target) {
watcher.depend()
}
return watcher.value
}
}
} function initMethods (vm: Component, methods: Object) {
const props = vm.$options.props
for (const key in methods) {
vm[key] = methods[key] == null ? noop : bind(methods[key], vm)
if (process.env.NODE_ENV !== 'production') {
if (methods[key] == null) {
warn(
`method "${key}" has an undefined value in the component definition. ` +
`Did you reference the function correctly?`,
vm
)
}
if (props && hasOwn(props, key)) {
warn(
`method "${key}" has already been defined as a prop.`,
vm
)
}
}
}
} function initWatch (vm: Component, watch: Object) {
for (const key in watch) {
const handler = watch[key]
if (Array.isArray(handler)) {
for (let i = 0; i < handler.length; i++) {
createWatcher(vm, key, handler[i])
}
} else {
createWatcher(vm, key, handler)
}
}
} function createWatcher (vm: Component, key: string, handler: any) {
let options
if (isPlainObject(handler)) {
options = handler
handler = handler.handler
}
if (typeof handler === 'string') {
handler = vm[handler]
}
vm.$watch(key, handler, options)
} export function stateMixin (Vue: Class<Component>) {
// flow somehow has problems with directly declared definition object
// when using Object.defineProperty, so we have to procedurally build up
// the object here.
const dataDef = {}
dataDef.get = function () { return this._data }
const propsDef = {}
propsDef.get = function () { return this._props }
if (process.env.NODE_ENV !== 'production') {
dataDef.set = function (newData: Object) {
warn(
'Avoid replacing instance root $data. ' +
'Use nested data properties instead.',
this
)
}
propsDef.set = function () {
warn(`$props is readonly.`, this)
}
}
Object.defineProperty(Vue.prototype, '$data', dataDef)
Object.defineProperty(Vue.prototype, '$props', propsDef) Vue.prototype.$set = set
Vue.prototype.$delete = del Vue.prototype.$watch = function (
expOrFn: string | Function,
cb: Function,
options?: Object
): Function {
const vm: Component = this
options = options || {}
options.user = true
const watcher = new Watcher(vm, expOrFn, cb, options)
if (options.immediate) {
cb.call(vm, watcher.value)
}
return function unwatchFn () {
watcher.teardown()
}
}
}
vue.js 源代码学习笔记 ----- instance state的更多相关文章
- vue.js 源代码学习笔记 ----- instance render
/* @flow */ import { warn, nextTick, toNumber, _toString, looseEqual, emptyObject, handleError, loos ...
- vue.js 源代码学习笔记 ----- instance init
/* @flow */ import config from '../config' import { initProxy } from './proxy' import { initState } ...
- vue.js 源代码学习笔记 ----- instance index
import { initMixin } from './init' import { stateMixin } from './state' import { renderMixin } from ...
- vue.js 源代码学习笔记 ----- instance event
/* @flow */ import { updateListeners } from '../vdom/helpers/index' import { toArray, tip, hyphenate ...
- vue.js 源代码学习笔记 ----- instance proxy
/* not type checking this file because flow doesn't play well with Proxy */ import config from 'core ...
- vue.js 源代码学习笔记 ----- instance inject
/* @flow */ import { hasSymbol } from 'core/util/env' import { warn } from '../util/index' import { ...
- vue.js 源代码学习笔记 ----- 工具方法 env
/* @flow */ /* globals MutationObserver */ import { noop } from 'shared/util' // can we use __proto_ ...
- vue.js 源代码学习笔记 ----- html-parse.js
/** * Not type-checking this file because it's mostly vendor code. */ /*! * HTML Parser By John Resi ...
- vue.js 源代码学习笔记 ----- core lifecycle
/* @flow */ import config from '../config' import Watcher from '../observer/watcher' import { mark, ...
随机推荐
- SqlMapConfig.xml配置
总结自:https://blog.csdn.net/d582693456/article/details/79886780 SqlMapConfig.xml是mybatis的核心配置 properti ...
- 20145324 《Java程序设计》第8周学习总结
20145324 <Java程序设计>第8周学习总结 教材学习内容总结 第十四章 1.NIO使用频道来衔接数据节点,可以设定缓冲区容量,在缓冲区中对感兴趣的数据区块进行标记,提供clear ...
- 【读书笔记】《深入浅出nodejs》第四章 异步编程
1. 异步编程的基础 -- 函数式编程 (1)高阶函数 -- 是可以把函数作为参数,或是将函数作为返回值的函数. (2)偏函数用法 -- 创建一个调用另外一个部分 -- 参数或变量已经预置的函数 -- ...
- 可扩展多线程异步Socket服务器框架EMTASS 2.0 (转自:http://blog.csdn.net/hulihui)
可扩展多线程异步Socket服务器框架EMTASS 2.0 (转自:http://blog.csdn.net/hulihui) 0 前言 >>[前言].[第1节].[第2节].[第3节]. ...
- bzoj 3450: Tyvj1952 Easy
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 411 Solved: 309[Submit][Status][Discuss] Descriptio ...
- 【前端】jQuery选择器$()的实现原理
今天三七互娱技术面试的时候面试官问了我这个问题,当时一脸懵逼,于是好好总结一下. 当我们使用jquery选择器的时候,$(s).回默认去执行jquery内部封装好的一个init的构造函数每次申明一个j ...
- 关于Java -cp引用jar是否支持通配符
其实是支持的: JDK6支持java -cp后面跟通配符'*',试了一下发现还是需要注意: 错误方式(Wrong way): java -cp /data/apps/lib/*.jar com.ch ...
- LeetCode——Range Sum Query - Immutable
Question Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), ...
- hdu5616 暴力枚举
2017-08-25 20:08:54 writer:pprp 题目简述: • HDU 5616• n个砝码,可以放在天平左右两侧或不放• m次询问,每次询问是否可以测出给定重量• 1 ≤ n ≤ 2 ...
- sql server 跨数据库调用存储过程
A库存储过程: create PROCEDURE [dbo].[spAAAForTest] ( ) =null , ) =null ) AS BEGIN select N'A' AS a , N'B' ...