.bind()之美
我并不是 Prototype JavaScript framework 的忠实粉丝,但我对它的总体代码质量印象深刻。具体而言,它为Function对象增加一个简洁的补充,对我管理函数呼叫执行后的上下文产生了极大的正面影响:bind跟call一样执行相同的常见任务,改变函数执行的上下文。不同之处在于bind返回的是函数引用可以备用,而不是call的立即执行而产生的最终结果。
如果需要简化一下bind函数以抓住概念的重点,我们可以先把它插进前面讨论的乘积例子中去,看它究竟是如何工作的。这是一个相当优雅的解决方案:
<script type="text/javascript"> var first_object = { num: 42 }; var second_object = { num: 24 };
function multiply(mult) { return this.num * mult; }
Function.prototype.bind = function(obj) { var method = this, temp = function() { return method.apply(obj, arguments); };
return temp; }
var first_multiply = multiply.bind(first_object); first_multiply(5); // 返回 42 * 5
var second_multiply = multiply.bind(second_object); second_multiply(5); // 返回 24 * 5 </script>
首先,我们定义了first_object, second_object和multiply函数,一如既往。细心处理这些后,我们继续为Function对象的 prototype 定义一个bind方法,这样的话,我们程序里的函数都有一个bind方法可用。当执行multiply.bind(first_object)时,JavaScript为bind方法创建一个运行上下文,把this置为multiply函数的引用,并把第一个参数obj置为first_object的引用。目前为止,一切皆顺。
这个解决方案的真正天才之处在于method的创建,置为this的引用所指(即multiply函数自身)。当下一行的匿名函数被创建,method通过它的作用域链访问,obj亦然(不要在此使用this, 因为新创建的函数执行后,this会被新的、局部的上下文覆盖)。这个this的别名让apply执行multiply函数成为可能,而传递obj则确保上下文的正确。用计算机科学的话说,temp是一个 闭包(closure),它可以保证,需要在first_object的上下文中执行multiply,bind呼叫的最终返回可以用在任何的上下文中。
这才是前面说到的事件处理函数和setTimeout情形所真正需要的。以下代码完全解决了这些问题,绑定deep_thought.ask_question方法到deep_thought的上下文中,因此能在任何事件触发时都能正确运行:
function addhandler() { var deep_thought = new BigComputer(42), the_button = document.getElementById('thebutton');
the_button.onclick = deep_thought.ask_question.bind(deep_thought); }
漂亮。
本文链接:http://www.blueidea.com/tech/web/2007/4855.asp
出处:Realazy
责任编辑:moby
上一页 JavaScript 中的作用域 [3] 下一页
◎进入论坛网页制作、WEB标准化版块参加讨论,我还想发表评论。
|