Vanilla Javascript 从不同的构造函数中访问私有方法变量

问题描述 投票:0回答:1

我正在尝试为我的大学任务构建一个绘图应用程序,并且我被迫使用封装和面向对象编程。使用 P5.js,我有 2 个构造函数,第一个构造函数(如下所示)有几个方法,其中有一个私有方法可以“获取”用户单击的颜色。第二个构造函数只是一个画圆的工具。

默认情况下,第一个构造函数有一个填充选项。在第二个构造函数中,我正在绘制圆圈,并且制作了一个按钮,一旦单击,就会删除填充或将其添加回来。

我的问题就在这里,一旦我单击删除填充,它就可以工作,但是当我想将填充应用回任何未来的圆形绘图时,我无法访问第一个构造函数的私有方法来获取用户的当前颜色选了。

我尝试在我的主 sketch.js 文件中创建一个新的 colorPalette (第一个构造函数),将其分配给一个变量,然后在创建主 CircleTool (第二个构造函数)时,我将此变量作为参数传递,认为我将能够从第二个构造函数中访问 colorPalette,请参阅下面的代码:

主 sketch.js 文件:

var toolbox = null;
var colourP = null;
var helpers = null;

function setup() {

    //create a canvas to fill the content div from index.html
    canvasContainer = select('#content');
    var c = createCanvas(canvasContainer.size().width, canvasContainer.size().height);
    c.parent("content");

    //create helper functions and the colour palette
    helpers = new HelperFunctions();
    colourP = new ColourPalette();

    //create a toolbox for storing the tools
    toolbox = new Toolbox();

    //add the tools to the toolbox.
    toolbox.addTool(new FreehandTool());
    toolbox.addTool(new LineToTool());
    toolbox.addTool(new SprayCanTool());
    toolbox.addTool(new mirrorDrawTool());
    toolbox.addTool(new CircleTool(colourP));
    background(255);

}

function draw() {
    //call the draw function from the selected tool.
    //hasOwnProperty is a javascript function that tests
    //if an object contains a particular method or property
    //if there isn't a draw method the app will alert the user
    if (toolbox.selectedTool.hasOwnProperty("draw")) {
        toolbox.selectedTool.draw();
    } else {
        alert("it doesn't look like your tool has a draw method!");
    }
}

colorPalette 构造函数:

function ColourPalette() {
    //a list of web colour strings
    this.colours = ["black", "silver", "gray", "white", "maroon", "red", "purple",
        "orange", "pink", "fuchsia", "green", "lime", "olive", "yellow", "navy",
        "blue", "teal", "aqua"
    ];
    //make the start colour be black
    this.selectedColour = "black";
    
    var self = this;

    var colourClick = function() {
        //remove the old border
        var current = select("#" + self.selectedColour + "Swatch");
        current.style("border", "0");

        //get the new colour from the id of the clicked element
        c = this.id().split("Swatch")[0];

        //set the selected colour and fill and stroke
        self.selectedColour = c;
        fill(c);
        stroke(c);

        //add a new border to the selected colour
        this.style("border", "2px solid blue");
        return c;
    }

    //load in the colours
    this.loadColours = function() {
        //set the fill and stroke properties to be black at the start of the programme
        //running
        fill(this.colours[0]);
        stroke(this.colours[0]);

        //for each colour create a new div in the html for the colourSwatches
        for (var i = 0; i < this.colours.length; i++) {
            var colourID = this.colours[i] + "Swatch";

            //using p5.dom add the swatch to the palette and set its background colour
            //to be the colour value.
            var colourSwatch = createDiv()
            colourSwatch.class('colourSwatches');
            colourSwatch.id(colourID);

            select(".colourPalette").child(colourSwatch);
            select("#" + colourID).style("background-color", this.colours[i]);
            colourSwatch.mouseClicked(colourClick)
        }

        select(".colourSwatches").style("border", "2px solid blue");
    };
    //call the loadColours function now it is declared
    this.loadColours();
    this.selectedColor = function() {
        var color = colourClick();
        fill(color);
    }
}

圆形工具构造函数:

