如何在JavaScript原型中添加事件处理函数?点击失效问题排查
嘿,我来帮你拆解下遇到的两个问题:
1. 点击事件不工作的核心原因:this的指向问题
在你的点击事件回调函数里,this的指向并不是你创建的Shape实例,而是触发点击事件的那个DOM元素(也就是<div id="shape-div"></div>)。所以当你在回调里写this.shapeElement时,这个this根本没有shapeElement这个属性,自然就无法执行隐藏操作啦。
解决方法有三种,选你顺手的就行:
方法一:用ES6箭头函数(推荐,写法简洁)
箭头函数不会绑定自己的this,它会继承外层作用域的this(也就是Shape实例):this.shapeElement.click(() => { this.shapeElement.css("display", "none"); });方法二:提前保存
this的引用
在回调外面把this存到一个变量里(比如that或者self),回调里用这个变量访问实例:const that = this; this.shapeElement.click(function() { that.shapeElement.css("display", "none"); });方法三:用jQuery的
$.proxy绑定this
通过$.proxy强制把回调的this绑定到Shape实例上:this.shapeElement.click($.proxy(function() { this.shapeElement.css("display", "none"); }, this));
另外还有个小坑:你在Shape构造函数里已经调用了this.draw(),但在$(document).ready里又调用了一次square.draw(),这会导致页面上生成两个形状!记得去掉ready里重复的square.draw()哦。
2. 从过程式转OOP觉得难,正常吗?
太正常了!完全不用焦虑😉。过程式编程是按步骤写“做什么”,而OOP需要你切换到“谁来做”的思维,要理解封装、实例化、this绑定这些新概念,刚开始肯定会觉得原来简单的操作变复杂了。多写几个小项目,慢慢习惯这种思维模式之后,你会发现OOP在复用性、代码组织上的优势的。
修正后的完整代码
这里用箭头函数的版本给你做了修正,还顺便把循环里的i改成了let,避免全局变量污染:
function Shape () { this.x = Math.floor(Math.random()*1200); this.y = Math.floor(Math.random()*500); this.draw(); } Shape.prototype.draw = function() { var shapeHtml = '<div id="shape-div"></div>'; var widthAndHeight = Math.floor(Math.random()*400); this.shapeElement = $(shapeHtml); this.shapeElement.css({ 'width': widthAndHeight, 'height': widthAndHeight, position: "relative", left: this.x, top: this.y }); this.shapeElement.css({ display: "block" }); // 箭头函数解决this指向问题 this.shapeElement.click(() => { this.shapeElement.css("display", "none"); }); $("body").append(this.shapeElement); } "use strict"; Shape.prototype.colour = function() { var colours = '0123456789ABCDEF'.split(''); var randomColour = "#"; for (let i = 0; i < 6; i++) { randomColour+=colours[Math.floor(Math.random()*16)]; }; this.shapeElement.css({backgroundColor: randomColour}); } $(document).ready(function() { var square = new Shape(); // 去掉重复的draw调用 square.colour(); })
内容的提问来源于stack exchange,提问作者Michael Alexander

