Javascript 超过最大调用堆栈大小-没有明显的递归

Javascript 超过最大调用堆栈大小-没有明显的递归,javascript,class,inheritance,recursion,callstack,Javascript,Class,Inheritance,Recursion,Callstack,我花了大约12个小时浏览这段代码,并对其进行了修改,试图找出哪里存在递归问题,因为我得到了“超过了最大调用堆栈大小”错误,但没有找到它。比我聪明的人请帮帮我 到目前为止,我发现当我创建对象,spot,一个circle,对象时,问题就消失了,但是当我将其设置为“pip”时,我得到了这个堆栈溢出错误。我已经用一个该死的显微镜检查了pip课程,但仍然不知道为什么会发生这种情况 var canvas = document.getElementById('myCanvas'); //----------

我花了大约12个小时浏览这段代码,并对其进行了修改,试图找出哪里存在递归问题,因为我得到了“超过了最大调用堆栈大小”错误,但没有找到它。比我聪明的人请帮帮我

到目前为止,我发现当我创建对象,
spot
,一个
circle
,对象时,问题就消失了,但是当我将其设置为“pip”时,我得到了这个堆栈溢出错误。我已经用一个该死的显微镜检查了pip课程,但仍然不知道为什么会发生这种情况

var canvas = document.getElementById('myCanvas');

//-------------------------------------------------------------------------------------
// Classes
//-------------------------------------------------------------------------------------
//=====================================================================================
//CLASS - point
function point(x,y){
    this.x = x;
    this.y = y;
}
//=====================================================================================
// CLASS - drawableItem
function drawableItem() {
    var size = 0;
    this.center = new point(0,0);
    this.lineWidth = 1;
    this.dependentDrawableItems = new Array();
}
//returns the size
drawableItem.prototype.getSize = function getSize(){
    return this.size;
}
// changes the size of this item and the relative size of all dependents
drawableItem.prototype.changeSize = function(newSize){
    var relativeItemSizes = new Array;
    relativeItemSizes.length = this.dependentDrawableItems.length;
    // get the relative size of all dependent items
    for (var i = 0; i < this.dependentDrawableItems.length; i++){
        relativeItemSizes[i] = this.dependentDrawableItems[i].getSize() / this.size;
    }
    // change the size
    this.size = newSize;
    // apply the ratio of change back to all dependent items
    for (var i = 0; i < relativeItemSizes.length; i++){
        this.dependentDrawableItems[i].changeSize(relativeItemSizes[i] * newSize);
    }
}
//moves all the vertices and every dependent to an absolute point based on center
drawableItem.prototype.moveTo = function(moveX,moveY){
    //record relative coordinates
    var relativeItems = new Array;
    relativeItems.length = this.dependentDrawableItems.length;
    for (var i = 0; i < relativeItems.length; i++){
        relativeItems[i] = new point;
        relativeItems[i].x = this.dependentDrawableItems[i].center.x - this.center.x;
        relativeItems[i].y = this.dependentDrawableItems[i].center.y - this.center.y;
    }
    //move the center
    this.center.x = moveX;
    this.center.y = moveY;
    //move all the items relative to the center
    for (var i = 0; i < relativeItems.length; i++){
        this.dependentDrawableItems[i].moveItemTo(this.center.x + relativeItems[i].x,
            this.center.y + relativeItems[i].y);
    }
}
// draws every object in dependentDrawableItems
drawableItem.prototype.draw = function(ctx){
    for (var i = 0; i < this.dependentDrawableItems.length; i++) {
        this.dependentDrawableItems[i].draw(ctx);
    }
}

//=====================================================================================
//CLASS - circle
function circle(isFilledCircle){
    drawableItem.call(this);
    this.isFilled = isFilledCircle
}
circle.prototype = new drawableItem();
circle.prototype.parent = drawableItem.prototype;
circle.prototype.constructor = circle;
circle.prototype.draw = function(ctx){
    ctx.moveTo(this.center.x,this.center.y);
    ctx.beginPath();
    ctx.arc(this.center.x, this.center.y, this.size, 0, 2*Math.PI);
    ctx.closePath();
    ctx.lineWidth = this.lineWidth;
    ctx.strokeStyle = this.outlineColor;
    if (this.isFilled === true){
        ctx.fill();
    }else {
        ctx.stroke();
    }
    this.parent.draw.call(this,ctx);
}

//=====================================================================================
//CLASS - pip
function pip(size){
    circle.call(this,true);
}
pip.prototype = new circle(false);
pip.prototype.parent = circle.prototype;
pip.prototype.constructor = pip;

//----------------------------------------------------------------------
// Objects/variables - top layer is last (except drawable area is first)
//----------------------------------------------------------------------
var drawableArea = new drawableItem();

var spot = new pip();
spot.changeSize(20);
drawableArea.dependentDrawableItems[drawableArea.dependentDrawableItems.length] = spot;

//------------------------------------------
// Draw loop
//------------------------------------------
function drawScreen() {
    var context = canvas.getContext('2d');
    context.canvas.width  = window.innerWidth;
    context.canvas.height = window.innerHeight;

    spot.moveTo(context.canvas.width/2, context.canvas.height/2);

    drawableArea.draw(context);
}

