开发者问题收集

JavaScript - 未捕获的 RangeError:超出最大调用堆栈大小

2017-05-04
2877

我在使用此代码时出现错误

var book = {
        year: 2004,
        edition: 1
    };

    Object.defineProperty(book, "year", {
        get: function(){
            return this.year;
        },
        set: function(newValue){

            if (newValue > 2004) {
                this.year = newValue;
                this.edition += newValue - 2004;
            }
        }
    });

    book.year = 2005;
    alert(book.edition);

警告告诉我错误发生在 Object.set [as year] this.year = newValue; 我很困惑为什么设置年份会导致此错误?

3个回答

设置 year 属性时,会隐式调用 set 函数。

set 函数会设置 year 属性(如果值为 > 2004)。

因此:

  1. 将 year 属性设置为 2005
  2. set 函数会将 year 属性设置为 2005
  3. GOTO 2 并无限循环
Quentin
2017-05-04

您正在为 year 定义一个 getter 和一个 setter。setter 在分配给 this.year = newValue; 时会再次调用 setter,这会导致无限循环。例如,您需要定义一个自定义属性 _year ,并将年份状态保留在那里:

var book = {
    edition: 1
};

Object.defineProperty(book, "_year", {
    value: 2004,
    enumerable: false, // Hide it when looping the object
    writeable: true,
    configurable: true
});

Object.defineProperty(book, "year", {
    get: function(){
        return this.year;
    },
    set: function(newValue){

        if (newValue > 2004) {
            this._year = newValue;
            this.edition += newValue - 2004;
        }
    },
    enumerable: true, // Show this when looping
    configurable: true
});

book.year = 2005;
alert(book.edition);

console.log(Object.keys(book)); // ['edition', 'year']
nils
2017-05-04

以下是导致此错误的事件序列:

  • 您设置了书籍的 year
  • 由于它是一个属性,因此该值将传递给您的 setter 函数。
  • 检查已执行 - 因为在本例中它为真,所以 year 已设置。
  • 哦 - 由于您刚刚设置了 year ,setter 再次运行。
  • 检查继续通过,因为它一遍又一遍地接收相同的值。
  • 您的浏览器开始无限循环,内存耗尽,并陷入一大堆中。

为了避免这种情况,您需要将实际值存储在对象的单独字段中(例如 this._year ),然后让您的 getter 返回该值。以下是示例:

var book = {
    _year: 2004,
    edition: 1
};

Object.defineProperty(book, "year", {
    get: function() {
        return this._year;
    },
    set: function(newValue) {
        if (newValue > 2004) {
            this._year = newValue;
            this.edition += newValue - 2004;
        }
    }
});

book.year = 2005;
alert(book.edition);
Joe Clay
2017-05-04