Search code examples
javascriptobject.observe

Maximum stack exceeded when observing value of defined property


I am getting a Maximum call stack size exceeded error whenever I try to use Object.observe to observe changes in an object that I defined properties for through Object.defineProperty.

What is the correct way to get around throwing this error while still being able to use both of these methods?

Note: Object.observe is only available in Chrome and Opera

var TestModule = (function () {
    "use strict";

    function TestClass() {
        this.testValue = 0;
        Object.defineProperty(this, "testValue", {
            get: function () {
                return this.testValue;
            },
            set: function (value) {
                this.testValue = value;
            },
            enumerable: true,
            configurable: false
        });
    }

    return {
        TestClass: TestClass
    };
}());
<!DOCTYPE html>

<head>
    <title>Stack Exceed Test</title>
    <script src="../js/TestModule.js"></script>
</head>

<body>
    <main>
        <div id="logger" role="log"></div>
    </main>
    <script>
        document.addEventListener("DOMContentLoaded", function () {
            var logger = document.getElementById("logger"),
                tc = new TestModule.TestClass();

            function log(message) {
                if (logger) {
                    logger.innerHTML = message;
                } else {
                    console.error(message);
                }
            }

            if (typeof Object.observe === "function") {
                Object.observe(tc, function (changes) {
                    console.log("Change");
                });

                try {
                    tc.testValue = 5;
                } catch (e) {
                    log(e);
                }
            } else {
                log("Object.observe is unsupported in your browser");
            }
        });
    </script>
</body>


Solution

  • You are reading and writing to the same variable over and over again in Object.defineProperty...

    You should change the name of this.testValue in the first line of TestClass. I would suggest renaming it to this._testValue which is a convention for naming variables to indict they are "private".

    Note, you can also keep this.testValue and completely remove the Object.defineProperty... section, because all you're doing is reading and writing the value, which is default.

    var TestModule = (function () {
        "use strict";
    
        function TestClass() {
            this._testValue = 0;
            Object.defineProperty(this, "testValue", {
                get: function () {
                    return this._testValue;
                },
                set: function (value) {
                    this._testValue = value;
                },
                enumerable: true,
                configurable: false
            });
        }
    
        return {
            TestClass: TestClass
        };
    }());
    <!DOCTYPE html>
    
    <head>
        <title>Stack Exceed Test</title>
        <script src="../js/TestModule.js"></script>
    </head>
    
    <body>
        <main>
            <div id="logger" role="log"></div>
        </main>
        <script>
            document.addEventListener("DOMContentLoaded", function () {
                var logger = document.getElementById("logger"),
                    tc = new TestModule.TestClass();
    
                function log(message) {
                    if (logger) {
                        logger.innerHTML = message;
                    } else {
                        console.error(message);
                    }
                }
    
                if (typeof Object.observe === "function") {
                    Object.observe(tc, function (changes) {
                        console.log("Change");
                    });
    
                    try {
                        tc.testValue = 5;
                    } catch (e) {
                        log(e);
                    }
                } else {
                    log("Object.observe is unsupported in your browser");
                }
            });
        </script>
    </body>