I'm setting a script in my HTML for a geoplugin, assigning the results to the window, and trying to access the variables in a component. The issue is, in the component, I can console.log(window) and see the variables, but any dot notation results in undefined.
Here's the script in my HTML:
<script type="text/javascript">
setupGeo = (o) => {
//This is one way I've tried it, setting a Geo object
window.Geo = {};
Geo.geoplugin_city = o.city;
Geo.geoplugin_region = o.region;
console.log(Geo.geoplugin_city); //works and returns my city
console.log(Geo.geoplugin_region); //works and return my state
//This is a second way I've tried it, assigning it to a function that
//returns the variable
window.geoplugin_latitude = function() { return o.lat; };
window.geoplugin_longitude = function() { return o.lon; };
console.log(window.geoplugin_longitude); //returns function
console.log(window.geoplugin_longitude); //return function
}
</script>
<script type="text/javascript" src="//extreme-ip-lookup.com/json/?
callback=setupGeo" async></script>
As you can see, the script is working as intended. I tried two different ways to and included them both as examples.
In my React component, I am using a ComponentDidMount method to retrieve the values and will eventually set them to state.
Here's the problem: I can console window and see all values, but when I try to dot notation in I get undefined.
componentDidMount() {
console.log('componentmounted', window)
// Window ...{Geo:{geoplugin_city: "MyCity", geoplugin_region: "MyState"}}
// ...geoplugin_latitude: f() ... geoplugin_longitude: f()
console.log('componentmounted', window.Geo) // undefined
console.log('componentmounted', window.geoplugin_latitude) //returns
//function
console.log('componentmounted', window.geoplugin_latitude()) //gives error
//that window.geoplugin_latitude isn't a function
}
So, I can see the window variables I need, I just get access them inside the Window object. I've done research on how to use the Window Object, but that isn't the issue since I can see the variables in the Window Object. They just become undefined when I try to get to them for use. I've also tried with ComponentWillMount and even UNSAFE_componentWillMount(), but those aren't the issue since I'm retrieving the variables in Window.
Any ideas on how React works that is making this an issue, and how I can go into the Window to get the variables?
Related
On a live website, I've previously changed console.log to be:
var console = {};
console.log = function () {};
With this code always executing, is it possible to reinstate the console functionality after this code, and if so, how?
It's needed, since the site is live. But I need to do further development, without making any updates to the live site. It's hard without console logging/information.
If that code is not running on the top level, because console is on window, you can just reference window.console.log, eg:
(() => {
var console = {};
console.log = window.console.log;
console.log('foo');
// or, just reference window:
window.console.log('bar');
})();
If the code is running on the top level and you're using const or let (rather than ES5 var), you can do the same thing:
const console = {};
console.log = window.console.log;
console.log('foo');
Otherwise, you'll have to save a reference to console.log before you reassign console with var:
var log = console.log;
var console = {};
console.log = log;
log('foo');
But it's probably not a great idea to create/overwrite built-in global variables like that unless absolutely necessary - the IIFE in the first snippet is probably preferable.
I know this is 1 year and 8 months old by the time I write this, but I happened to figure out a good workaround solution.
You can set a global variable that will get the window.console object when the website loads and another global variable called "console" to get the old console state whenever you want.
var oldConsole = window.console;
var console = {};
So when you need to reset the console to its normal functionality, you simply do:
console = oldConsole.log; // since it's 'window.console.log'
console.log('Hello, world!'); // this output will now display on devtools with its default configuration
My previous colleague rewrite window.print method:
function print(data){
var window_print = window.open('', 'my div', 'height=768, width=1024');
window_print.document.write('<!DOCTYPE html><html><head><title>Печать</title></head><body>' + data + '</body></html>');
window_print.print();
window_print.close();
}
My intention was to use default behavior of that function: just print current page, and I added:
if(data) {....} else { window.print() }
And of course I received error: "too much recursion: window.print();"
My question is how to invoke default behavior window.print()?
Edit: Ok, it appears that print is an own property of window in some browsers, and isn't in others. Therefore, just cache the value of window.print:
var printWindow = window.print;
// define your new print function here
var print = function(data) { ... };
// then later:
printWindow.call(window);
NB: If you're doing all this in the global scope, then you'll need to define the new print using a function expression (var print = ...) rather than a function declaration (function print(data) { ... }) because function declarations get hoisted to the top of their scope, and therefore the print redefinition would happen before you had chance to cache it. If you're not doing it in the global scope, then it doesn't matter as the new print won't override window.print regardless of how it's defined.
Original:
Try:
Object.getPrototypeOf(window).print.call(window);
print doesn't appear to be an own property of window, meaning that the newly defined print merely shadows something further up the prototype chain. You can bypass this shadowing by moving up the prototype chain using Object.getPrototypeOf.
You'll also need to use call so that the print method receives the correct value for this.
You need to store the original print method as another property in the window, just before the definition of your own print().
EDIT: You also need to define the new print function specifically as window.print = function(){...} rather than function print(){...} in order to be able to access the original - see answers with nice links here and here. This won't have any impact on how you call the method.
window.originalPrint = window.print;
window.print = function(data)
{
if(data)
{
document.getElementById('foo').innerHTML = data;
}
else
{
window.originalPrint();
}
}
<div id="foo"></div>
<button onclick="window.print('hello')">print('hello')</button>
<button onclick="window.print()">print()</button>
I am trying to subclass native window object, but when I do so none of the window methods are callable in child class.
Here is an example below:
<script type="application/javascript" >
function baseWindow () {
}
baseWindow.prototype = window;
var mywindow = new baseWindow();
window.alert('works'); // works of course
alert(window.document); // accessing property of course works
mywindow.alert('doesn\'t work'); // alert doesn't work in subclass error: TypeError: Illegal invocation
mywindow.__proto__.alert('works') // accessing it directly via __proto__ works
alert(mywindow.document); // accessing document property works
</script>
Can someone explain why that doesn't work and if there is workaround ?
Thanks
As you figured out already, some properties of window are inherited properly, while others are not. Those that are not are methods that expect the object they are invoked on to be window which is obviously not the case in your example. By "expect" i mean they throw an error if the expectation is not met.
What you can do to avoid it is override those particular functions, perhaps by using the original functions somehow (depending on what you want to do with them).
function MyWindow(){
this.alert = window.alert.bind(window); // override it to work!
}
MyWindow.prototype = window;
var mine = new MyWindow();
mine.alert(mine.location);
If you want many instances of Window and a single alert function shared between them and you don't want to alter window.alert, you need to add another object that inherits from window as prototype for Window:
function MyWindow() {
}
MyWindow.prototype = Object.create(window);
MyWindow.prototype.alert = window.alert.bind(window);
var mine = new MyWindow();
mine.alert(mine.location);
I am trying to subclass native window object,
You cant.
Why? because window is not a function, and you cant call Window constructor.
Why? because the DOM is built that way.
function baseWindow () {
}
baseWindow.prototype = window
it's not even proper prototypal inheritance.
if Window constructor was callable one could write
function BaseWindow () {
Window.call(this);
}
BaseWindow.prototype = Object.create(Window.prototype)
But you cant do that.
EDIT just to be clear,
window is an instance of Window, they are not the same.
I have a problem. I have defined some global variables and namespaced it into an object called "app".
Example:
window.app : {
foo : null,
bar : null,
}
Well, the idea is that I want to be able to modify those variables from any module by calling app.foo = "baz" or app.bar = "baz", but I don't want the user to be able to modify those variables from the browser console (element inspector).
Is it possible?
PD: Well, I have a Backbone.js collection which is sinchronized with the server. I don't want the user to be able to modify that collection with the console
No. The browser is the user's domain. They have the possibility to modify your scripts and inject their own functionality in various ways (through the console or browser plug-ins). That's one of the reasons why you should never blindly trust user input on the server side.
They could even manually forge a complete request, tricking your server into thinking that your JavaScript code made that request.
If you want these values to be secure, you need to keep them on the server. You can send them to the client, of course, as long as you keep a possibility to validate the values against those on the server.
The only way to make the variables not (easily) modifiable by a user is to remove them from global scope - something like
!function() {
foo = null;
bar = null;
}()
You'll need to redesign the way your modules interact with each other to accomplish this. An MVC Framework like Angular.js will help.
You should never rely on this as a security mechanism, though - the browser is fully in the user's control.
Still for them who are searching solution to this problem, use const modifier while assigning variable instead of var. Now try to change value of variable from browser console. It will throw error Uncaught TypeError: Assignment to constant variable that will prevent your data from being modified.
A possible way to avoid to (easily) modify javascript variables from the browser console is to either use the get operator (ECMAScript 5) or a getter-function.
To make it possible to define "private" variables, an anonymous function defines the variables in the local scope, so that it is not globally available. (as mentioned in joews' answer)
As mentioned before, this does not make it impossible to manipulate the variables.
Via get operator:
window.app = (function () {
var _foo = 123; // private variable
return {
get foo () { return _foo; }
};
}());
// --- accessing app from the console ---
// app.foo is readable from console, but not modifiable
console.log(app.foo);
app.foo = 234;
console.log(app.foo); // 123
// However, app.foo can still be modified via Object.defineProperty or
// removed with the delete operator
Via getter-function (older browsers, e.g IE < 9):
window.app = (function () {
var _foo = 123; // private variable
return {
foo: function() { return _foo; }
};
}());
// --- accessing app from the console ---
console.log(app.foo()); // 123
// However, the foo function can still be overwritten.
// But at least, the internal _foo variable is unaffected.
app.foo = function () { return 234; }
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
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.
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.
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.
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.
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"
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;
})();