10

For some reason I seem unable to use JSON.stringify on a DOMWindow object. For example:

console.log(window.self); // Outputs a hierarchical DOMWindow object
console.log(JSON.stringify(window.self)); // Outputs nothing - not even an error

alert(window.self); // Alerts "[object DOMWindow]"
alert(JSON.stringify(window.self)); // Again nothing - not even an error

Tested on Safari and Chrome. Does anyone have any ideas how I can achieve this?

Edit:

Moved edit to a new question as it's not really specific to this.

1

6 Answers 6

3

Why would you want to do serialize the DOM? If you must, Crescent's link is where you need to look. The reason you cannot serialize (stringify) the window object is because it contains circular references, and JSON.stringify does not support them by default.

Sign up to request clarification or add additional context in comments.

3 Comments

@dosboy pay attention to the "why would you want to do it". There's hardly any good reason to serialize the DOM.
@Alex A lot of time has gone by, do you guys know of any way it would be possible to send a DOM object through an IPC module?
It doesn't matter why the OP wants to serialize the DOM. They just want to know how it can be done. This "answer" doesn't provide any solution (which there are) to the OP's problem.
3

In Chrome 8 dev, I get TypeError: Converting circular structure to JSON (window generally contains a self-referential self, window, and top reference, if you're not in a frame), so directly using JSON.stringify will not work.

It sounds like you're using this for debug output. If you care only about some information, you could copy that information to an object, and then stringify it. Then encapsulate it in a function to grab all the information that you think you'll ever care about from window.

var data = JSON.stringify({
    'location': window.location
    // etc
});

Comments

3

As others have said, stringify doesn't support circular references, which DOMWindow contains. Generally, circular references could be converted to JSON using Douglas Cockford's JSON cycle.js.

However, I just tried this on window, and it causes a stack overflow anyway. While that may be a bug in the cycle.js code, it seems like its more likely that window is just too big of an object.

Comments

3

This answer is not mine, but I was here for the same thing and found this answer elsewhere. I don't have that page open anymore-- I do have the github page still open...

JSON.stringify deep objects -- thanks, @Bergi. https://github.com/Canop/JSON.prune

// JSON.prune : a function to stringify any object without overflow
// two additional optional parameters :
//   - the maximal depth (default : 6)
//   - the maximal length of arrays (default : 50)
// You can also pass an "options" object.
// examples :

//   var json = JSON.prune(window)
//   var arr = Array.apply(0,Array(1000)); var json = JSON.prune(arr, 4, 20)
//   var json = JSON.prune(window.location, {inheritedProperties:true})
// Web site : http://dystroy.org/JSON.prune/
// JSON.prune on github : https://github.com/Canop/JSON.prune
// This was discussed here : https://stackoverflow.com/q/13861254/263525
// The code is based on Douglas Crockford's code : https://github.com/douglascrockford/JSON-js/blob/master/json2.js
// No effort was done to support old browsers. JSON.prune will fail on IE8.
(function () {
    'use strict';

    var DEFAULT_MAX_DEPTH = 6;
    var DEFAULT_ARRAY_MAX_LENGTH = 50;
    var seen; // Same variable used for all stringifications
    var iterator; // either forEachEnumerableOwnProperty, forEachEnumerableProperty or forEachProperty

    // iterates on enumerable own properties (default behavior)
    var forEachEnumerableOwnProperty = function(obj, callback) {
        for (var k in obj) {
            if (Object.prototype.hasOwnProperty.call(obj, k)) callback(k);
        }
    };
    // iterates on enumerable properties
    var forEachEnumerableProperty = function(obj, callback) {
        for (var k in obj) callback(k);
    };
    // iterates on properties, even non enumerable and inherited ones
    // This is dangerous
    var forEachProperty = function(obj, callback, excluded) {
        if (obj==null) return;
        excluded = excluded || {};
        Object.getOwnPropertyNames(obj).forEach(function(k){
            if (!excluded[k]) {
                callback(k);
                excluded[k] = true;
            }
        });
        forEachProperty(Object.getPrototypeOf(obj), callback, excluded);
    };

    Date.prototype.toPrunedJSON = Date.prototype.toJSON;
    String.prototype.toPrunedJSON = String.prototype.toJSON;

    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        meta = {    // table of character substitutions
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        };

    function quote(string) {
        escapable.lastIndex = 0;
        return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
            var c = meta[a];
            return typeof c === 'string'
                ? c
                : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
        }) + '"' : '"' + string + '"';
    }

    function str(key, holder, depthDecr, arrayMaxLength) {
        var i, k, v, length, partial, value = holder[key];
        if (value && typeof value === 'object' && typeof value.toPrunedJSON === 'function') {
            value = value.toPrunedJSON(key);
        }

        switch (typeof value) {
        case 'string':
            return quote(value);
        case 'number':
            return isFinite(value) ? String(value) : 'null';
        case 'boolean':
        case 'null':
            return String(value);
        case 'object':
            if (!value) {
                return 'null';
            }
            if (depthDecr<=0 || seen.indexOf(value)!==-1) {
                return '"-pruned-"';
            }
            seen.push(value);
            partial = [];
            if (Object.prototype.toString.apply(value) === '[object Array]') {
                length = Math.min(value.length, arrayMaxLength);
                for (i = 0; i < length; i += 1) {
                    partial[i] = str(i, value, depthDecr-1, arrayMaxLength) || 'null';
                }
                return  '[' + partial.join(',') + ']';
            }
            iterator(value, function(k) {
                try {
                    v = str(k, value, depthDecr-1, arrayMaxLength);
                    if (v) partial.push(quote(k) + ':' + v);
                } catch (e) { 
                    // this try/catch due to forbidden accessors on some objects
                }               
            });
            return '{' + partial.join(',') + '}';
        }
    }

    JSON.prune = function (value, depthDecr, arrayMaxLength) {
        if (typeof depthDecr == "object") {
            var options = depthDecr;
            depthDecr = options.depthDecr;
            arrayMaxLength = options.arrayMaxLength;
            iterator = options.iterator || forEachEnumerableOwnProperty;
            if (options.allProperties) iterator = forEachProperty;
            else if (options.inheritedProperties) iterator = forEachEnumerableProperty
        } else {
            iterator = forEachEnumerableOwnProperty;
        }
        seen = [];
        depthDecr = depthDecr || DEFAULT_MAX_DEPTH;
        arrayMaxLength = arrayMaxLength || DEFAULT_ARRAY_MAX_LENGTH;
        return str('', {'': value}, depthDecr, arrayMaxLength);
    };

    JSON.prune.log = function() {
        console.log.apply(console,  Array.prototype.slice.call(arguments).map(function(v){return JSON.parse(JSON.prune(v))}));
    }
    JSON.prune.forEachProperty = forEachProperty; // you might want to also assign it to Object.forEachProperty

}());

