How to replace javascript standard built-in objects? - javascript

My client builds their own app based on Chromium, their navigator.appVersion is AppleWebkit/534+
But to my surprise they replace javascript standard built-in objects with their own, for example, check their Map bellow,
Their Map has methods like,
arr:Array[0]
isEmpty:function
remove:function
But no standard Map method like has, keys, values, check here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map (BTW, the reason we need Map here instead of plain js object is we need the key to be something other than string)
I am curious, how did they do that? Why would someone want to do that!!
And more importantly how do I restore the build in version ?

I had the same issue that the global function has been overwritten.
My trick is to use the contentWindow of an iframe to get the original function back:
Here's the code, it doesn't work in code-snippets of StackOverflow due to iframe policy, but it should work with your environment:
// contaminated Map
Map = function() {
this.foo = 'bar';
}
const map1 = new Map();
console.log(map1);
​
// restoring Map
const iframe = document.createElement('iframe');
document.body.append(iframe);
const OriginalMap = iframe.contentWindow.Map;
iframe.remove();
​
const map2 = new OriginalMap();
map2.set('foo', 'bar');
console.log(map2);
Here's the screenshot shows that it works:
This is more like a workaround, not sure if there's a better way to do it.

how did they do that?
It's as simple as:
Map = function() { ... }
Why would someone want to do that!!
As other comments have guessed, probably because the code is older than the availability of built-in Map. If the same code is also supposed to run on older browsers, then this consideration might still be relevant.
how do I restore the build in version ?
The suggestion in the other answer is an interesting idea... I can't think of a better way.
That said: I'm guessing your task is to make extensions/modifications to an existing codebase. Having two different Maps in the same codebase sounds pretty confusing -- for anyone working on this code after you (which may be yourself, in a couple of months), it'll be pretty hard to understand what's going on. So I offer another suggestion: don't just locally get the built-in Map, and instead pick either of:
modernize the whole system to use built-in JavaScript Maps. Replace all uses of the handcrafted Map, and then delete that definition. Use built-in Map everywhere. (Check with your client though whether they are okay with you spending your time on this.)
stick with what's there, and use the handcrafted Map in your new code as well. While its functions have different names, it seems that all the important features are there. You can probably find an example of how to iterate over such a map. (This would still leave the above alternative as a future option.)

Related

Instantiating a class dynamically from a string

Good afternoon fellow developers,
I am currently trying to develop a function that instantiates business objects dynamically based on the value of the string it receives as a parameter. I know this can be done in JavaScript as I have done it before and, just to be sure, I even tested it again in Visual Studio Code after having encountered this issue in my SAPUI5 app. My function's code looks somewhat like this:
createObject: function (sObject) {
var newObject = new this[sObject]();
// var newObject = new [sObject](); I also tried this way.
};
For the sake of testing this function, the sObject string currently contains the hardcoded value "Order" and I am importing my Order.js object into the file where i'm trying to instantiate this objects dynamically. No matter what I try I keep getting this error when debugging my code:
TypeError: this[sObject] is not a constructor
I was wondering if some of you might have tried something similar before and might be able to point me in the right direction. Even if there are ways for me to work around this issue, it would be really nice if I learnt how to do this dynamically since I was planning on using this approach on several different scenarios. I look forward to reading from you!
It is a really unsafe practice to instantiate objects from a string and an ATROCIOUS one to do it from a parameter a user can supply. If you have a limited set of objects its much safer to have a big switch statement.
switch(name) {
"objA": return new ObjA();
}

Linq.js Enumerable.from()

I am new to this very very nice Linq.js library that I have just discovered. I am following the examples to write queries like:
Enumerable.from(jsonArray).select(...); // noice
Can I do this shortcut?
jsonArray.select(...); // error as expected
I read the tests in library, seems like pretty much every call starts with Enumerable.someCommand();. I am wondering if the linq commands have been applied to the correct prototypes in js, so I can call them in the style of 2nd line of code. am I not aware of it because I am a newbie?
I am the creator of the open source project http://www.jinqJs.com.
You could simply do jinqJs().from(jsonArray).select();
Let me know if I could be of any more help
If your concern is that Linq.js doesn't extend the Array prototype, I think it's misplaced. It's not exactly a light framework, kinda the same reason why jquery doesn't do the same thing. You shouldn't expect anything to work on just anything.
If you wanted to make bridging that gap a little nicer, it should be safe to add some methods to convert to the other.
if (!Array.prototype.AsEnumerable) { // not likely to be used by others
Array.prototype.AsEnumerable = () => Enumerable.From(this);
}
Then that would allow you to do:
jsonArray.AsEnumerable().Select(...);

