0

Maximum call stack size exceeded每当我尝试使用Object.observe来观察我为 through 定义属性的对象的变化时,我都会收到错误消息Object.defineProperty

在仍然能够使用这两种方法的同时避免抛出此错误的正确方法是什么?

注意: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>

4

2 回答 2

1

你一遍又一遍地读写同一个变量Object.defineProperty...

this.testValue您应该在 TestClass 的第一行更改名称。我建议将其重命名this._testValue为命名变量的约定,以表明它们是“私有的”。

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

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>

于 2015-09-15T17:57:17.607 回答
0

解决此问题的另一种方法是,如果您不想通过间接方式“包装”您的值,则使用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
    });
}
于 2015-09-15T19:44:23.643 回答