ie, javascript and 'item' as a variable name - javascript

Is this considered to be a JS bug in IE?
Please check the following function
function select_deselect_all_items(status)
{
select_deselect_items_under_panel(status, $('myPanel'));
panel = $('myPanel');
var items = panel.getElementsByTagName('input');
for (var n = 0; n < items.length; n++) {
item = items[n];
if (item.id.substr(0, 10) == 'myItems_') {
item.checked = status;
select_deselect_items_under_panel(status, $('myPanel'));
}
}
}
Now, this works fine in FF and Chrome, but generate an error in IE. Error is the following:
Error: Unable to get value of the property 'substr': object is null or undefined
I have this function in several places throughout my code (haven't placed it into one js file, unfortunately) and I've already stumbled on this issue. The problem seems to be with item variable. If this is changed to something else, i.e. myWildVarName, things seem to work ok. I debugged the page in IE, and I see that item is an object with certain properties...
So, a bug or a rookie mistake?
Cheers

You do have a mistake in your code, in that you never declare the item variable and thus fall prey to the Horror of Implicit Globals.
My guess is that you have something on your page that has either the name or id "item", and so that's becoming a property of window because IE does that (and many other browsers have followed suit). As you probably know, properties of window are globals, and so when you try to assign to the item symbol in your function, you're assigning to that global property. Depending on what item is, IE may be trying to apply "don't actually assign to the object, but assign to its default property instead" logic (because it's allowed to do that if it wants to with host objects) and running into an issue.
Declare your local variable (always a good idea) and the problem should go away.
Update: Now that you've posted the actual error, the rationale above for what's happening may not be spot-on, on but the recommendation (declare the local) remains the same. :-)

IE and some other browsers have the habit of adding a reference in the global scope for each element that has an id, so the likely reason for item to already have a value in IE is that you have an element with id="item".
If you declare the item variable as a local variable in the function, it's not a problem that it exists in the global scope also:
var item;

Related

How to get out of a binding situation in javascript

I have the following code that I am trying to use to register a callback on an array of buttons. But I cannot seem to understand how I can bind the strings that I would need in the callback. Any suggestions would be much appreciated!
for (var i = 0; i < this.car_types.length; ++i) {
this.select_car_buttons.push($("#button_select_car_" +
this.car_types[i].car_type));
this.select_car_buttons[this.select_car_buttons.length - 1]
.click(function() {
console.log(this.car_types[i].car_type);
}.bind(this));
}
Somehow the this object is the button itself and not the object under whose scope the function is called.
EDIT : It seems like the this object was indeed being passed in properly. The issue is that the variable i is not going out of scope and is being captured by reference not by value. How should I go about solving this problem?
Also there seem to lots of such issues with JavaScript as a language (at least things that can be classified as an issue considering the semantics employed by the traditional C family languages such as C and C++ to be correct), is there some article I can read that warns me against these types of issues?
ANOTHER EDIT : On trying making a closure with the value of i captured by value I tried the following code
this.select_car_buttons[this.select_car_buttons.length - 1]
.click((function(scoped_i) {
return function() {
console.log(this.car_types[scoped_i].car_type);
}.bind(this);
}(i)));
But I get the following error in Safari
TypeError: undefined is not an object (evaluating 'scoped_i')
EDIT : The same code works in Firefox and Chrome but not in Safari!
This is a scope issue. For modern browsers (that support ES6) you could just change var to let in your for loop and it would get fixed.
for (let i = 0; i < this.car_types.length; ++i)
Quoting the MDN docs
The let statement declares a block scope local variable, optionally initializing it to a value.
For more global support (non ES6 support) use an immediately invoked function to create extra scope for the variable (which you will pass as a parameter)
this.select_car_buttons[this.select_car_buttons.length - 1]
.click((function(scoped_i) { // IIF starts here, the new variable is called scoped_i for verbosity
return function() { // your original function code goes here
console.log(this.car_types[scoped_i].car_type); // use the newly scoped variable
}.bind(this);
}.bind(this)(i))); // end and execute the IIF while passing the i variable to it
Yes, this structure do make a lot of closures and make code very hard to read. Since you use jQuery, there are a much better way to solve this problem which saves the data in html:
html:
<button class="select-car" data-car-type="CarA">Select CarA</button>
<button class="select-car" data-car-type="CarB">Select CarB</button>
<!-- And a lot of buttons -->
js:
var selectCarOnClick = function() {
console.info($(this).data('car-type'));
};
$('button.select-car').click(selectCarOnClick);
Live exmaple: http://codepen.io/SCLeo/pen/VaQYjW
If you have a lot of other information to store and you want to use a object to store them instead of DOM, you can save car-name or car-id instead of car-type.
Here is the document about $.data: https://api.jquery.com/jquery.data/

Debugging: Get content of variables bound inside functions

I have some function defined inside a function, but set to global:
function someFn(someVar) {
var arr = makeArray(someVar);
// global function:
foo = function(bar) {
return arr.indexOf(bar)==-1;
}
}
When I debug with chrome console:
> foo
function (bar){return arr.indexOf(bar)==-1;}
can I get, without changing the source code, the content of arr?
Let's assume I can't just get and execute the commands by which arr was generated, because I don't know the last value of someVar.
The variable has to be somewhere in the memory, because when I call the function, it can be accessed, but what name does it have? I already tried:
> foo.arr
undefined
X-Y problem response; I don't know how you could access arr from the console, but I can give you a few tips to debugging via a breakpoint, even if the code is minified.
Try using Google Chrome, and in Debugger, click the {} icon below the code window. That will pretty-print the script, though the varnames will still be minified. (_a1 = new_43` etc.)
Next is the art of reading minified code; Code minifiers can't change anything that is accessed via a string; the most signature of which are object properties (anything after a .). It also helps that without whitespace, it becomes easier to find a particular sequence of symbols. You could try CTRL-Fing for terms like .indexOf, ==-1, etc. If this is an actual corporate-released library, chances are you can go beyond your little example and refer to things like myCompanyLibrary.dockInstance.locator=.
Once you find that line, you can put a breakpoint there. Good luck!

jQuery selector does not work in IE7/8

Does anyone know why this would not work in IE7/8?
drop_area = $('div#drop_area');
It works perfectly in IE9, FF2/3, and Chrome. Internet Explorer 7/8 gives the following error:
SCRIPT438: Object doesn't support this property or method
Edit: This is the HTML that goes with my javascript:
http://pastebin.com/nwxx8RzW
IE has a weird behaviour to register some properties in global scope. Elements with an given ID may be accessed simply by using the ID.
So you have a element with the ID "drop_area", it's accessible in IE by using this ID, try:
alert(drop_area.tagName)
..to check it.(should give "DIV")
So what happens: You try to assign something else to this element when using drop_area = $('div#drop_area'); , but this is an invalid operation on an DOMElement.
So use the var-keyword to clarify that you want to create a variable
var drop_area = $('div#drop_area');
or in the case that you have to create a global variable inside a function, assign the variable to the global context:
window['drop_area'] = $('div#drop_area');
The code you've shown on pastebin has numerous global variable issues. In other words, you are coding assuming that variables you are declaring are local in scope, whereas in reality they turn out to be global. Examples include set, box_handle, elements, i, id, drop_area, element, row, image_id, etc. All of your functions are global in scope as well, when they can easily be encapsulated in an other function.
Now I don't know if there's some subtle interactions going on, whether some code has hammering (global) data set by other code, but it certainly seems as if something is getting overwritten and hence methods and properties are disappearing. I would start by going through the code and adding var to local variables. Next I'd be encapsulating most of this code in an anonymous autoexecuting function.
Usually that error shows, that you use jQuery on a website that also uses Prototype. That's why get an error (which is actually throw by Prototype). The other possibility is, that you try to call the code, before the jQuery lib was included into the HTML.
To make sure it's not my first guess, add this code to your JS code:
$.noConflict();
Therefore it is important that Prototype is included into the HTML, before jQuery is included: http://api.jquery.com/jQuery.noConflict/
If you than replace all occurrences of $() with jQuery() and it works, it was the first issue with using jQuery and Prototype at the same time.
Have you got an element with an id of 'drop_area'? ie 6/7/8 auto assigns a global var to the dom element using the element id. Some more code would be helpful.

Cannot Set Property ... of undefined --- bizarre

I'm getting a bizarre error in Chrome... check out the screenshot below.
I define record using object literal syntax.
I try setting the "id" property and get the exception.
I've tried both :
record['id'] = 'wtf';
and also
record.id = 'wtf';
I use this type of syntax all over the place in my script.... what could be going on here ?
Is this a bug in Chrome ?
EDIT :
I've solved the problem for now, but I'm still not sure why this is happening.
I moved the definition of record to occur outside of the if block. Anyone know what could be occurring ? I thought all variable declarations were scoped to the function and therefore this shouldn't be an issue.
The problem is most likely that dl is less than or equal to zero, so the statement that initializes record doesn't get executed. From your indentation, it looks like you intended for both statements to be part of the if block, but with no braces, the record['id'] = 'wtf'; statement gets executed no matter what.
By moving the variable initialization outside the if statement, you forced it to happen in any case and moved the assignment inside the if block (which, I'm assuming is what you wanted).
Probably a better way to solve it is adding braces like this:
if (dl > 0) {
var record = {};
record.id = 'wtf';
}
Unless you really do want to initialize record in both cases.
You are correct about variable declarations being scoped to the function, but the assignment doesn't happen until you get to that point in the code. record was in scope, but it still had its default value of undefined because you hadn't assigned anything to it yet.
Works for me, no reason it shouldn't work. Are you sure it's referring to that exact line? what if you alert(record) before you set it? Have you tried to debug it yet?

Strange IE error - between JavaScript global variable and element with name attribute

I tested the following code in IE6, IE7 and IE8 with the same result:
<a name="cd"/>a</a>
<script>
try {
cd = new Date;
} catch(e) {
alert(e);
}
</script>
In all cases an error is thrown. However using
var cd = new Date;
seems to solve the problem.
Does anyone know why that is ?
Here is an example: http://jsbin.com/ahuhu4/2
When you don't use the var specifier to declare your variable, the variable cd is added as a property to the window object, e.g. window.cd. You already have an object element that is a child of window that is <a name="cd">a</a> which is already typed. You can't specify new Date as a type for this object as it already exists. When you use the var keyword, you are rescoping the variable to a local scope and removing its direct attachment to the window object. This removes the error and allows IE to proceed. Other browser engines handle this differently.
IE does you the great favor of creating properties of window for each page element with an "id" value. It's just a thing. (note: this statement is not really true.)
edit — yes, the element doesn't have "id". OK, well good news - IE also treats references by name as if they were by "id". Recall that document.getElementById("cd") on that page would return a reference to the <a>, just as it would if it had an "id" element.
edit again I think it's not quite correct to say that IE creates actualy window properties, at least by my reading of what the IE8 debugger is telling me. It's more like the interpreter treats an implicit reference to a global variable ("cd" in this case) as a request for it to go look for something in the global page context by that name. To IE, that process includes checking the DOM for elements with that "id" or "name" value. By using the var keyword, you're explicitly telling the interpreter that you're declaring a symbol in the applicable scope (global, here), so that "lookup" process is skipped.
//
Firefox does not automatically define global variables for elements with ids or names.
IE including #9, Opera 10, Safari 5 and Chrome 6 all do maintain a global
rollcall of named or id'd elements in the document.
It seems like it could crowd up the global namespace...
function a1(id){
try{
window[id].style.color= 'red';
}
catch(er){
return er.message+'\n'+'window.'+id+' = '+window[id];
}
return 'window.'+id+'='+window[id];
}
function a2(id){
window[id]= 'red';
return 'window.'+id+'='+window[id]
}
/*
firefox returns window[idstring] is undefined.
The others all find it, just like the old IE document.all object.
query the id as a global identifier:
alert(a1('idstring'))
colors the element red and returns[object HTMLButtonElement]
(returns [object Object] in older ie browsers)
assign the global a new value: alert(a2('idstring')) returns 'red'
Try the element again alert(a1('idstring'))
throws an error - Cannot convert 'window[id].style' to object
or Cannot set property 'color' of undefined or
Result of expression 'window[id].style' [undefined] is not an object ot
Object expected
*/

Categories

Resources