Google Maps V3 not loading (Asked & Answered)

This question is already answered. I discovered what the problem is.
But, I'm posting the Q&A here because others may be in the same predicament.
My google map code came from samples I found on the web.
In the "bad" code there was a line that looked like this:
var latlng= new google.maps.LatLng(results[0].geometry.location.Ua, results[0].geometry.location.Va);
This code worked until last night.
Using firebug to inspect the objects, it turns out that location is now of the form: {Ta: number, Ua: number}
My immediate fix was to use the lat() and lng() methods whenever I required the lat and/or lng.
The other fix was to instantiate my map in a more intelligent fashion.
Yes, it was silly rely upon properties uncovered deep in an object using the firebug inspector. Yes, being a google maps noob and relying on copy paste with little or no knowledge reaped its just rewards.
But, doing a quick google seach found many folks (other than the "sample" I borrowed from) also using the .Va property directly.
Hence the post here in case this is their problem too.
In case you're interested in why this happened, it's simple: the sample was using undocumented internals of the API, so when Google updated the Maps JS file, it broke.
More specifically, Ua and Va were auto-generated variable names resulting from minification. It looks like Google removed a variable in the original source and the labels shifted up (Ua,Va → Ta,Ua).
I'll bet I know exactly how the author of the bad sample came up with his code. He inspected a LatLng (the type of object in location in your example) in his browser's dev tools, saw that those two oddly-named variables contained the data he wanted, and just went with it. Since the lat and lng methods are "hidden" in LatLng's prototype, he didn't notice them.
There are two lessons to be learned here:
Always use documented API methods; anything else is an implementation detail that is subject to change.
Don't trust the code on some dude's website is a good or even competent example of how to do things. This is especially true in the case of Google Maps, where there's extensive documentation and official examples.

Does "go to definition" work in Eclipse for javascript?

Working with Eclipse for Javascript, Ctrl-click seems to work on some objects but will not take me outside of the current javascript file. Is there any way to get this "go to definition" to work more fully? I use Eclipse for Java and depend on this functionality, would like to see it work better in Javascript as I'm just trying to learn Javascript.
I think it probably doesn't work because of the many ways in JavaScript to define something..
function foo() {}
var foo = function() {};
window.foo = function() {};
window['foo'] = function() {};
var z = 'foobar'; window[z.substr(0, 3)] = function() {};
Especially the last one would be - even though it's unlikely to be ever used in real code - pretty much impossible to be detected by an IDE without executing the whole code and then tracking where a global is defined for the first time.
Another example would be with libraries implementing a class system. Without knowing the details of every library it's pretty hard to find out what class names they define.
Intellij Idea support that functionality. I was looking to see if Eclipse has a plugin and came across your post, I use to work with Intellij Idea and I have that functionality that is very helpful so to the user that is saying that is impossible for a IDEA please take a look in Intellij Idea you will be surprise of all the functionality that you can find.

Dynamic proxies in javascript?

I can proxy a single function in javascript by doing something like this (just jotted down from memory so bear with me)
function addAroundAdvice(target){
var targetFunction = target.aFunction;
target.aFunction = new function(){
invokePreCall();
targetFunction.apply(target, arguments);
invokePostCall();
}
}
Being a java programmer I'd think of this as a dynamic proxy. Every time I write code like this I think that someone must have made a really smart library that does the common proxying operations that is at least 10% better than what I can do in a hurry. I'd be expecting some stuff like correctly intercepting all methods for any given object, which may not be entirely trivial. Then there's different types of advice. So while I'm not expecting something the size of scriptaculous, it's certainly more than 6 lines of code.
So where are these libraries ?
Try jQuery AOP plugin
Looking at the source it seems that only uses jQuery as a namespace, so you could try this plugin even if don't want to use jQuery.
The Dojo Toolkit has a lot of support for AOP constructs like this:
Eugene Lazutkin's Blog Post on Aspect Oriented Programming with Dojo
The fact that you have been able to do it I would think means that there is a library to achieve it in the form of pure JavaScript i.e. your above example. Design Patterns can be applied to JavaScript as you know, so I think the advice I would provide to you is the following by a Google and Yahoo GUI developer :
http://jsdesignpatterns.com/
Chapter 14: The Proxy Pattern. Reference there solution to yours. You may still prefer your approach or you may find tips from their approach.
Cheers,
Andrew
I don't think you can intercept all functions.
The best you can do is iterate over all elements of an object and look for any functions:
for elem in someObject {
if typeof(elem) == "function" {
// replace the function
}
}
Trouble is, that if you add a function later it's not routed through the proxy.

Categories

Resources