1
+ import { isObject , isArray , hasOwn , isIntegerKey , hasChanged , isSymbol } from './shared.js'
2
+ import {
3
+ reactive , readonly ,
4
+ toRaw , ReactiveFlags , proxyMap , readonlyMap , shallowReactiveMap , shallowReadonlyMap
5
+ } from './reactive.js'
6
+ import { track , trigger , ITERATE_KEY , pauseTracking , resetTracking } from './effect.js'
7
+
8
+ function createArrayInstrumentations ( ) {
9
+ const instrumentations = { } ;
10
+ [ 'includes' , 'indexOf' , 'lastIndexOf' ] . forEach ( key => {
11
+ instrumentations [ key ] = function ( ...args ) {
12
+ const arr = toRaw ( this ) ;
13
+ for ( let i = 0 , l = this . length ; i < l ; i ++ ) {
14
+ track ( arr , "get" , i + '' ) ;
15
+ }
16
+ const res = arr [ key ] ( ...args ) ;
17
+ if ( res === - 1 || res === false ) {
18
+ return arr [ key ] ( ...args . map ( toRaw ) ) ;
19
+ } else {
20
+ return res ;
21
+ }
22
+ } ;
23
+ } ) ;
24
+
25
+ [ 'push' , 'pop' , 'shift' , 'unshift' , 'splice' ] . forEach ( key => {
26
+ instrumentations [ key ] = function ( ...args ) {
27
+ pauseTracking ( ) ;
28
+ const res = toRaw ( this ) [ key ] . apply ( this , args ) ;
29
+ resetTracking ( ) ;
30
+ return res
31
+ }
32
+ } )
33
+ return instrumentations
34
+ }
35
+
36
+ const arrayInstrumentations = createArrayInstrumentations ( ) ;
37
+
38
+ const get = createGetter ( ) ;
39
+ const set = createSetter ( ) ;
40
+
41
+ const builtInSymbols = new Set (
42
+ Object . getOwnPropertyNames ( Symbol )
43
+ . map ( key => ( Symbol ) [ key ] )
44
+ . filter ( isSymbol )
45
+ )
46
+
47
+ function createGetter ( isReadonly = false , shallow = false ) {
48
+ return function get ( target , key , receiver ) {
49
+ const targetFromMap = ( isReadonly
50
+ ? shallow
51
+ ? shallowReadonlyMap
52
+ : readonlyMap
53
+ : shallow
54
+ ? shallowReactiveMap
55
+ : proxyMap
56
+ ) . get ( target ) ;
57
+
58
+ if ( key === ReactiveFlags . IS_REACTIVE ) {
59
+ return ! isReadonly
60
+ } else if ( key === ReactiveFlags . IS_READONLY ) {
61
+ return isReadonly
62
+ } else if ( key === ReactiveFlags . IS_SHALLOW ) {
63
+ return shallow
64
+ } else if ( key === ReactiveFlags . RAW && targetFromMap ) {
65
+ return target ;
66
+ }
67
+
68
+ const targetIsArray = isArray ( target ) ;
69
+
70
+ if ( ! isReadonly && targetIsArray && hasOwn ( arrayInstrumentations , key ) ) {
71
+ return Reflect . get ( arrayInstrumentations , key , receiver )
72
+ }
73
+
74
+ const res = Reflect . get ( target , key , receiver ) ;
75
+
76
+ if ( isSymbol ( key ) && builtInSymbols . has ( key ) ) {
77
+ return res ;
78
+ }
79
+
80
+ if ( ! isReadonly ) {
81
+ track ( target , key ) ;
82
+ }
83
+
84
+ if ( shallow ) {
85
+ return res
86
+ }
87
+
88
+ if ( isObject ( res ) ) {
89
+ return isReadonly ? readonly ( res ) : reactive ( res ) ;
90
+ }
91
+
92
+ return res ;
93
+ }
94
+ }
95
+
96
+ function createSetter ( ) {
97
+ return function set ( target , key , value , receiver ) {
98
+ let oldValue = target [ key ] ;
99
+ value = toRaw ( value ) ;
100
+ oldValue = toRaw ( oldValue ) ;
101
+
102
+ const hadKey = isArray ( target ) && isIntegerKey ( key )
103
+ ? Number ( key ) < target . length
104
+ : hasOwn ( target , key ) ;
105
+
106
+ const res = Reflect . set ( target , key , value , receiver ) ;
107
+ if ( ! hadKey ) {
108
+ trigger ( target , key , 'add' , value )
109
+ } else if ( hasChanged ( value , oldValue ) ) {
110
+ trigger ( target , key , 'set' , value )
111
+ }
112
+ return res ;
113
+ }
114
+ }
115
+
116
+ function has ( target , key ) {
117
+ const res = Reflect . has ( target , key ) ;
118
+ track ( target , key ) ;
119
+ return res ;
120
+ }
121
+
122
+ function ownKeys ( target ) {
123
+ const key = isArray ( target ) ? 'length' : ITERATE_KEY ;
124
+ track ( target , key ) ;
125
+ return Reflect . ownKeys ( target ) ;
126
+ }
127
+
128
+ function deleteProperty ( target , key ) {
129
+ const hadKey = hasOwn ( target , key ) ;
130
+ const res = Reflect . deleteProperty ( target , key ) ;
131
+ if ( res && hadKey ) {
132
+ trigger ( target , key , 'delete' ) ;
133
+ }
134
+ return res
135
+ }
136
+
137
+
138
+ export const mutableHandlers = {
139
+ get,
140
+ set,
141
+ deleteProperty,
142
+ has,
143
+ ownKeys
144
+ }
145
+
146
+ const readonlyGet = createGetter ( true ) ;
147
+
148
+ export const readonlyHandlers = {
149
+ get : readonlyGet ,
150
+ set ( target , key ) {
151
+ console . warn ( `Set operation on key "${ String ( key ) } " failed: target is readonly.` )
152
+ return true
153
+ } ,
154
+ deleteProperty ( target , key ) {
155
+ console . warn ( `Delete operation on key "${ String ( key ) } " failed: target is readonly.` ) ;
156
+ return true
157
+ }
158
+ }
159
+
160
+ export const shallowReactiveHandlers = Object . assign (
161
+ { } ,
162
+ mutableHandlers ,
163
+ {
164
+ get : createGetter ( false , true ) ,
165
+ set : createSetter ( )
166
+ }
167
+ )
168
+
169
+ export const shallowReadonlyHandlers = Object . assign (
170
+ { } ,
171
+ readonlyHandlers ,
172
+ {
173
+ get : createGetter ( true , true )
174
+ }
175
+ )
0 commit comments