Uglify.js messing things up within if statement - javascript

I have this code
if (!win._hb_bids) {
win._hb_bids = {};
}
win._hb_bids.hb_auction_id = helpers.generateCacheBuster();
if (config.isAmazon) {
translated with Uglify.js to this code
if ((p._hb_bids = p._hb_bids || {}) && (p._hb_bids.hb_auction_id = e.default.generateCacheBuster()), s.isAmazon)
I would assume that this code should be executed from left to right, setting _hb_bids property to an empty object. Instead, what I see in the Chrome debugger, generateCacheBuster() is executed first, and then it tries to make an assignment to p._hb_bids.hb_auction_id, and p._hb_bids is undefined at this moment.
What is the reason for such a strange execution order? And how the code can be rewritten to work correcly after uglify?
UPDATE:
I found the cause of the issue. I had another part of the code doing iframe content refresh, and the win variable was pointing to an iframe window which was destroyed already. That probably caused this weird behaviour. So it wasn't uglify.js problem as I initially thought and stated in the title.

Related

How does render() actually execute?

I'm working on a project and I have created an interesting challenge for myself.
render() {
const sysObjs = this.state.systemObjects;
const jsonPackage = sysObjs[0];
if(typeof jsonPackage === 'undefined'){
console.log("undefined!!!")
} else {
//let jsonData = JSON.parse(jsonPackage.replaceAll("\\\\", "\\"));
console.log(jsonPackage.replaceAll("\\\\", "\\"));
}
console.log(jsonPackage.replaceAll("\\\\", "\\"));
If I run that it will fail and it will fail on the last line of the snippet and it will fail because from the perspective of that line of code jsonPackage is undefined and we get a "cannot read property 'replaceAll' of undefined. That makes sense to me as doing any sort of operation on something that is undefined would fairly difficult. The part that is confusing me though is that if I remove that last line then the code will execute. That's confusing to me because that console.log is also there within the if-else block so I would imagine that both should throw errors but they don't. In fact if I run that after removing the last line I will actually get both sections of the if-else block to log to the console and that tells me that this is executing in a way that I don't understand. Can anyone explain what's happening for me? At the root here something is doing something such that the const jsonPackage is not populated immediately when it is set so I'm curious how react actually handles something like that.
Lastly, I commented out that line because that line throws "Unhandled Rejection(Error) A cross-origin error was thrown." I'm also not too sure what that actually means either as it wasn't covered in the course I took.
render() is called each time your component's state updates. It can also get called in a number of other circumstances, but I think that's the relevant one for this situation.
You're not showing all of your code, but there is probably something running on mount or something similar that updates this.state.systemObjects.
On the first render of the component, this.state.systemObjects is undefined. So, if you have your console.log(jsonPackage.replaceAll("\\\\", "\\")); line in at the end of your render, it will fail because it can't do an operation on undefined. However, with it commented out, it runs fine, because it goes through the if(typeof jsonPackage === 'undefined'){ section of your if clause and not the else clause, where an operation is done on jsonPackage.
Then, once systemObjects is updated, render runs again. On that pass, systemObjects now is not undefined, so the else clause gets run -- since you don't have an undefined value any more, that else clause runs fine.
Your cross-origin error is not caused by any code you've shown -- it's probably caused by an API request somewhere. There are plenty of answers on SO about what can cause those.
I think you answered your own question. This is happening because the first time your code is executing, jsonPackage is not defined. This is why both blocks of your if statement are logging, because during the first pass though it is undefined and during the second it is, which will cause the else block to fire.
And this is why your code is breaking, during the first pass through of render, jsonPackage is not defined which will throw an error.
Its not really possible to explain why it's not defined the first time around without seeing the rest of your code. As a rule of thumb however, you should generally never assume that a React state value will always be defined and add checks accordingly.

How .__defineGetter__ can be used to detect if the console in a browser is open

I have been reading through the source code here which detects when the console is open and if so plays an audio element.
I am confused by a couple of things.
Firstly, I cannot figure out how it detects that the console is open.
if( audioCheck === true || (window.Firebug && window.Firebug.chrome && window.Firebug.chrome.isInitialized)) {
play();
}
The lines below return undefined so it is audioCheck === true that triggers the play() function.
window.Firebug && window.Firebug.chrome && window.Firebug.chrome.isInitialized
It is the following line that sets audioCheck to true. I have done some research on __defineGetter__ but it remains unclear for me.
audioElement.__defineGetter__('id', function() {
audioCheck = true;
});
Can anyone explain what this does? I cannot figure it out after much research.
And finally what completely throws me is that if I remove this line the audio doesn't play:
console.log("Check the console: ", audioElement);
This is really strange as I would have though this should only log the info to the console, and not have any effect on whether or not the sound is played, but I guess this must tie back in with the __defineGetter__
There are a number of questions in here so any light that could be shed on these would be greatly appreciated.
I don't know of any sources to confirm this1, but most likely the behavior you are experiencing is an effect of what modern browsers' consoles usually do — if you issue console.log() and pass an HTML element as its argument, the console will attempt to display its details such as the ID. And the __defineGetter__ line ensures that when the browser accesses the ID, the fake getter function gets invoked (__defineGetter__() is just a non-standard way of setting — or replacing — a getter property on an object2). Quite smart, isn't it?
1Probably analysis of the source code of various browsers would be required to fully understand and validate the issue.
2Read more on getters at MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get (note that the standard way, as described therein, is to call Object.defineProperty()).

string comparison in Chrome changing mid-function

I am getting a totally bizarre issue in Chrome v. 33 that looks as if the string comparison operator is broken. It only occurs with the developer tools closed. I have the following function:
function TabSelected(data) {
var tab, was_design;
this.data = data;
tab = this.data.tab;
was_design = tab === 'design';
if (this.data.tab === 'design') {
this.tab = 1;
} else {
this.tab = 2;
console.log('was_design');
console.log(was_design);
console.log('is_design');
console.log(tab === 'design');
}
}
Which I call like so:
new TabSelected({
tab: 'design'
});
I have a setInterval running that runs this code every 50 ms. Most of the time, the if statement picks the first code path, so nothing gets logged to the console. However, after about ~8 seconds, it goes down the else code path. When I open the developer tools afterwards (since the bug doesn't happen when they're closed), I see the following log output:
was_design (index):96624
false (index):96625
is_design (index):96626
true (index):96627
I am... confused by this. I've also tried logging the contents of tab, which is in fact 'design', and logging this, which is a new TabSelected instance.
Am I losing my mind? Is Chrome losing it's mind?
UPDATE: I was able to reproduce it in a simplified setting: http://jsfiddle.net/WBpLG/24/. I'm pretty sure this is a bug with Chrome and I've filed an issue, see answer below.
Make this change and the problem should go away:
if (this.data.tab === 'design') {
to
if (String(this.data.tab) === 'design') {
However, I can confirm that typeof this.data.tab === 'string' both before the if clause and during the else, so I think this is only a partial answer at best.
Alternatively, I can also clear the problem by adjusting NewElementButtonSectionOpened.prototype.previous_requirement on line 59440:
// Create a single instance of the requirement and store it in the closure.
var cachedReq = new TabSelected({ tab: 'design' });
// Now just return that one instance over and over again.
NewElementButtonSectionOpened.prototype.previous_requirement = function() {
// deleted line: return new TabSelected({ tab: 'design' });
return cachedReq;
};
While both of these solutions fix the problem on my machine, it is not clear to me why this works.
I am afraid to mention it, but at one point, I was also able to prevent the error from happening by adding a throw new Error("..."); line in your else block. In other words, changing something in the else block altered the behavior of the if check. My only clue here is that the length of the error message mattered. For a while there, I could clear the error or cause the error consistently by altering the length of an error message that would never be thrown. This is so bizarre that I must surely have been mistaken, and indeed, I can no longer replicate it.
However, this is an extremely large JavaScript file. Maybe there is something to that. Maybe it is just a ghost story. This problem is certainly quite creepy enough without it, but just in case somebody else sees something similar... You aren't alone.
I was able to create a simple reproduction case, so I've filed a bug with Chromium.
The necessary conditions seem to be: a setInterval or repeating setTimeout, an expensive computation in the body of the interval, a call to a new Object passing data that contains a string, and a string comparison.

A weird prototype loading thing with Yabble.js

I have a very odd problem that I have to assume is because of Yabble.js. I have never used Yabble.js before, and the only reason I am now is because it is a dependency of a library I'm using (Gamejs), but I would love to understand why this happens, and whether it is actually Yabble.js's fault, or possibly Gamejs's.
Here's a heavily compressed (and modified for genericness) version of my main.js:
var gamejs = require('gamejs');
...
function Character(/*lots of arguments*/) {
Character.superConstructor.apply(this, arguments);
this.somethingtomakeitaprototypeforthisexample = oneofthearguments;
}
gamejs.utils.objects.extend(Character, gamejs.sprite.Sprite);
Character.prototype.draw = function(display){
display.blit(this.animator.image, this.pos);
}
... /*Skipping most of the file, irrelevant to the problem*/
function main() {
maincharacter = new Character(/* appropriate number and types of arguments */);
... /*skipping the rest*/
}
gamejs.ready(main);
I have done enough debugging to know that it gets into the main function no problem and that the break occurs at the call to Character. Here is the error message (from Chrome's console):
Uncaught TypeError: undefined is not a function
main
_readyResources
I have determined that Character is the undefined function. However, if I define my ready function thusly:
gamejs.ready(function(){
console.log('Character:');
console.log(Character);
main();
});
the full contents of Character, as properly defined, prints out, but I still get the error in main. Thus, I know that Character is defined by the namespace before main is called.
Fun fact though: I do have a workaround. If I change the function prototype for main to:
function main(CharacterClass) {...};
then change the ready function to:
gamejs.ready(function(){ main(Character); });
and change the relevant line in main to:
var character = new CharacterClass(...);
it works fine. But this feels really hackish.
So my question is not how to make it work, since I have that already, but rather why it is a problem and how to make it work like it's supposed to.
Any thoughts?

variable assignments using jQuery failing in Safari?

I'm using jQuery 1.3.2 and it's breaking under Safari 4 for mysterious reasons.
All of my javascript references are made right before the tag, yet with the following code:
var status = $('#status');
status.change( function(){ /* ... */ } );
The following error is displayed in the Web Inspector:
TypeError: Result of expression 'status.change' [undefined] is not a function.
However the error is not encountered if I eliminate the variable assignment attach the change method directly like so:
$('#status').change( function(){ /* ... */ } );
Why? I need to use variables for this and several other findById references because they're used many times in the script and crawling the DOM for each element every time is regarded as bad practice. It shouldn't be failing to find the element, as the javascript is loaded after everything except and .
Try changing the variable to something other than "status."
It's confusing your variable with window.status (the status bar text). When I typed var status = $('#status') into the debugging console, the statusbar changed to [Object object]. Must be a bug in Safari.
If you put the code inside a function, so that status becomes a function-local variable, it should work.
It's standard practice in jQuery to wrap things in a
$.onready(function() {
});
This makes sure the DOM is loaded before you try to manipulate it.

Categories

Resources