A friend asked me the other day how would I determine where a string lay within a JavaScript Array. I of course answered – “it depends! If you are using newer IE or a non-crappy implementation of the JavaScript engine then use Array.indexOf – it has been around for years…..”
var arr = ["simon", "marky", "david"] return arr.indexOf("marky") // 1.0
Well – turns out the friend was asking about SSJS in XPages and it turns out that apparently XPages has one of those crappy JavaScript engines of which I spoke and Array.indexOf is not supported (facepalm). (*really??*)
<xp:text escape="true" id="computedField1"> <xp:this.value><![CDATA[#{javascript: var arr = ["simon", "marky", "david"] return arr.indexOf("marky") }]]></xp:this.value> </xp:text>
Polyfill
OK so there is a simple polyfill for the indexOf, which has also been around for years as this article written in 2007 demonstrates…..
if(!Array.indexOf){ Array.prototype.indexOf = function(obj){ for(var i=0; i<this.length; i++){ if(this[i]==obj){ return i; } } return -1; } }
And if we add this to our XPages sample code we get the answer we are expecting….
<xp:text escape="true" id="computedField1"> <xp:this.value><![CDATA[#{javascript: if(!Array.indexOf){ Array.prototype.indexOf = function(obj){ for(var i=0; i<this.length; i++){ if(this[i]==obj){ return i; } } return -1; } } var arr = ["simon", "marky", "david"] return arr.indexOf("marky") }]]></xp:this.value> </xp:text>
Yay !
Prototyping in JavaScript
For a better explanation that I can give, check out this StackOverflow answer on what is prototyping – suffice to say that every JavaScript object has a prototype property and this is the basis for prototypal (as opposed to class based) inheritance in the JavaScript language.
What we did in the polyfill above is: we simply said if Array.indexOf method does not exist, then we created one.
So what does this have to do with XPages?
In JavaScript when you prototype a function, the scope is on the page you are looking at. As soon as you leave the page the prototype is gone. In XPages it seems to be a little broader than that…..
I (unintentionally) discovered that once you prototype the Array.indexOf, not only does it become available on the same page, it is permanently on the same page. You run the prototype code once….then take it away, and it still works. The scope would appear to be at the application level…..
Well so then I asked some people who are way smarter than I and Nathan Freeman pointed me to his article about XPages Performance Pro Tips and told me he expected that the prototype would actually be at the server level and he was right….
I included the URL of the test database in the picture above to demonstrate that when I move the simple code to another database – it still works (after the prototype code has been run once)
And just to be sure – in another browser !!
Once the Array.prototype.indexOf was created, it became available in all applications on the server, instantly.
Killing the prototype
- Restarting HTTP *DOES NOT* stop this.
- Killing all browsers and starting again does not stop this
As far as I can tell you have modified the way the SSJS works on the server until you kill it. So far I have run a test over 24 hours later and it is still working……
This is COOL right?
Well for one it means that you can seriously enhance all your JavaScript on the server in ways which make custom libraries look like a waste of time. We could truly add all the corporate libraries to SSJS once when the server loads and they would always be available to all developers at all times.
And the even more awesome (depending on perspective…..)
Well yeah but…….
You can also serious screw up perfectly good code across the server
Conclusion
Prototypal inheritance is at the root of JavaScript programming language and is very powerful. What we can see here though is that we are able to affect code across the entire server with a few lines of code. This is *very* cool and *very scary* at the same time.
So with this knowledge comes great responsibility – use it at your own risk and make sure you have very good server side code review if you are going to go down this path.