
本文讲解如何在不破坏封装的前提下,让一个构造函数(如 CircleTool)正确访问另一个构造函数(如 ColourPalette)中维护的私有状态(如当前选中颜色),重点解决 this 绑定、作用域丢失及状态共享问题。
本文讲解如何在不破坏封装的前提下,让一个构造函数(如 circletool)正确访问另一个构造函数(如 colourpalette)中维护的私有状态(如当前选中颜色),重点解决 `this` 绑定、作用域丢失及状态共享问题。
在基于 P5.js 的绘图应用中,严格遵循面向对象与封装原则意味着:状态应被保护,但需提供受控的访问途径。你遇到的核心问题并非“无法访问私有方法”,而是对 JavaScript 执行上下文(尤其是 this 绑定)和作用域链的理解偏差——colourClick 是一个闭包内定义的私有函数,它本身不可直接导出;真正需要共享的是其副作用所维护的状态,即 selectedColour 这个公开可读的属性。
✅ 正确做法:通过公共属性暴露状态,而非尝试调用私有函数
ColourPalette 构造函数中,this.selectedColour 是一个公开可读的属性(初始值为 "black",并在用户点击色块时被更新)。它正是你需要的“当前颜色”源。无需、也不应试图调用 colourClick() —— 该函数职责是响应 DOM 事件并更新状态,不是数据获取接口。
因此,在 CircleTool 中,只需确保:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 构造时正确接收 palette 实例;
- 在回调中通过 self.colorPalette.selectedColour 安全读取该值;
- 使用 var self = this(或更现代的 const self = this)保存实例引用,避免 mouseClicked 回调中 this 指向 DOM 元素导致 this.colorPalette 失效。
以下是修正后的 CircleTool 关键片段(已适配现代实践):
立即学习“Java免费学习笔记(深入)”;
function CircleTool(palette) {
this.name = "circleTool";
this.icon = "/assets/circle.jpg";
this.colorPalette = palette; // ✅ 正确保存引用
const self = this; // ✅ 使用 const 声明,避免 window.self 冲突
let startMouseX = -1;
let startMouseY = -1;
let drawing = false;
this.draw = function() {
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;
}
};
this.populateOptions = function() {
select(".options").html("<button id='fillToggle'>Fill circle</button>");
select("#fillToggle").mouseClicked(function() {
const button = select("#" + this.elt.id);
if (self.axis === "fill") {
self.axis = "notFill";
fill(self.colorPalette.selectedColour); // ✅ 直接读取公开状态
button.html("Circle not Filled");
} else {
self.axis = "fill";
noFill();
button.html("Circle Filled");
}
});
};
}⚠️ 关键注意事项
- 不要尝试“调用私有函数获取颜色”:colourClick() 是事件处理器,其内部变量 c 属于闭包局部作用域,无法从外部访问。它的价值在于更新 self.selectedColour —— 这才是你该依赖的单一事实来源。
- 命名一致性至关重要:统一使用 color(如 colorPalette, selectedColor)而非混用 colour/color,既符合 p5.js API 规范,也提升代码可维护性。
- 避免 var,优先 const/let:var 的变量提升和函数作用域易引发隐蔽 bug;const 用于不变引用,let 用于可变值,语义清晰且更安全。
- self 不是必须,但需明确绑定:也可用箭头函数替代(select("#fillToggle").mouseClicked(() => { ... })),因其自动继承外层 this;但若需兼容旧环境,const self = this 仍是稳健方案。
✅ 总结:封装 ≠ 隔离,而是可控协作
真正的封装不是把数据锁死,而是明确边界、暴露契约。ColourPalette 通过 this.selectedColor 提供了稳定、线程安全(单线程 JS 环境下)的颜色状态契约;CircleTool 作为消费者,只需信任并使用该契约即可。这种设计既满足大学作业对 OOP 和封装的要求,又保持了代码的健壮性与可扩展性——未来若需支持透明度或 HSL 色彩模型,只需升级 ColourPalette 的内部实现,而 CircleTool 无需任何修改。

















