7

Assuming I have a div that looks like:

<div id="testDiv">some stuff in here</div>

and I have a script that defines an object literal:

var testObject = 
{
    testDiv: $("#testDiv"),
    testDivProperty: this.testDiv    
};

Why is it when I access testObject.testDiv I get a reference to a jQuery object, i.e.,

[<div id=​"testDiv">​…​</div>​]

but when I access testObject.testDivProperty I get a reference to the actual element, i.e.,

<div id=​"testDiv">​…​</div>​

and hence am not able to perform jQuery operations on testObject.testDivProperty?

André Dion
  • 21,269
  • 7
  • 56
  • 60
x1886x
  • 1,217
  • 2
  • 12
  • 21
  • You *can* perform jQuery operations on it, but it means wrapping it again - `$(testObject.testDivProperty);`. I'm just commenting though. I'm as curious about this as you are :) – Reinstate Monica Cellio Oct 02 '13 at 11:45
  • Personally on Chrome I get `undefined` when querying `testObject.testDivProperty` (tested using `body` instead of `#testDiv`). – h2ooooooo Oct 02 '13 at 11:46
  • 1
    I just tested in Chrome, using the above code, and got the same result as the OP. – Reinstate Monica Cellio Oct 02 '13 at 11:47
  • This is the expected result, but I'm not really sure why exactly the jQuery element is unwrapped? -> http://jsfiddle.net/CQw5v/ – adeneo Oct 02 '13 at 11:49
  • I would have expected `this.testDiv` to be `undefined`, but for some reason `window.testDiv` exists...(I get the [same result](http://jsfiddle.net/zmGPd/) as OP and Archer running in Chrome Canary) – André Dion Oct 02 '13 at 11:49
  • @Archer That's incredibly odd. [Here's what happens for me](http://screencast.com/t/IcDbNk6XArQ). – h2ooooooo Oct 02 '13 at 11:49
  • When trying to assign inside a function, works ok: http://jsfiddle.net/CQw5v/1/ but outside, I get same as those before me. – Jakub Kotrs Oct 02 '13 at 11:50
  • 1
    `this` is the window object, and this.testDiv references the native DOM element as it's attached to the window in some browsers. – adeneo Oct 02 '13 at 11:52
  • possible duplicate of [Self-references in object literal declarations](http://stackoverflow.com/questions/4616202/self-references-in-object-literal-declarations) combined with [Should the id of elements be made global variables?](http://stackoverflow.com/questions/6381425/should-the-id-of-elements-be-made-global-variables-and) – Bergi Oct 02 '13 at 12:08
  • Also note that the element ID will only be attached to the window if no such property already exists. This means that if you start using this crappy method of accessing elements, and you create a DIV with the ID `history`, `location`, or anything else that already exists in the window object, you obviously can't access those elements with `window.location`, as that's already taken, causing even more confusion. – adeneo Oct 02 '13 at 12:21

6 Answers6

3

Trying to refer to the object you're defining as this during object instantiation doesn't work like you're expecting it to.

this in your example actually refers to the window object. Some browsers (e.g., Chrome and IE) will attach named DOM nodes to the document and/or window objects, which is why this.testDiv refers to the element with id="testDiv". It just so happens the property name you're trying to access has the same value as the element ID.

To demonstrate what's really going on, try this:

<div id="test"></div>

var myObj = {
    prop1: $('#test'),
    prop2: this.prop1
};

this.prop1 in the context of myObj should be undefined, but window.test may (depending on the browser) refer to the DOM node <div id="test"></div>.

Given your example, you could do your assignment as follows:

var myObj = { prop1: $('#test') };
myObj.prop2 = myObj.prop1;

or

var test = $('#test');
var myObj = {
    prop1: test,
    prop2: test
};
André Dion
  • 21,269
  • 7
  • 56
  • 60
1

This cannot work. this is window in this context.

var testObject = 
{
    testDiv: $("#testDiv"),
    testDivProperty: this.testDiv // window.testDiv

}
user229044
  • 232,980
  • 40
  • 330
  • 338
  • 1
    But why does `testDiv` exist as a property of `window`, and why does it reference the correct DOM node? Is this documented behaviour? – André Dion Oct 02 '13 at 11:54
  • It doesn't. `this.testDiv` is undefined. You are setting `testDiv` elsewhere, possibly accidentally leaking it as a global. If, anywhere else in your code, you're doing `testDiv = ...` without first scoping it with `var testDiv`, you're creating a `testDiv` property on `window`. – user229044 Oct 02 '13 at 11:56
  • 4
    In some browsers elements are attached to the window by name or ID, that's why window.testDiv works, it's the ID of the element. – adeneo Oct 02 '13 at 11:56
  • @meagar It's not `undefined` though (at least not in Chrome). That's what's surprising for me. – André Dion Oct 02 '13 at 11:57
  • @adeneo Ah, of course. Your browser *may* be biting you that way. – user229044 Oct 02 '13 at 11:57
  • 2
    http://stackoverflow.com/questions/3434278/ie-chrome-are-dom-tree-elements-global-variables-here – adeneo Oct 02 '13 at 11:58
  • @meager - try it in the console on this page. Just append the div to `body` and then create the variable. You'll see it work just as described. – Reinstate Monica Cellio Oct 02 '13 at 11:58
  • @Archer - depending on the browser. IE used this crap for years, and it works in Chrome as well, but it's not really standarized, so one shouldn't rely on it, but it's the reason this strange example is working in some browsers. – adeneo Oct 02 '13 at 12:00
  • @Archer Yes, this has nothing to do with the code in qustion though. As adeneo points out, Chrome is adding the div to the window by its ID. The problem only appears because the variable name and div ID happen to be the same. – user229044 Oct 02 '13 at 12:00
  • @adeneo Actually, it's completely standard behaviour, and browsers are *supposed* to do it. – user229044 Oct 02 '13 at 12:03
  • 1
    It's in the drafts, and will probably be standarized, but I don't think Firefox supports this at all, and it's a really bad practice to clutter the window object with all the values of the id and/or name attribute "of any HTML element in the active document with a non-empty attribute". – adeneo Oct 02 '13 at 12:06
  • @meagar Yes, I know - see my answer below ;) – Reinstate Monica Cellio Oct 02 '13 at 12:06
  • @adeneo Plus there's the obvious issue that *will* occur when people call elements by the same name as existing window properties. Personally I think it sucks and has trouble written all over it. – Reinstate Monica Cellio Oct 02 '13 at 12:07
  • @adeneo Firefox does support it, so do all browsers which correctly and fully implement HTML5. – user229044 Oct 02 '13 at 12:07
  • window.testDiv depends on browser – MD SHAHIDUL ISLAM Oct 02 '13 at 12:08
  • @Salim So does literally everything. I think what you're implying is that `window.testDiv` is *non-standard*, but that isn't the case. This is completely standard HTML5, and modern Webkit, Firefox and IE all support it. – user229044 Oct 02 '13 at 12:12
  • https://developer.mozilla.org/en-US/docs/Migrate_apps_from_Internet_Explorer_to_Mozilla#DOM_differences – adeneo Oct 02 '13 at 12:14
  • @meagar - as noted earlier, it's in the drafts for HTML 5.1, so how it can be completely standard HTML5 is beyond me? You are however right in that the newer versions of Firefox also supports this. – adeneo Oct 02 '13 at 12:24
  • @adeneo It's in HTML5, regardless 5.1: http://www.w3.org/TR/html5/browsers.html#named-access-on-the-window-object – user229044 Oct 02 '13 at 12:36
  • Those are recommendations for the spec, posted a few months ago ? – adeneo Oct 02 '13 at 12:38
0

After some playing around I found the answer. At the time that you create the 2nd property, this refers to window, where you have a div with the id of testDiv.

So you're actually doing this...

var testObject = 
{
    testDiv: $("#testDiv"),
    testDivProperty: window.testDiv    
}

I personally wasn't aware that you could do this, but window.testDiv returns the DOM element with the ID testDiv.

Reinstate Monica Cellio
  • 25,975
  • 6
  • 51
  • 67
0

As mentioned already, this refers to the global window object.

The reason this.testDiv refers to the DOM element is because of a standard behavior in web browsers to add a global references to every DOM element with an id. The references are added as the elements are parsed, so your script code must be located below the element to reference.

Whether to rely on these references or not is another discussion.

Fredrik
  • 113
  • 8
0

Actually, in first case getting the jQuery object is obvious and should be understood (as you used '$'). In the second case, you get reference to a simple DOM node(object) because of these reasons-

- You didn't use jQuery anywhere in it, so don't expect it to be a jQuery object.

- You accessed this.testDiv meaning that - give me the property named "testDiv" of the current node(which is being accessed) Now if you have written this code in the <body> tag then this should point to the node/object(in DOM) of body element. I am not sure on this part but, somehow your 'testDiv' object was registered as a property in the body object(maybe because you used an "id" attribute for this element, thus making it unique). Thus, when you tried getting the object using this.testDiv you got the exact object for the <div> element in the DOM. And, javascript by default gives you a simple reference to the DOM/javascript object(not the jQuery object).

Apart from this, jQuery objects can be thought of as a coating over the normal javascript/DOM objects. It was not part of the question but still if you want to access as a jQuery object then,

To convert javascript object Obj to jQuery object, do this Obj=$(Obj);

The new Obj will be a jQuery object.

halkujabra
  • 2,844
  • 3
  • 25
  • 35
  • No. `this` would not point to the `` element when the script is included there. What made you think that? – Bergi Oct 02 '13 at 12:55
0
let object = $('#someId') -- jQueryObject

accesing any custom object field

object[0].anyProp = 'anyValue'

console.log(object) -- jQuery object
console.log(object[0]) -- Raw JS object
console.log(object[0].anyProp) -- Raw JS object prop
YanAlex
  • 99
  • 1
  • 10