@@ -78,28 +78,120 @@ class p5 {
78
78
this . _updateWindowSize ( ) ;
79
79
80
80
const bindGlobal = property => {
81
- Object . defineProperty ( window , property , {
82
- configurable : true ,
83
- enumerable : true ,
84
- get : ( ) => {
85
- if ( typeof this [ property ] === 'function' ) {
86
- return this [ property ] . bind ( this ) ;
87
- } else {
88
- return this [ property ] ;
89
- }
90
- } ,
91
- set : newValue => {
81
+ if ( property === 'constructor' ) return ;
82
+
83
+ // Common setter for all property types
84
+ const createSetter = ( ) => newValue => {
85
+ Object . defineProperty ( window , property , {
86
+ configurable : true ,
87
+ enumerable : true ,
88
+ value : newValue ,
89
+ writable : true
90
+ } ) ;
91
+ if ( ! p5 . disableFriendlyErrors ) {
92
+ console . log ( `You just changed the value of "${ property } ", which was a p5 global value. This could cause problems later if you're not careful.` ) ;
93
+ }
94
+ } ;
95
+
96
+ // Check if this property has a getter on the instance or prototype
97
+ const instanceDescriptor = Object . getOwnPropertyDescriptor ( this , property ) ;
98
+ const prototypeDescriptor = Object . getOwnPropertyDescriptor ( p5 . prototype , property ) ;
99
+ const hasGetter = ( instanceDescriptor && instanceDescriptor . get ) ||
100
+ ( prototypeDescriptor && prototypeDescriptor . get ) ;
101
+
102
+ // Only check if it's a function if it doesn't have a getter
103
+ // to avoid actually evaluating getters before things like the
104
+ // renderer are fully constructed
105
+ let isPrototypeFunction = false ;
106
+ let isConstant = false ;
107
+ let constantValue ;
108
+
109
+ if ( ! hasGetter ) {
110
+ const prototypeValue = p5 . prototype [ property ] ;
111
+ isPrototypeFunction = typeof prototypeValue === 'function' ;
112
+
113
+ // Check if this is a true constant from the constants module
114
+ if ( ! isPrototypeFunction && constants [ property ] !== undefined ) {
115
+ isConstant = true ;
116
+ constantValue = prototypeValue ;
117
+ }
118
+ }
119
+
120
+ if ( isPrototypeFunction ) {
121
+ // For regular functions, cache the bound function
122
+ const boundFunction = p5 . prototype [ property ] . bind ( this ) ;
123
+ if ( p5 . disableFriendlyErrors ) {
92
124
Object . defineProperty ( window , property , {
93
125
configurable : true ,
94
126
enumerable : true ,
95
- value : newValue ,
96
- writable : true
127
+ value : boundFunction ,
128
+ } ) ;
129
+ } else {
130
+ Object . defineProperty ( window , property , {
131
+ configurable : true ,
132
+ enumerable : true ,
133
+ get ( ) {
134
+ return boundFunction ;
135
+ } ,
136
+ set : createSetter ( )
97
137
} ) ;
98
- if ( ! p5 . disableFriendlyErrors ) {
99
- console . log ( `You just changed the value of "${ property } ", which was a p5 global value. This could cause problems later if you're not careful.` ) ;
100
- }
101
138
}
102
- } ) ;
139
+ } else if ( isConstant ) {
140
+ // For constants, cache the value directly
141
+ if ( p5 . disableFriendlyErrors ) {
142
+ Object . defineProperty ( window , property , {
143
+ configurable : true ,
144
+ enumerable : true ,
145
+ value : constantValue ,
146
+ } ) ;
147
+ } else {
148
+ Object . defineProperty ( window , property , {
149
+ configurable : true ,
150
+ enumerable : true ,
151
+ get ( ) {
152
+ return constantValue ;
153
+ } ,
154
+ set : createSetter ( )
155
+ } ) ;
156
+ }
157
+ } else if ( hasGetter || ! isPrototypeFunction ) {
158
+ // For properties with getters or non-function properties, use lazy optimization
159
+ // On first access, determine the type and optimize subsequent accesses
160
+ let lastFunction = null ;
161
+ let boundFunction = null ;
162
+ let isFunction = null ; // null = unknown, true = function, false = not function
163
+
164
+ Object . defineProperty ( window , property , {
165
+ configurable : true ,
166
+ enumerable : true ,
167
+ get : ( ) => {
168
+ const currentValue = this [ property ] ;
169
+
170
+ if ( isFunction === null ) {
171
+ // First access - determine type and optimize
172
+ isFunction = typeof currentValue === 'function' ;
173
+ if ( isFunction ) {
174
+ lastFunction = currentValue ;
175
+ boundFunction = currentValue . bind ( this ) ;
176
+ return boundFunction ;
177
+ } else {
178
+ return currentValue ;
179
+ }
180
+ } else if ( isFunction ) {
181
+ // Optimized function path - only rebind if function changed
182
+ if ( currentValue !== lastFunction ) {
183
+ lastFunction = currentValue ;
184
+ boundFunction = currentValue . bind ( this ) ;
185
+ }
186
+ return boundFunction ;
187
+ } else {
188
+ // Optimized non-function path
189
+ return currentValue ;
190
+ }
191
+ } ,
192
+ set : createSetter ( )
193
+ } ) ;
194
+ }
103
195
} ;
104
196
// If the user has created a global setup or draw function,
105
197
// assume "global" mode and make everything global (i.e. on the window)
0 commit comments