window.addEventListener('resize', drawScreen);
var canvas=document.getElementById('myCanvas');
//-------------------------------------------------------------------------------------
//班级
//-------------------------------------------------------------------------------------
//=====================================================================================
//类点
功能点(x,y){
这个.x=x;
这个。y=y;
}
//=====================================================================================
//类别-可提取项目
函数drawableItem(){
变量大小=0;
该中心=新点(0,0);
此参数为0.lineWidth=1;
this.dependentDrawableItems=新数组();
}
//返回大小
drawableItem.prototype.getSize=函数getSize(){
返回此.size;
}
//更改此项的大小以及所有从属项的相对大小
drawableItem.prototype.changeSize=函数(newSize){
var relativeItemSizes=新数组;
relativeItemSizes.length=此.dependentDrawableItems.length;
//获取所有依赖项的相对大小
对于(变量i=0;i
下面是演示:

这是你的问题。在
pip
对象上,父对象将是
circle.prototype
。因此,当您现在调用
spot.draw()
时,它将调用
spot.parent.draw.call(spot)
,其中
此.parent
仍然是
圆。prototype


您需要从
circle.prototype.draw
显式调用
drawableItem.prototype.draw.call(this)
。顺便说一句,你应该这样做。

你为什么要写这样的代码?很难理解和调试。当我创建很多类时,我通常使用它们来构造代码。以下是我将如何重写您的代码:

var Point = Object.augment(function () {
    this.constructor = function (x, y) {
        this.x = x;
        this.y = y;
    };
});
使用
augment
可以干净地创建类。例如,您的
drawableItem
类可以按如下方式重新构造:

var DrawableItem = Object.augment(function () {
    this.constructor = function () {
        this.size = 0;
        this.lineWidth = 1;
        this.dependencies = [];
        this.center = new Point(0, 0);
    };

    this.changeSize = function (toSize) {
        var fromSize = this.size;
        var ratio = toSize / fromSize;
        this.size = toSize;

        var dependencies = this.dependencies;
        var length = dependencies.length;
        var index = 0;

        while (index < length) {
            var dependency = dependencies[index++];
            dependency.changeSize(dependency.size * ratio);
        }
    };

    this.moveTo = function (x, y) {
        var center = this.center;
        var dx = x - center.x;
        var dy = y - center.y;
        center.x = x;
        center.y = y;

        var dependencies = this.dependencies;
        var length = dependencies.length;
        var index = 0;

        while (index < length) {
            var dependency = dependencies[index++];
            var center = dependency.center;

            dependency.moveTo(center.x + dx, center.y + dy);
        }
    };

    this.draw = function (context) {
        var dependencies = this.dependencies;
        var length = dependencies.length;
        var index = 0;

        while (index < length) dependencies[index++].draw(context);
    };
});
var Circle = DrawableItem.augment(function (base) {
    this.constructor = function (filled) {
        base.constructor.call(this);
        this.filled = filled;
    };

    this.draw = function (context) {
        var center = this.center;
        var x = center.x;
        var y = center.y;

        context.moveTo(x, y);

        context.beginPath();
        context.arc(x, y, this.size, 0, 2 * Math.PI);
        context.closePath();

        context.lineWidth = this.lineWidth;
        context[this.filled ? "fill" : "stroke"]();
        base.draw.call(this, context);
    };
});

var Pip = Circle.augment(function (base) {
    this.constructor = function () {
        base.constructor.call(this, true);
    };
});
现在您已经创建了所有类,您终于可以开始绘图了:

window.addEventListener("DOMContentLoaded", function () {
    var canvas = document.getElementById("myCanvas");
    var context = canvas.getContext("2d");
    var drawableArea = new DrawableItem;
    var spot = new Pip;

    spot.changeSize(20);
    drawableArea.dependencies.push(spot);
    window.addEventListener("resize", drawScreen, false);

    drawScreen();

    function drawScreen() {
        var width = canvas.width = window.innerWidth;
        var height = canvas.height = window.innerHeight;
        spot.moveTo(width / 2, height / 2);
        drawableArea.draw(context);
    }
}, false);
我们结束了。请亲自观看演示:

我们不仅使您的代码更具可读性、可理解性和可维护性,而且
window.addEventListener("DOMContentLoaded", function () {
    var canvas = document.getElementById("myCanvas");
    var context = canvas.getContext("2d");
    var drawableArea = new DrawableItem;
    var spot = new Pip;

    spot.changeSize(20);
    drawableArea.dependencies.push(spot);
    window.addEventListener("resize", drawScreen, false);

    drawScreen();

    function drawScreen() {
        var width = canvas.width = window.innerWidth;
        var height = canvas.height = window.innerHeight;
        spot.moveTo(width / 2, height / 2);
        drawableArea.draw(context);
    }
}, false);
var DerivedClass = BaseClass.augment(function (base) {
    console.log(base === BaseClass.prototype); // true
});
function inherits(Child,Parent){
  Child.prototype=Object.create(Parent.prototype);
  Child.parent=Parent.prototype;
  Child.prototype.constructor=Child;
};
function DrawableItem() {
  this.name="DrawableItem";
}
DrawableItem.prototype.changeSize = function(newSize){
  console.log("changeSize from DrawableItem");
  console.log("invoking object is:",this.name);
}
function Circle(isFilledCircle){
    Circle.parent.constructor.call(this);
    this.name="Circle";//override name
}
inherits(Circle,DrawableItem);
Circle.prototype.changeSize = function(newSize){
  Circle.parent.changeSize.call(this);
  console.log("and some more from circle");
};
function Pip(size){
    Pip.parent.constructor.call(this,true);
    this.name="Pip";
}
inherits(Pip,Circle);

var spot = new Pip();
spot.changeSize();