关于prototype.js函数绑定代码的解释

发布于 2024-08-29 20:19:26 字数 639 浏览 7 评论 0原文

来自: http://ejohn.org/apps/learn/#2

Function.prototype.bind = function(){
  var fn = this, args = Array.prototype.slice.call(arguments), object = args.shift();
  return function(){
    return fn.apply(object,
      args.concat(Array.prototype.slice.call(arguments)));
  };
};

谁能告诉我为什么需要第二次返回(在 fn.apply 之前)?

另外,谁能解释为什么 args.concat 是必要的?为什么不将其重写为:

fn.apply(object, args)

而不是

return fn.apply(object,
          args.concat(Array.prototype.slice.call(arguments)));

From: http://ejohn.org/apps/learn/#2

Function.prototype.bind = function(){
  var fn = this, args = Array.prototype.slice.call(arguments), object = args.shift();
  return function(){
    return fn.apply(object,
      args.concat(Array.prototype.slice.call(arguments)));
  };
};

Can anyone tell me why the second return is necessary (before fn.apply)?

Also, can anyone explain why args.concat is necessary? Why wouldn't it be re-written as:

fn.apply(object, args)

instead of

return fn.apply(object,
          args.concat(Array.prototype.slice.call(arguments)));

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

拿命拼未来 2024-09-05 20:19:27

第二次返回是必要的,因为否则我们将丢失绑定函数的任何返回值。

您可能已经知道这一点,但提一下也没什么坏处。如果我们不将 fn.apply 包装在另一个函数中,那么我们将直接调用函数 fn ,这是次优的,如 bind只应该设置执行上下文(this 在函数内部引用什么),而不是调用它。

可以通过调用 JavaScript 方法的 callapply 方法来调用它们。这是一个小例子:

function example() {
    alert("useless example");
}

example.apply() // or example.call(), alerts "useless example";

Prototype 的 bind() 中的外部函数应该像绑定函数周围的不可见包装器一样工作。因此,传递给包装器的任何参数也应该传递给绑定函数,并且它必须返回绑定函数返回的任何值,这就是 return 语句存在的原因。

在 fn.apply 中执行 args.concat 的原因是不同的,并且它不是可选的。 Prototype 中的 bind 允许您将参数添加到绑定函数中。

args 表示我们在函数上调用 bind 时传递的参数。 arguments 表示我们调用绑定函数时传递的参数。我们基本上在那里连接两个数组。

从上面的例子来看:

var obj = { x: 'prop x' };
var boundExample = example.bind(obj, 12, 23); // args => 12, 23
boundExample(36, 49); // arguments => 36, 49

// arguments that our example() function receives => 12, 23, 36, 49

The second return is necessary because otherwise we will lose any return value from the bound function.

You may already know this, but doesn't hurt to mention. If we don't wrap fn.apply inside another function, then we are directly calling the function fn which is sub-optimal, as bind is only supposed to set the execution context (what should this refer to inside the function), and not invoke it.

Javascript methods can be invoked by calling the call or apply method on them. Here's a small example:

function example() {
    alert("useless example");
}

example.apply() // or example.call(), alerts "useless example";

The outer function in Prototype's bind() is supposed to work like an invisible wrapper around the bound function. Thus any arguments that are passed to the wrapper should be passed to the bound function as well, and it must return any value that the bound function returns, which is why the return statement is there.

The reason for doing args.concat inside fn.apply is different and it's not optional. bind in Prototype allows you to prepend arguments to the bound function.

args represents the arguments that were passed when we called bind on the function. arguments represents the arguments that were passed when we called the bound function. We're basically concatenating two arrays there.

From the above example:

var obj = { x: 'prop x' };
var boundExample = example.bind(obj, 12, 23); // args => 12, 23
boundExample(36, 49); // arguments => 36, 49

// arguments that our example() function receives => 12, 23, 36, 49
愁杀 2024-09-05 20:19:27

旧帖子,但较新的方法;)

Function.prototype.bind = function(){
    var fn = this, 
    context = arguments[0], 
    args = Array.prototype.slice.call(arguments, 1);
    return function(){
        return fn.apply(context, args.concat([].slice.call(arguments)));
    }
}

obj = {'abc':'x'};
var func = function() {
  console.log(arguments);
  alert(this.abc);
}
var x = func.bind(obj);

console.log(x(1,2,3));

这是一个很好的解释示例。运行它并检查控制台日志。
然后修改代码以省略

[].slice.call(arguments)

您将看到 x(1,2,3) 执行的 console.log 不再显示参数。 这是因为参数对象是所有函数中的局部变量。
这可能听起来有点令人困惑,但它的意思基本上是:

var x = func.bind(obj,1,2,3);

在内部返回此函数:

function() {
    return fn.apply(obj, [1,2,3].concat([].slice.call(arguments)));
}

因此它更像是该函数的模板。

当您现在像这样运行它时:

x(4,5,6)

这将运行:

fn.apply(obj, [1,2,3].concat([].slice.call(arguments)))

使用特殊参数 object = {0:4,1:5,2:6} ,可以使用 [].slice.call 将其转换为数组
其中参数是本地对象,在函数调用期间自动分配。

Old post but a newer approach ;)

Function.prototype.bind = function(){
    var fn = this, 
    context = arguments[0], 
    args = Array.prototype.slice.call(arguments, 1);
    return function(){
        return fn.apply(context, args.concat([].slice.call(arguments)));
    }
}

obj = {'abc':'x'};
var func = function() {
  console.log(arguments);
  alert(this.abc);
}
var x = func.bind(obj);

console.log(x(1,2,3));

This is a very good example to explain. Run it and check the console log.
Then modify the code to leave out

[].slice.call(arguments)

You will see that the console.log of the execution of x(1,2,3) is not showing up the arguments anymore. This is because the arguments objects is a local variable within all functions.
That might sound a bit confusing, but what it means is basically:

var x = func.bind(obj,1,2,3);

Returns this function internally:

function() {
    return fn.apply(obj, [1,2,3].concat([].slice.call(arguments)));
}

So it is more of a template for the function.

When you do now run it like:

x(4,5,6)

This will be ran:

fn.apply(obj, [1,2,3].concat([].slice.call(arguments)))

with a special arguments object = {0:4,1:5,2:6} , which can be converted into an array using [].slice.call
where arguments is a local object, that is automatically beeing assigned during the invokation of the function.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文