I would like to be able to expose a function-scoped variable that is part of a website's (not mine) javascript.
Here's a simplified example:
function addHooks(e, t, n, i) {
var props = { // Would like to expose this
update: function() { ... },
remove: function() { ... },
find: function() { ... },
};
...
}
In the above example, I would like to expose the props variable so that my webextension can then access this to modify the behavior of the website. Please note, that the website that serves this JS file isn't under my control and thus, I cannot simply modify the source file to export this variable. However, I'm fully open to modifying the final code that the browser runs (I just don't know how to). The javascript file containing the addHooks function appears to be added dynamically via XHR.
Although I have no idea on how to accomplish this programmatically, I have had some success setting a breakpoint and then issuing window.siteController = props in the browser's developer console. Unfortunately, manual user-intervention is not something I can package and distribute.
One method that I have been toying with is the idea of making an AJAX request for the JS file, modifying its script contents and appending it to the page.
Is there a canonical, programmatic way in which a function-scoped variable can be exposed?
if it's the props object variable that you want exposed, you could return he entire object from the functin, like in closures.
Or , you could, simple declare a the enclosing function as a constructor function, set props as this.props and then, invoke the same function elsewhere, using the new keyword.
Let me know if this helps
EDIT:
Thanks to Makyen who pointed out my error.
Apparently you might be able to do it if you re-define the function in a page script and insert it as a script element. (See the comment for two references).
Just be sure that your <script> element is inserted after the original definition and then you can either return props at the end of the function, or use this.props and use the function either as a constructor or using thecallfunction, passing an object that will get the props property added.
Old answer ( __ wrong__ apparently)
Short answer: you can't.
Full explanation: if you can't change the code of the function and you can only use the function (call it) you cannot alter its variable's scope (and good thing you can't, too. There's a reason why the variable was limited to its current scope).
And you can't change the website's JavaScript. As a Firefox or Chrome extension (and possibly the same fires to other browsers I'm not sure) you can't even access the function (let alone it's inner variables). I mean to say you can't even call it from the extension of it's in the website's code.
content scripts cannot see JavaScript variables defined by page scripts
More info and source
Firefox/Chrome runs your JavaScript code in a parallel environment, isolated from the website's environment. This is of course for security reasons. It also helps for you to be able to develop without knowing the exact inner workings of each website your code might be injected into, as you don't need to bother regarding naming conflicts (which would be impossible if it weren't for the separation environments).
The only thing you do have access to is the DOM, through which you can gather information, alter the website and even talk with the website in some cases (the website should follow a protocol you decide upon as well).
Related
I realised that I don't know how variables are injected into JavaScript in HTML.
I would like to test overriding a clickTag variable which is simply a var in the main body of a JavaScript ( a default value ), but to override it with the injected variable.
Something like this >
somewhere.com/index.html?{"clickTag":"http://www.something.com"}
What's the best way to do that ?
Pretty basic, but I've been used to having the DoubleClick Enabler handling that for me and I have not thought about how the data actually gets in, and how I could test it.
( for a basic php file, passing variables the simplest way, it would be work.php?play=good&balance=true etc but I'm not finding a question here for what I have asked )
Please also correct my terminology if it is bad or misleading. Thanks.
Variables aren't injected into JavaScript.
A JavaScript program defines variables. It might get values to assign to them by accessing APIs (such as location in a web browser which would give you details of the URL of the page).
If you want to override the value of a variable in an existing program then you would need to change the source code of that program to write a new value to that variable between the point where it would normally be assigned and the point where it gets read back and used.
I'm a habit driven creature, and console.log/console.error/etc happens to be the thing I just instinctively use to print things out. However, I'm trying to drive all my logging in node to 'winston'. I'd prefer to do something like var console = require('./modules/logger'); at the top of my file and then just use console.whatever as usual.. tapping into extra arguments as necessary (otherwise the api is pretty much the same). Since this is localized to the file I'm working with and not some sort of global change, is there any danger in setting 'console' to that module's export? And not just "well, it might be confusing for someone else".
I did notice this question pop up as a similar question, but it doesn't really answer whether there's a danger behind it. And there's some other questions that ask if you can override some of node's core, but I'm not doing that - I'm just making a local reference using the same name as a "magic" global.
Other than possibly overriding existing console functions in a non-standard (i.e. unexpected) way, I do not see any danger in replacing the global console with your own object as long as it provides all the expected functions and calling conventions (function signatures) as the default console. I've done it many times without issue.
If you do provide some non-standard implementation of an existing function on the global console with a different signature than other code expects, you're bound to run into problems.
If you do your replacement in a module or function scope, only references in that scope would be affected.
My question basically refers to this example:
https://github.com/vlandham/vlandham.github.com/blob/master/vis/gates/coffee/vis.coffee
At the end of this script (on line 202) it calls the (view_type) parameter from the front end and based on the view type ('year' or 'all') renders the exact method. I need to implement the a similar strategy, but within the show_details() method of this script (on line 176)..What I precisely need is to retrieve the view_type in the show_details() method and based on the view type ('year' or 'all') decide what the content variable (in show_details() method) should display..any ideas or help will be really helpful. Thank you.
So cofeescript automatically inserts local var statements for any variable referenced inside a function (precisely to prevent global leakage that JavaScript causes by default). This means you have to explicitly pollute some global namespace which in a browser would be the window object. Nothing in CofeeScript will prevent you from assigning a field of your choice with what ever value you need and reading it back any time you need. Note that this is messy and prevented for a reason (its hard to keep this kind of code clean, also there is no window object in a server side envrionment like node.js), but it will work.
Looking at this JS code by David Fowler he wraps every "class" with an anonymous self executing method where he sends in jQuery and window. I get that this is a way for ensuring that $ and window are actually the global jQuery and winndow variables you'd expect them to be.
But isn't this a bit over-protective? Should you protect yourself from someone else changing the $ and window variable - is there actually code that does that, and if so why? Also, are there other advantages to wrapping everything like this?
If I remember correctly there are some other libraries than jQuery using the $.
The concept of using function context to create local / function scopes is all about to protect your own code. This especially makes sense if you expect your Javascript code to run in an environment where multiple other (maybe even unknown) scripts may get loaded.
So, if some other Javascript code which got load before your own, assigns window.$ with some other value (it might load the prototype framework for instance), then your code is already screwed if you try to access jQuery specific things.
Another point there is the "a--hole"-effect. Someone creates a line like
window.undefined = true;
...
Now, all your checks against undefined will pretty much fail. But by explicitly creating those variables/parameters and filling them with the values you expect, you can avoid all those problems.
(function(win, doc, $, undef) {
}(window, window.document, jQuery));
Generally most top-level JavaScript code should be wrapped in an IIFE, whether they pass in particular variables or not. This prevents variables created with var from polluting the global scope.
Another small benefit is minification: if you minify your code, making window into a "local variable" by passing it in as a parameter allows the minifier to rename it. This benefit goes away if you gzip, however, so it's not a real win.
Mostly people just pick a pattern for their IIFEs and stick with it, so in his case he's decided this is they way he writes his .js files and he does so uniformly. Having a uniform standard is valuable in and of itself.
To clarify, the code can be written in slightly longer form with
(function () {
var $ = jQuery;
var window = window;
// ...
}());
The code inside the anonymous function is the the function scope, so it prevent confliction with the global variables.
Imaging that if every jQuery plugin is not wrapped in a anonymous function, then there will be a global variables hell.
It's just to preserver integrity.
$ can be Prototype, so sending jQuery as argument will save your code if someone else add a library/variable which overwrite $.
About the second argument "window", I see it as a module you want to write on.
I have a page that could contain a different inner page at any specific time.
Each inner page needs a specific js file, that is being loaded dynamically using the Headjs.
To avoid collisions (of methods and object names), I would like to unload the old js file before loading a new one.
Does anyone know how to do it, or if it is even possible? Thanks!
No. Theoretically there's nothing like "unload" javascript file. Once its loaded its there all the time.
But there might be other tricks to avoid "collision", mainly clean code. some examples for your case would be
1- Usage of namespaces
2- avoid global variables
3- define everything within a scope and understand scopes
4- Use understandable descriptive variable names, avoid variables named s,i,j, etc.. unless you are used to that and know what're doing. Also be aware since javascript files are loaded when a page is requested, so it causes extra traffic to use huge large names for variables and classes.
Lets say you have functions with same name but live in different scopes/namespace
Example:
var myclass;
if (something) myclass = Obj1;
else if (somethingelse) myclass = Obj2;
myclass.func();
so here you go, two functions with the same name, but live in different classes.and so you can switch between different implementations
Hope this helps