8

I try to load some external .js files, and have some irresolvable namespace conflicts.

I had the idea of loading some of the files in their own context somehow, replacing the "this" from pointing at the window object to some custom namespace.

example:

first.js:

name = "first";

second.js:

name = "second";

It seems to me that this kind of trick can be very useful. Is it possible at all?

EDIT
seems that replacing "this" does not begin to solve the problem, as it is not the default context for identifier resolution in javascript. this is my test code:

var first = {};
var second = {};

(function(){name = "first";}).call(first);
(function(){name = "second";}).call(second);


document.write('name= '+name+' <br/>\n'); //prints "second"
document.write('first.name= '+first.name+' <br/>\n'); //prints "undefined"
document.write('second.name= '+second.name+' <br/>\n'); //prints "undefined

any ideas?

RESOLUTION
It is not possible. I ended up wiser than I was this morning, and I gave it up. I recommend these enlightening reading materials for anyone with a similar problem that might want to take a crack at it: http://jibbering.com/faq/notes/closures/
http://softwareas.com/cross-domain-communication-with-iframes

6 Answers 6

4

One idea I've had for doing it without needing modifications to your external JavaScript file is getting the contents of the JavaScript file in an AJAXy way (up to you how you do that) and then put it all in a function using the new Function(code) way, then initialise that with new:

surrogateWindow = new new Function(jsCode)();

Then surrogateWindow is the this of that code. I think that that idea should work.

Sign up to request clarification or add additional context in comments.

3 Comments

I know its been 9 years but this just saved my life. This works perfectly: var xhttp=new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { surrogate = new new Function(this.responseText)(); } }; xhttp.open("get", url, true); xhttp.send(); Once the async call is done I can reference "surrogate." and my function names and no more clashes.
Coming back to this almost ten years later, I say that on a certain style of code this will work—if it explicitly says this.foo instead of just foo or window.foo. But if not, then it won’t. Not sure why I didn’t specify this when I wrote the answer: I knew it at that time, without a doubt. I’m contemplating whether I neglected to consider it, having recently been fed too much Java. No idea. I don’t care to try to interpret the actions of me of ten years ago. 😀
Always fun looking back on old code :) In my particular case I am loading a 3rd party libraries which uses a very old version of another 3rd party library that I use throughout my code, only I use a newer version. I've changed my code to do this to load the newer version into a surrogate and viola ... Personally I think this is a very neat and novel solution to a problem that comes up way to often.
2

Even though this is an old question, this answer may still be relevant for some:

When a js file is loaded it automatically gets the window's context. That is not possible to change. However, if you are trying to avoid conflicts between libraries that you are loading, and you don't have control over those libs, and they don't have a built-in "no-conflict" mechanism, then there is a nice trick - you can load those into a source-less iframe. This will make their context to be the window of the iframe, and you will still be able to access the iframe since there is no cross-domain issue here.

You can see this library as an example for use of this technique.

1 Comment

Ironically, the original problem was raised when I wanted to manage several JQuery versions :). I did end up doing some IFrame thing if I recall corecctly.
2

I'm not clear on your reason for doing this; what are you using this for, exactly?

Wrapping the contents of your second.js in an anonymous function will prevent variables in that file from conflicting with global variables. If you really must have a this set to a particular object that isn't the global object, you could do something like

var differentThis = {};
(function() {
    // Contents of second.js go here
}).call(differentThis);

UPDATE

You can't do what you want. You seem to want to access the Variable object, which is the object to which a property is added when you declare a variable in JavaScript. In global code, the Variable object is the global object, so you can access it; within a function this is a property of the execution context that there is no way to access directly.

1 Comment

I already tried that, and although the "this" keyword is properly replace, I found out that it is not the default context for identifier resolution.
1

You can load your file in an iframe, the file is not a .js but an HTML file, like:

<html>
<body>
  <script>
    var $ = parent.$, // you can share objects with the parent, eg: jQuery
      localObject = { // your local object definition
        name: 'first',
        showName: function(){
          $('div.name').html( this.name );
        }
      };
    //assign the local object to the custom namespace
    parent.customNamespace.object1 = localObject; 
  </script>
</body>
</html>

The trick is to use parent. to get the javascript objects available in the parent page.

3 Comments

This seems like a dirty but doable solution, but i can't use it for reasons I didn't specify in the original question - my code comes from outside the document's domain and so my IFrame will not be able to access the parent's internal state.
I use it heavily in our app to cleanly separate the 3 codes: HTML, CSS and JS. I found it a not so dirty way of having includes browser side.As you are cross domains, I think the only way is make your server fetch the js files, transform and cache them, wrap them inside a function passing the this as context, and send them to the browser eg: http://yourdomain.com/fetchjs?url=http://otherdomain.com/other.js&namespace=custom.object1 good luck.
Sadly, server side is also not an option. When I wrote "dirty but doable" I was thinking of the priorities I have to answer to - where the extra page load is considered very costly. I agree that code-and-order-wise this is the solution easiest to implement and maintain. Thanks.
1

For the code you've written, I think you're misunderstanding some of the way classes work in JavaScript. In Java you can drop the this., but in JavaScript you can't. You'll always need to have this. there. So then your code becomes:

var first = {};
var second = {};

(function(){this.name = "first";}).call(first);
(function(){this.name = "second";}).call(second);


document.write('name= '+name+' <br/>\n'); //prints "undefined"
document.write('first.name= '+first.name+' <br/>\n'); //prints "first"
document.write('second.name= '+second.name+' <br/>\n'); //prints "second"

It would also be good to do it in a more normal class way. I'm not sure exactly what your situation is as I can't see all your code so you might be already doing it this way.

function Something(name) {
    this.name = name;
}

var first = new Something("first");
var second = new Something("second");

document.write('name= '+name+' <br/>\n'); //prints "undefined"
document.write('first.name= '+first.name+' <br/>\n'); //prints "first"
document.write('second.name= '+second.name+' <br/>\n'); //prints "second"

Comments

-1

Well you could wrap the contents of the js files with something like this:

var externalInterfaceForYourObject = (function(){
  //code that defines your object

  //this should refer to the current anonymous function, and not the window object
  return this;
})();

1 Comment

I tested it and the anonymous function is run under the window context, and return the window object.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.