4 Comments

This seems to be copied from this answer
@Bergi: The post left the code comments intact which seem to point to all the relevant sources. It seems the repo was in fact based on the answer.
Brad, chances are the answer Bergi linked to is where you got the original code from.
@BoltClock: Oh right, I didn't notice the comments included the attribution. Thanks!
2

You don't get an error? I get TypeError: Converting circular structure to JSON. I would say, it cannot be done.

Also, window and window.self point to the same object (the Global object), so you don't need to use that property...

Comments

1

You can use this function to stringify the window object:

function recur(obj, visited = new WeakSet()) {
    if (visited.has(obj)) {
        return {}; // skip already visited object to prevent cycles
    }
    visited.add(obj); // add the current object to the visited set

    var result = {}, _tmp;
    for (var i in obj) {
        try {
            // enabledPlugin is too nested, also skip functions
            if (i === 'enabledPlugin' || typeof obj[i] === 'function') {
                continue;
            } else if (typeof obj[i] === 'object') {
                // get props recursively
                _tmp = recur(obj[i], visited);
                // if object is not {}
                if (Object.keys(_tmp).length) {
                    result[i] = _tmp;
                }
            } else {
                // string, number or boolean
                result[i] = obj[i];
            }
        } catch (error) {
            // handle error, you can log it here if needed
            // console.error('Error:', error);
        }
    }
    return result;
}
JSON.stringify(recur(window))

1 Comment

Nice, this worked! I recommend you run this in the Console on a about:blank page because it will stringify the page contents. This crashed my browser. Or run this in a blank HTML page.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.