JavaScript中prototype为对象添加属性的误区与正确用法
本文通过谷歌地图应用实例,分析在JavaScript中使用prototype添加属性时常见的误区。重点探讨了直接调用局部变量与使用this关键字的区别,解释了为何直接赋值或错误引用会导致undefined错误,并展示了通过构造函数将局部变量反赋给this对象属性来正确关联原型属性的方法。
代码示例与背景介绍
先列出实现功能所需的全部代码片段(节选)
具体代码如下:
MenuControl.prototype.boxDisplay = false;//是否显示图层选择菜单
MenuControl.prototype.controlUI;
MenuControl.prototype.show = function(){
if(pointControl.boxDisplay){
pointControl.hide();
}
menuBoxDiv.style.display = "";
this.boxDisplay = true;
this.controlUI.style.backgroundColor = '#DDDDDD';
};
MenuControl.prototype.hide = function(){
menuBoxDiv.style.display = "none";
this.boxDisplay = false;
this.controlUI.style.backgroundColor = 'white';
};
//图层选择开关
function MenuControl(controlDiv, map) {
controlDiv.style.padding = '5px';
var controlUI = document.createElement('div');
this.controlUI = controlUI;
controlUI.style.backgroundColor = 'white';
controlUI.style.height = '18px';
controlUI.style.borderStyle = 'solid';
controlUI.style.borderWidth = '1px';
controlUI.style.cursor = 'pointer';
controlUI.style.textAlign = 'center';
controlUI.title = '点击启用菜单';
controlDiv.appendChild(controlUI);
var controlText = document.createElement('div');
controlText.style.fontFamily = 'Arial,sans-serif';
controlText.style.fontSize = '12px';
controlText.style.paddingLeft = '4px';
controlText.style.paddingRight = '4px';
controlText.innerHTML = '<strong>图层选择</strong>';
controlUI.appendChild(controlText);
google.maps.event.addDomListener(controlUI, 'click', function() {
if(menuControl.boxDisplay){
menuControl.hide();
}else{
menuControl.show();
}
});
}
//点开关框体
PointControl.prototype.boxDisplay = false;//是否显示图层选择菜单
PointControl.prototype.controlUI;
PointControl.prototype.show = function(){
if(menuControl.boxDisplay){
menuControl.hide();
}
pointBoxDiv.style.display = "";
this.boxDisplay = true;
this.controlUI.style.backgroundColor = '#DDDDDD';
};
PointControl.prototype.hide = function(){
pointBoxDiv.style.display = "none";
this.boxDisplay = false;
this.controlUI.style.backgroundColor = 'white';
};
function PointControl(controlDiv, map) {
controlDiv.style.padding = '5px';
var controlUI = document.createElement('div');
this.controlUI = controlUI;
controlUI.style.backgroundColor = 'white';
controlUI.style.height = '18px';
controlUI.style.borderStyle = 'solid';
controlUI.style.borderWidth = '1px';
controlUI.style.cursor = 'pointer';
controlUI.style.textAlign = 'center';
controlUI.title = '点击操控点菜单';
controlDiv.appendChild(controlUI);
var controlText = document.createElement('div');
controlText.style.fontFamily = 'Arial,sans-serif';
controlText.style.fontSize = '12px';
controlText.style.paddingLeft = '4px';
controlText.style.paddingRight = '4px';
controlText.innerHTML = '<strong>点</strong>';
controlUI.appendChild(controlText);
google.maps.event.addDomListener(controlUI, 'click', function() {
if(pointControl.boxDisplay){
pointControl.hide();
}else{
pointControl.show();
}
});
}功能需求与初始尝试
开发的是基于谷歌地图的应用,界面右侧有两个div按钮,点击后可展开左侧的div子菜单。
需求如下:
在打开子菜单前,需判断该子菜单是否已处于打开状态;若已打开,则先关闭再打开。
在切换子菜单开关时,对应的按钮颜色需随之改变以反映当前状态。
这就要求在各个按钮的show()方法中操作另一个按钮的属性和方法,以实现联动开关效果。
最初尝试的代码如下:
代码如下:
MenuControl.prototype.controlUI;
MenuControl.prototype.show = function(){
controlUI.style.backgroundColor = '#DDDDDD';//直接调用属性
};
function MenuControl(controlDiv, map) {
controlUI = document.createElement('div');
controlUI.style.backgroundColor = 'white';
}问题排查与解决方案
结果发现,无论点击哪个菜单开关,只有“点”按钮的颜色发生了改变。
原因可能是controlUI被错误地定义为了全局变量,导致引用混乱。
随后尝试修改如下:
代码如下:
MenuControl.prototype.controlUI;
MenuControl.prototype.show = function(){
this.controlUI.style.backgroundColor = '#DDDDDD';//添加this关键字
};
function MenuControl(controlDiv, map) {
controlUI = document.createElement('div');
controlUI.style.backgroundColor = 'white';
}结果依然失败。
经过思考,找到了一种可行的解决方案:
代码如下:
MenuControl.prototype.controlUI.style.backgroundColor = "white";//一上来就给你赋值,看你往哪儿跑
MenuControl.prototype.show = function(){
this.controlUI.style.backgroundColor = '#DDDDDD';
};
function MenuControl(controlDiv, map) {
controlUI = document.createElement('div');
this.controlUI.style.backgroundColor = 'white';
}这样至少会抛出错误信息,提示无法给undefined添加style属性等,从而暴露问题所在。
一度感到绝望,打算给所有属性都添加全局变量,以便调用。
没想到这反而启发了正确的思路。
最终得到了最初那段正确的代码:
代码如下:
MenuControl.prototype.controlUI;//先建立此属性,挖一个坑
MenuControl.prototype.show = function(){
this.controlUI.style.backgroundColor = '#DDDDDD';//使用this关键字调用,实际调用的是this.controlUI对象
};
function MenuControl(controlDiv, map) {
var controlUI = document.createElement('div');//建立局部变量,并正常赋值
this.controlUI = controlUI;//将此局部变量反赋给this对象的属性,达到关联引用
controlUI.style.backgroundColor = 'white';//正常调用引用对象进行操控
}这样就将prototype添加的属性和自身创建的局部变量关联起来,使其可被外部其它对象所调用获取。
成功实现了通过类对象区分同名属性并进行全局调用的目的。
什么时候该用JS构造器:与工厂模式、字面量的选择对比
2026-11-05 16:18:22
推荐几款轻量级JS照片墙开源库及对比
2026-11-05 15:56:19
JavaScript递归写法有哪些常见陷阱及避免方法
2026-11-05 14:53:38
JS数组浅拷贝与深拷贝怎么选?场景与方法总结
2026-11-05 14:41:02
p5.js 中 setup() 和 draw() 函数的执行机制详解
2026-11-05 12:32:38
