我正试图深入了解并理解而不是反刍代码。我知道bind, call and apply
通过修改this
指向的内容来更改执行上下文。我不明白的是,这些方法必不可少和/或导致更短的代码。请考虑以下事项:
var person = {
firstName: 'john',
lastName: 'doe',
fullName: function () {
console.log(this.firstName + " " + this.lastName);
}
}
//#1, binder is an html button
$('#binder').click(person.fullName.bind(person)); //john doe
//#2, anonymous is an html button
$('#anonymous').click(function () {
person.fullName(); //john doe
});
//seems strange I see this application a lot 'borrowing' a method
//why?
var o = { firstName: 'obj', lastName: 'ect' };
person.fullName.call(o); //obj ect to console
我想知道一些关于何时使用调用和应用(以及在不使用匿名函数和函数#1之外绑定)的良好实践和/或节省时间的一般范例
答案 0 :(得分:2)
要专注于每个功能必不可少的地方,我会说
apply
在处理可变参数函数时最有用。它允许您将值数组转换为参数列表。
function logwrapper(f){
return function(){
console.log("called");
return f.apply(this, arguments);
}
}
var bar = function(){ ... }
var foo = logwrapper(bar);
bind
在您希望将方法传递到只需要一个函数的代码时最有用。一个常见的例子是settimeout和其他期望回调的函数:
setTimeout(function(){ obj.meth(); }, 100); //handwritten callback
setTimeout(obj.meth.bind(obj), 100); //Function.prototype.bind
setTimeout(bind(obj, "meth"), 100); //Some JS libraries have functions that
//let you write the object only once.
请记住,IE< = 8不支持本机Function.prototype.bind。在这种情况下,您可能需要使用polyfill或helper库。
call
对于借用方法非常有用。如果这对你的特定用例有用或者很大,那么一个非常常见的重要用法就是在arguments
上使用数组方法。由于历史原因,arguments
没有任何常用的数组方法(切片,地图等),因此您需要借用它们:
function myvariadic(x){
var rest = [].slice.call(x, 1);
}
您可能会看到另一个示例是hasOwnProerty方法:
for(k in obj){
if(Object.prototype.hasOwnProperty.call(obj, k)){
....
}
}
这使您可以调用真正的hasOwnProperty方法,即使对象使用自己的hasOwnProperty键对其进行阴影处理。
答案 1 :(得分:1)
这就是说,要了解何时使用call
/ apply
或bind
,您必须了解的是 闭包 ,以及 this
的具体结束。
我在这里使用了广泛的闭包定义。不是您通常会在JavaScript技术聊天中获得的,我们通常会谈论 词汇 闭包。
为了这个小帖子的目的,让我们假设一个闭包将为任何变量(this
包含)提供一个值,它存在于你关注的函数的当前范围之外。
bind
,call
和apply
基本上可以为this
提供值(以及其他一些参数作为选项)。
它只对两件事有用:
稍后再说
this
提供值。例如,传递对方法的引用会丢失与底层对象实例的连接。或者使用类原型函数。或者在事件处理程序的上下文中调用,其中JS已将此设置为捕获事件的DOM元素。
call
只会将this
设置为该特定函数执行的第一个参数的值。
由于在JS中创建对象非常简单,因此您可能希望执行以下操作:
Worker = function ()
{
this.things_done = 0;
}
Worker.prototype = {
do_something: function (count)
{
this.things_done += count;
}
}
var worker= new Worker(); // Worker object
var wanabee_worker = { things_done: 100 }; // classless object
Etvoilà!您刚刚创建了与Worker
没有类关系的东西,但仍然可以使用Worker
方法,因为它已经定义了所有必需的属性。
worker.do_something.call (wanabee_worker, 10);
允许wanabee_worker
借用不相关的对象Worker
的方法。
也可以使用相反的方法:
function reset_work_count ()
{
this.things_done = 0;
}
reset_work_count.call (worker);
这里我们有一个与Worker
没有任何关系的普通函数,除了它使用相同的属性。 call
允许将其应用于Worker
对象。
apply
而言, this
完全相同。唯一的区别是传递其他参数的方式。
bind
将创建一个内部闭包并返回一个新的包装函数,该函数将使用传递给bind
的参数作为this
的值。
典型示例:将事件处理程序绑定到特定对象。
$('#binder').click(person.fullName.bind(person));
在JQuery goo下面,代码最终会做什么
binder.addEventListener ('click', person.fullName.bind(person), false);
如果处理程序被简单地定义为person.fullName
,则会调用它,并将this
设置为捕获事件的DOM元素。
在这种特殊情况下,JS引擎提供的this
的闭包不适合我们的需要,因此我们使用bind
提供另一种选择。
而不是person.fullName.bind(person)
,您可以使用:
function() { person.FullName(); }
除了
bind
是一个内部构造,可以更有效地完成闭包。您还可以想象用于处理事件的对象将由某个代理函数动态分配/计算。在这种情况下,使用bind
将是无用的,因为我们想要的是访问允许我们将lambda对象用作工作类之一的方法。
function event_handler (param)
{
var obj = compute_lambda_obj ();
Worker.prototype.do_something.call (ojb, param);
}