function CircleTool(palette) {
    this.name = "circleTool";
    this.icon = "/assets/circle.jpg";
    this.colorPalette = palette;

    var startMouseX = -1;
    var startMouseY = -1;
    var drawing = false;
    this.draw = function() {
        //Function to draw the circle
        if(mouseIsPressed) {
            if(startMouseX == -1) {
                drawing = true;
                startMouseX = mouseX;
                startMouseY = mouseY;
                loadPixels();
            }    
            else {
                updatePixels();
                ellipse(startMouseX,startMouseY,dist(startMouseX,startMouseY,mouseX,mouseY));
            }        
        }
        else if(drawing) {
            drawing = false;
            startMouseX = -1;
            startMouseY = -1;
        }
    }
    //adds a button and click handler to the options area. When clicked
    //toggle the fill of the circle
    this.populateOptions = function() {
        select(".options").html(
            "<button id='directionButton'>Fill circle</button>");
        //  //click handler
        select("#directionButton").mouseClicked(function() {
            var button = select("#" + this.elt.id);
            if (self.axis == "fill") {
                self.axis = "notFill";
                console.log(colorPalette);
                button.html('Circle not Filled');
            } else {
                self.axis = "fill";
                self.lineOfSymmetry = width / 2;
                noFill();
                button.html('Circle Filled');
            }
        });
    };
}

现在,在 CircleTool 构造函数中,我采用该参数并将其分配给一个变量。我需要访问的是 colorPalette 中名为“colourClick()”的私有方法,特别是保存用户单击的当前颜色的变量“c”(我尝试在调用该函数时返回变量“c”,以便我可以获取该值,但它不起作用,我错过了一些东西。有没有办法利用这一点并获取该变量“c”的值并在“populateOptions”的 CircleTool 构造函数中使用它方法?我只允许使用普通的 Javascript 和 p5.js 方法来创建这个。

javascript p5.js
1个回答
0
投票

问题全在你的

CircleTool
“班级”内。在
populateOptions
函数中,您引用了一个变量
colorPalette
,但该范围内不存在这样的变量。
CircleTool
接受一个参数
palette
,它在范围内,所以你可以使用它。另外,您还可以分配
this.colorPalette = palette;
,但如果您想引用它,则需要使用对
CircleTool
实例的引用。您不能简单地在传递给
this.colorPalette
内部的
mouseClicked()
调用的回调函数中使用
populationOptions
,因为
this
关键字将绑定到被单击的元素。您可以使用本地
self
变量,您需要在
CircleTool
函数中的某个位置分配该变量,类似于在
ColourPalette
函数中的操作。

其他一些建议:

  1. 小心使用“self”作为变量名,它会隐藏全局
    window.self
    ,这不会伤害任何东西,但当你忘记声明/分配它时,它会变得不明显。
  2. 避免使用
    var
    。它应该被视为已弃用/有害,请使用
    const
    let
    代替。
  3. 您最好遵循更惯用的类定义风格,如果现代 JavaScript 可以接受,最好使用
    class
    语法,或者至少在构造函数之外的
    YourObject.prototype
    上声明您的方法。
  4. 混合单词颜色/颜色的拼写会令人困惑。鉴于 p5.js 使用美式英语拼写颜色,我建议您坚持使用它。然而,如果你想使用颜色,你至少应该保持一致(即为什么有一个带有选定的Colour属性‽的colorPalette对象)

工作版本:

function CircleTool(palette) {
    this.name = "circleTool";
    this.icon = "/assets/circle.jpg";
    this.colorPalette = palette;

    // Create a self variable to deal with the changing meaning of this in callback functions
    var self = this;
    var startMouseX = -1;
    var startMouseY = -1;
    var drawing = false;
    this.draw = function() {
        //Function to draw the circle
        if(mouseIsPressed) {
            if(startMouseX == -1) {
                drawing = true;
                startMouseX = mouseX;
                startMouseY = mouseY;
                loadPixels();
            }    
            else {
                updatePixels();
                ellipse(startMouseX,startMouseY,dist(startMouseX,startMouseY,mouseX,mouseY));
            }        
        }
        else if(drawing) {
            drawing = false;
            startMouseX = -1;
            startMouseY = -1;
        }
    }
    //adds a button and click handler to the options area. When clicked
    //toggle the fill of the circle
    this.populateOptions = function() {
        select(".options").html(
            "<button id='directionButton'>Fill circle</button>");
        //  //click handler
        select("#directionButton").mouseClicked(function() {
            var button = select("#" + this.elt.id);
            if (self.axis == "fill") {
                self.axis = "notFill";
                console.log(self.colorPalette);
                // set fill based on the colorPalettes current selection
                fill(self.colorPalette.selectedColour);
                button.html('Circle not Filled');
            } else {
                self.axis = "fill";
                self.lineOfSymmetry = width / 2;
                noFill();
                button.html('Circle Filled');
            }
        });
    };
}
© www.soinside.com 2019 - 2024. All rights reserved.