观察定义属性的值时,超出了最大堆栈

时间:2015-09-15 17:50:42

标签: javascript object.observe

每当我尝试使用Object.observe来观察我通过Object.defineProperty定义属性的对象中的更改时,我收到Maximum call stack size exceeded错误。

在能够同时使用这两种方法时,绕过抛出此错误的正确方法是什么?

注意:Object.observe仅适用于Chrome和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>

2 个答案:

答案 0 :(得分:1)

您正在Object.defineProperty...

一遍又一遍地阅读和写入同一个变量

您应该在TestClass的第一行更改this.testValue的名称。我建议将其重命名为this._testValue,这是一个命名变量的约定,以指示它们是&#34;私有&#34;。

注意,您也可以保留this.testValue并完全删除Object.defineProperty...部分,因为您所做的只是读取和写入默认值。

&#13;
&#13;
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
    };
}());
&#13;
<!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>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

解决这个问题的另一种方法,如果你不想排序&#34;包装&#34;你的间接价值是使用Object.getNotifier(),它允许你手动发出通知并保留一个不是你对象成员的局部变量。

如果您使用通知程序,则可以避免必须具有实际未被使用的对象属性。如果您使用包装方法,则对象上将同时包含_testValue testValue。使用通知程序,您将拥有testValue

考虑代码更改:

function TestClass() {
    var testValue, notifier;
    /* 
     * The new locally scoped varible which will
     * be captured by the getter/setter closure
     */
    testValue = 0;

    /*
     * Create a notifier for the object
     * which we can use to trigger 
     * Object.observe events manually
     */
    notifier = Object.getNotifier(this);

    Object.defineProperty(this, "testValue", {
        get: function () {
            return testValue;
        },
        set: function (value) {
            /*
             * Use the notifier to trigger 
             * the observe()
             */
            notifier.notify({
                type: "update",
                name: "testValue",
                oldValue: testValue
            });
            testValue = value;
        },
        enumerable: true,
        configurable: false
    });
}