49

Is there a way to find out all user defined window properties and variables (global variables) in javascript?

I tried console.log(window) but the list is endless.

hippietrail
  • 15,848
  • 18
  • 99
  • 158
GriffLab
  • 2,076
  • 3
  • 20
  • 21
  • Related (if not duplicate): [Fetching all (javascript) global variables in a page](http://stackoverflow.com/q/2226007/1048572), [Javascript - dumping all global variables](http://stackoverflow.com/q/8369338/1048572) – Bergi Jul 18 '14 at 09:29
  • @Bergi: Which answer here covers my question that was just marked as a dupe of this? Are you saying the question is a dupe even though the answers are not. Should the answer about `keys()` be moved from my question or are you saying that one's wrong and even though the answers here look outdated one of these is the right answer?? – hippietrail Apr 26 '15 at 11:57
  • @hippietrail: I don't see why the answers here would be outdated. (How) don't they work for you? It seems to be just what you want, if I didn't misunderstood your question. – Bergi Apr 26 '15 at 12:04

7 Answers7

112

You could also compare the window against a clean version of the window instead of trying to snapshot during runtime to compare against. I ran this in console but, you could turn it into a function.

// make sure it doesn't count my own properties
(function () {
    var results, currentWindow,
    // create an iframe and append to body to load a clean window object
    iframe = document.createElement('iframe');
    iframe.style.display = 'none';
    document.body.appendChild(iframe);
    // get the current list of properties on window
    currentWindow = Object.getOwnPropertyNames(window);
    // filter the list against the properties that exist in the clean window
    results = currentWindow.filter(function(prop) {
        return !iframe.contentWindow.hasOwnProperty(prop);
    });
    // log an array of properties that are different
    console.log(results);
    document.body.removeChild(iframe);
}());
jungy
  • 2,932
  • 2
  • 18
  • 17
  • Chrome's console doesn't log `results` properly as of nov. 18, I had to make `results` global then log it. Awesome code though! – Maen Nov 08 '18 at 10:43
12

This is in the same spirit as @jungy 's answer but we can do it in 3 lines:

document.body.appendChild(document.createElement('div')).innerHTML='<iframe id="temoin" style="display:none"></iframe>';

for (a in window) if (!(a in window.frames[window.frames.length-1])) console.log(a, window[a])

document.body.removeChild($$('#temoin')[0].parentNode);

First we add a hidden iframe; then we test existing variables against the standard JavaScript API in the iframe; then we remove the iframe.

To work more conveniently, it could be useful to sort the results in alphabetical order, and it's still possible in a 3 lines version:

document.body.appendChild(document.createElement('div')).innerHTML='<iframe id="temoin" style="display:none"></iframe>';

Object.keys(window).filter(a => !(a in window.frames[window.frames.length-1])).sort().forEach((a,i) => console.log(i, a, window[a]));

document.body.removeChild($$('#temoin')[0].parentNode);

And it can be packed into a bookmark:

javascript:document.body.appendChild(document.createElement('div')).innerHTML='<iframe%20id="temoin"%20style="display:none"></iframe>';Object.keys(window).filter(a=>!(a%20in%20window.frames[window.frames.length-1])).sort().forEach((a,i)=>console.log(i,a,window[a]));document.body.removeChild(document.querySelectorAll('#temoin')[0].parentNode);throw 'done';
Siltaar
  • 173
  • 1
  • 7
  • 1
    "it could be useful to sort the results in chronological order, and it's still possible in a 3 lines version: ..." Don't you mean alphabetical order? (chronological would mean based on time, not alphabetical/lexical sort) – Venryx Jun 03 '19 at 21:31
  • True, fixed. Thanks. – Siltaar Jun 05 '19 at 12:03
11

You would need to do the work for yourself. Read in all properties, on the first possible time you can. From that point on, you can compare the property list with your static one.

var globalProps = [ ];

function readGlobalProps() {
    globalProps = Object.getOwnPropertyNames( window );
}

function findNewEntries() {
    var currentPropList = Object.getOwnPropertyNames( window );

    return currentPropList.filter( findDuplicate );

    function findDuplicate( propName ) {
        return globalProps.indexOf( propName ) === -1;
    }
}

So now, we could go like

// on init
readGlobalProps();  // store current properties on global object

and later

window.foobar = 42;

findNewEntries(); // returns an array of new properties, in this case ['foobar']

Of course, the caveat here is, that you can only "freeze" the global property list at the time where your script is able to call it the earliest time.

jAndy
  • 231,737
  • 57
  • 305
  • 359
  • 1
    I think this would be the closest to a perfect answer . – Andreas Louv Jun 22 '13 at 01:09
  • But maybe you should mention that `Object.getOwnPropertyNames` is part of the ECMAScript 5 Edition. Also filter and Array.indexOf – Andreas Louv Jun 22 '13 at 01:11
  • 1
    @NULL well, I was used to mention it for the last couple of month, I feel its time to move on :) – jAndy Jun 22 '13 at 01:11
  • @jAndy definetely time to move on, I only support ie9 and above now, this is a brilliant answer thanks alot. – GriffLab Jun 22 '13 at 01:24
  • 1
    @jAndy maybe put the `readGlobalProps` in an IIFE that way it would be called as soon as you define it? – GriffLab Jun 22 '13 at 01:27
  • @GriffLab Yes. I guess the same way assuming that people don't worry about legacy browsers, I'm assuming they put their application logic in closured, private scopes :-) – jAndy Jun 22 '13 at 08:49
  • Does `keys(window)` not take care of most of the filtering? – hippietrail Apr 26 '15 at 12:01
  • This won't be any use from a userscript (Greasemonkey, Tapermonkey) since I don't believe userscript are guaranteed to run before the js in the page. What would the second best method be for that case? – hippietrail Apr 26 '15 at 12:23
  • @hippietrail *Since you don't believe, nothing will ever be...?* Believe me there's more out there, the Greasemonkey [`@run-at`](https://wiki.greasespot.net/Metadata_Block#.40run-at) for example. – yckart May 28 '17 at 07:52
3

I ran this in the console in ChromeDev tool and it copied all of the user defined proper

const getUserDefinedKeys = () => {
  const globalKeys = [ 'postMessage','blur','focus','close','parent','opener','top','length','frames','closed','location','self','window','document','name','customElements','history','locationbar','menubar','personalbar','scrollbars','statusbar','toolbar','status','frameElement','navigator','origin','external','screen','innerWidth','innerHeight','scrollX','pageXOffset','scrollY','pageYOffset','visualViewport','screenX','screenY','outerWidth','outerHeight','devicePixelRatio','clientInformation','screenLeft','screenTop','defaultStatus','defaultstatus','styleMedia','onanimationend','onanimationiteration','onanimationstart','onsearch','ontransitionend','onwebkitanimationend','onwebkitanimationiteration','onwebkitanimationstart','onwebkittransitionend','isSecureContext','onabort','onblur','oncancel','oncanplay','oncanplaythrough','onchange','onclick','onclose','oncontextmenu','oncuechange','ondblclick','ondrag','ondragend','ondragenter','ondragleave','ondragover','ondragstart','ondrop','ondurationchange','onemptied','onended','onerror','onfocus','oninput','oninvalid','onkeydown','onkeypress','onkeyup','onload','onloadeddata','onloadedmetadata','onloadstart','onmousedown','onmouseenter','onmouseleave','onmousemove','onmouseout','onmouseover','onmouseup','onmousewheel','onpause','onplay','onplaying','onprogress','onratechange','onreset','onresize','onscroll','onseeked','onseeking','onselect','onstalled','onsubmit','onsuspend','ontimeupdate','ontoggle','onvolumechange','onwaiting','onwheel','onauxclick','ongotpointercapture','onlostpointercapture','onpointerdown','onpointermove','onpointerup','onpointercancel','onpointerover','onpointerout','onpointerenter','onpointerleave','onselectstart','onselectionchange','onafterprint','onbeforeprint','onbeforeunload','onhashchange','onlanguagechange','onmessage','onmessageerror','onoffline','ononline','onpagehide','onpageshow','onpopstate','onrejectionhandled','onstorage','onunhandledrejection','onunload','performance','stop','open','alert','confirm','prompt','print','queueMicrotask','requestAnimationFrame','cancelAnimationFrame','captureEvents','releaseEvents','requestIdleCallback','cancelIdleCallback','getComputedStyle','matchMedia','moveTo','moveBy','resizeTo','resizeBy','scroll','scrollTo','scrollBy','getSelection','find','webkitRequestAnimationFrame','webkitCancelAnimationFrame','fetch','btoa','atob','setTimeout','clearTimeout','setInterval','clearInterval','createImageBitmap','onappinstalled','onbeforeinstallprompt','crypto','indexedDB','webkitStorageInfo','sessionStorage','localStorage','chrome','onformdata','onpointerrawupdate','speechSynthesis','webkitRequestFileSystem','webkitResolveLocalFileSystemURL','openDatabase','applicationCache','caches','ondevicemotion','ondeviceorientation','ondeviceorientationabsolute','WebUIListener','cr','assert','assertNotReached','assertInstanceof','$','getSVGElement','getDeepActiveElement','findAncestorByClass','findAncestor','disableTextSelectAndDrag','isRTL','getRequiredElement','queryRequiredElement','appendParam','createElementWithClassName','ensureTransitionEndEvent','scrollTopForDocument','setScrollTopForDocument','scrollLeftForDocument','setScrollLeftForDocument','HTMLEscape','elide','quoteString','listenOnce','hasKeyModifiers','isTextInputElement' ];
  return Object.fromEntries(Object.entries(window).filter(([ key ]) => !globalKeys.includes(key)));
};

const getCircularReplacer = () => {
  const seen = new WeakSet();
  return (key, value) => {
    if (typeof value === 'object' && value !== null) {
      if (seen.has(value)) {
        return;
      }
      seen.add(value);
    }
    return value;
  };
};

copy(JSON.stringify(getUserDefinedKeys(), getCircularReplacer()));
Raza
  • 3,147
  • 2
  • 31
  • 35
  • If your page has iframes and throws the following error, try launching chrome with the `--disable-web-security` flag: "Blocked a frame with origin "" from accessing a cross-origin frame." – Trent Aug 28 '20 at 17:14
0

The properties of window object are in chronological order. So, create some variable with unique name at the beginning of your first script included in your webpage and get the index of this property:

var abcdefghijklmnopqrstuvwxyz = true;
var firstOwnPropertyFound = Object.keys(window).indexOf('abcdefghijklmnopqrstuvwxyz');

Then anywhere you want to get array of all user defined properties use:

let myProp = Object.keys(window).slice(firstOwnPropertyFound);

or if you want to skip the first two variables:

let myProp = Object.keys(window).slice(firstOwnPropertyFound + 2);

The myProp variable is array contains all property names you created. In my test webpage for example:

Array(7) [
  0: "abcdefghijklmnopqrstuvwxyz"
  1: "firstOwnPropertyFound"
  2: "st"
  3: "clog"
  4: "tstfnc"
  5: "tstFNC1"
  6: "obj"
  length: 7
]

Then access all variables:

myProp.forEach(item => {
  console.log(window[item]);
}

I use this and it works. (Sorry for my bad English)

0

I didn't create this code, this answer is an improved version of this original answer.

The improvements are:

  1. Wrapped around a function to use whenever needed
  2. Show the property's data, not only its name

(function showAllNonNativeWindowProperties(){

     var results, currentWindow,
  
    iframe = document.createElement('iframe');
    iframe.style.display = 'none';
    document.body.appendChild(iframe);
  
    currentWindow = Object.getOwnPropertyNames(window);
 
    results = currentWindow.filter(function(prop) {
        return !iframe.contentWindow.hasOwnProperty(prop);
    });

    for (var each of results.sort()){
        console.log(`${each}: `, window[`${each}`]);
    }
    
    document.body.removeChild(iframe);
})()
Diego Fortes
  • 8,830
  • 3
  • 32
  • 42
-6

Maybe this?:

for (var property in window)
{
    if (window.hasOwnProperty(property))
        console.log(property)
}
LonelyWebCrawler
  • 2,866
  • 4
  • 37
  • 57