解决JS(jQuery)中blur触发函数this指针指向问题(函数作用域问题)
昨晚在写JS的时候(基于jQuery)一直纠结这么一个问题,不太好表述清楚,所以这篇文章的标题也怪怪的。大致状况如下:
/* *定义一个表单类,里面成员变量有各个inputs的对象集合 *各个inputs绑定blur事件用来触发表单输入验证 *验证用的函数封装在prototype中,属于成员函数 */ function UserForm(){ //...这里获取表单和inputs this.inputs.blur(this.validate); } UserForm.prototype = { setStatus: function(){ //用来设置表单状态,表示填写进度用 }, validate: function(){ //...省略无关内容 //这里获取当前触发了blur事件的input对象 $input = $(this); //这里用来调用成员函数setStatus this.setStatus(1); } }
代码如上,问题就出在this指针上面。当我在构造函数UserForm()里面使用this.elements定义各个成员变量的时候,这里的this指针会指向我们的UserForm对象,在成员函数validate()里面正常情况下也可以使用this.fun()的方式来调用其他公有函数。但是,我在构造函数中调用validate()函数的时候使用了jQuery的blur()函数来调用,那么这时候的this指针就指向了当前失去焦点触发blur的input元素,则无法再使用this.fun()的方式来调用其他公有函数。
解决方法1:
既然是this指针的问题,那么我们不在类里面封装使用blur方法调用,我到类外先获取inputs然后给input绑定一个blur函数,再把当前input对象传给validate就能解决。
function UserForm(){ //...这里获取表单和inputs this.inputs.blur(this.validate); } UserForm.prototype = { setStatus: function(){ //用来设置表单状态,表示填写进度用 }, //修改validate方法,改为把当前input对象作为参数传进来 validate: function($input){ //...省略无关内容 <del datetime="2011-06-18T09:15:35+00:00">//这里获取当前触发了blur事件的input对象 $input = $(this);</del> //这里用来调用成员函数setStatus this.setStatus(1); } } $(document).ready(function(){ var loginForm = new UserForm('#UserLoginForm','#signUp'); var inputs = $('#UserLoginForm input'); $inputs.blur(function(){ loginForm.validate($(this)); }); });
但这是非常不可取的,我封装成类本来就是想把逻辑处理的内容都在类里面完成,这样做就变成我把处理过程都放到类外去做了,那我的类不就成废物一个了么?
于是……
解决方法二:
纠结好久我到推上发了发牢骚,结果 @rainux 大大粗线鸟,告诉我一个神奇的$.proxy(this.handler, this)函数,是jQuery的函数,用来改变函数作用域,把handler的作用域绑定在this上面。如果写在blur函数里面,那么就是element.blur($.proxy(this.handler, this)),如此,validate函数中的this指针就仍然是指向UserForm类,就可以顺利调用成员函数了。
function UserForm(){ //...这里获取表单和inputs this.inputs.blur($.proxy(this.validate, this)); } UserForm.prototype = { setStatus: function(){ //用来设置表单状态,表示填写进度用 }, validate: function(){ //...省略无关内容 //这里用来调用成员函数setStatus this.setStatus(1); } } $(document).ready(function(){ var loginForm = new UserForm('#UserLoginForm','#signUp'); });
但是还有一个问题,我改变了this指针使得我的成员函数可以使用this.foo的方式调用没错但是我要怎么确定当前哪个input触发了该函数呢?
再试了半天纠结了好久之后给出最终解决方法:使用event.currentTarget。(依然感谢 @rainux 大大的帮助)
最终解决方法:
function UserForm(){ //...这里获取表单和inputs this.inputs.blur($.proxy(this.validate, this)); } UserForm.prototype = { setStatus: function(){ //用来设置表单状态,表示填写进度用 }, //这里把event作为参数传入 validate: function(event){ //...省略无关内容 //使用event.currentTarget获取当前DOM对象,为了方便我把它转化为jQuery对象 $input = $(document.getElementById(event.currentTarget.id)); //这里用来调用成员函数setStatus this.setStatus(1); } } $(document).ready(function(){ var loginForm = new UserForm('#UserLoginForm','#signUp'); });
总结
在解决这些问题的时候走了挺多弯路,说明之前写的代码不够多,看的文档不够仔细,其实click()、blur()等这些事件方法都是可以直接传参数什么的,而不是我一直以为的必须使用匿名函数的方法,这些技巧都挺有用的,所以,多看官方文档有好处的T_T


最近回复