奇怪的JavaScript行为(我期待递归)

时间:2014-02-26 10:52:51

标签: javascript recursion methods properties

我在JavaScript中编写了一个简单的class (想要更好的词)。该类创建了两个名为foobar的访问者(获取/设置)属性,以及两个名为setPropertygetProperty的方法。

属性的get / set方法调用getPropertysetProperty,后者又从属性对象中获取和设置属性。

我希望在这里看到无限递归,其中属性调用方法,这些方法调用属性,这些属性调用方法......等等。

但是它有效...而且我很清楚如何以及存储值的位置!

示例代码

var Test = (function () {
    return function Test() {
        var $this = this,
            properties = {
                foo: {
                    get: function () { return $this.getProperty("foo"); },
                    set: function (value) { $this.setProperty("foo", value); },
                    enumerable: false,
                    configurable: false
                },
                bar: {
                    get: function () { return $this.getProperty("bar"); },
                    set: function (value) { $this.setProperty("bar", value); },
                    enumerable: false,
                    configurable: false
                }
            };

        Object.defineProperties(this, properties);

        this.getProperty = function (name) {
            console.log("get was definitely called!");
            return properties[name];
        };

        this.setProperty = function (name, value) {
            console.log("set was definitely called!");
            properties[name] = value;
        };
    };
})();

var test = new Test();
//undefined
test.foo = "Hello World";
//set was definitely called!
//"Hello World"
test.bar = 3;
//set was definitely called!
//3
test.foo;
//get was definitely called!
//"Hello World"
test.bar;
//get was definitely called!
//3

非常有兴趣知道为什么我不只是收到“太多的递归”错误!

1 个答案:

答案 0 :(得分:2)

当您致电defineProperties时,您正在test对象中创建属性,而不是properties对象中的属性。

properties对象不再用作属性,仅作为属性值的存储重用。设置foo属性将使用值替换property对象中的属性定义。

设置test.foo属性时,将调用属性的setter代码并将值存储在properties对象中,但这不会影响test.foo属性。创建属性后,不再使用用于定义它们的对象。

代码有点令人困惑,因为它首先使用properties对象作为属性的定义,然后重用它来存储属性值。如果为此使用两个单独的对象,则更清楚的是设置属性不会影响属性本身:

var Test = (function () {
    return function Test() {
        var $this = this,
            def = {
                foo: {
                    get: function () { return $this.getProperty("foo"); },
                    set: function (value) { $this.setProperty("foo", value); },
                    enumerable: false,
                    configurable: false
                },
                bar: {
                    get: function () { return $this.getProperty("bar"); },
                    set: function (value) { $this.setProperty("bar", value); },
                    enumerable: false,
                    configurable: false
                }
            },
            storage = {};

        Object.defineProperties(this, def);

        this.getProperty = function (name) {
            console.log("get was definitely called!");
            return storage[name];
        };

        this.setProperty = function (name, value) {
            console.log("set was definitely called!");
            storage[name] = value;
        };
    };
})();