Максимальный стек превышен при наблюдении значения определенного свойства
Я получаю Maximum call stack size exceeded
ошибка всякий раз, когда я пытаюсь использовать Object.observe
наблюдать изменения в объекте, для которого я определил свойства через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>
2 ответа
Вы читаете и пишете в одну и ту же переменную снова и снова в 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>
Другой способ решить эту проблему, если вы не хотите "оборачивать" свое значение косвенным путём, это использовать 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
});
}