了解Function.call.bind - 逐步

时间:2016-01-15 08:43:55

标签: javascript

一切都以此Question

开头

然后来自@MinusFour的答案

var slice = Function.call.bind(Array.prototype.slice);

我想明白,发生了什么事, 我的好奇心是这个问题。

要实现什么?理解“Function.call.bind”。

相同的

的逐步方法

MDN开始

注意:我在这里使用NodeJS

1)

var adder = new Function('a', 'b', 'return a + b');
console.log(adder(2, 6));

**输出**

8

这是预期的,没什么好看的

2)

这是我们的最终目标,从有界中调用函数myFunc 功能(Function.call.bind(myFunc)

function myFunc(a, b) {
    console.log(arguments.length, a, b, a + b);
}

第3)

var adder = Function(myFunc);
console.log(adder.toString())

输出

function anonymous() { function myFunc(a, b) {   console.log(a + b); } }

预期!上面的代码什么也没做,因为我称之为'匿名', 它没有任何作用。

4)

var adder = Function.call(myFunc);
console.log(adder.toString())

输出

function anonymous() {

}

预期! '.call'调用'Function''this'设置为'myFunc',并且没有任何参数或函数体。所以一个空的匿名函数是输出。现在,我可以"var adder = Function.call(myFunc,myFunc);"从步骤3

创建相同的功能

到目前为止一切顺利

5)

var adder = Function.call.bind(myFunc);
console.log(adder.toString())   
adder(2,6); 

输出

function () { [native code] }
1 6 undefined NaN

此处第一个参数未传递给'myFunc'函数。 对于函数'this'(有界'adder'),这被视为Function.call

现在我明白了(或者我误解了?)直到现在,但是那时候 下面的代码如何运作?

var slice = Function.call.bind(Array.prototype.slice);
function fn(){
    var arr = slice(arguments);
}

在我的情况下,第一个加法器参数被丢弃(或Function.call将其视为'this'),上面的slice会发生同样的情况吗?

无论如何,我想将其作为参考资料

1 个答案:

答案 0 :(得分:2)

我害怕你走错了方向。这一行:

var slice = Function.call.bind(Array.prototype.slice);

永远不会调用Function,也永远不会安排稍后调用它。唯一正在使用的Functioncall属性。 Function可能是ObjectDateRegExp或任何其他功能,或者可能是Function.prototype;无所谓。 Function.prototype本来会更直接,也可能不那么令人困惑。

这有点难以解释,因为它涉及两层处理this,其中this在不同时间是不同的事情:

call函数调用具有特定this值的函数,并将其作为第一个参数,并传递给您的任何其他参数。例如:

function foo(arg) {
    console.log("this.name = " + this.name + ", arg = " + arg);
}
var obj = {name: "bar"};
foo.call(obj, "glarb"); // "this.name = bar, arg = glarb"

在那里,因为我们在call上呼叫foocall呼叫foothis设置为obj并传递"glarb" 1}} argment。

call根据this调用期间的call知道应该调用哪个函数。在foo.callthis期间call设置了foo。这可能令人困惑,所以让我们来看看它:

  • foo.call(obj, "glarb")来电call
    • call看到this = foo,参数obj"glarb"
    • call来电thisfoo):
      • foo看到this = obj和单个参数"glarb"

关于slice,您通常会看到call用于从数组创建数组 - ,如,它不是一个真正的数组:

var divArray = Array.prototype.slice.call(document.querySelectorAll("div"));

var divArray = [].slice.call(document.querySelectorAll("div"));

在那里,我们调用callthis设置为Array.prototype.slice(或[].slice,这是相同的功能)并传入{{1}返回的集合}作为第一个参数。 querySelectorAll调用它看作call的函数,使用其第一个参数this进行该调用,并传递任何其他函数。

这就是this内容的第一层。

this是函数具有的另一个函数,它与bind类似,但不同:call 调用目标函数给定call和参数,this创建并返回 new 函数,如果调用它,它将执行此操作。回到我们的bind示例:

foo

这被称为绑定事物(function foo(arg) { console.log("this.name = " + this.name + ", arg = " + arg); } var obj = {name: "bar"}; var fooWithObjAndGlarb = foo.bind(obj, "glarb"); fooWithObjAndGlarb(); // "this.name = bar, arg = glarb" obj参数)到"glarb"

foo不同,由于call创建了一个新函数,我们可以在以后添加参数:

bind

好的,现在我们已经完成了所有工作。那么你的代码中发生了什么?让我们把它分成几部分:

function foo(arg) {
    console.log("this.name = " + this.name + ", arg = " + arg);
}
var obj = {name: "bar"};
var fooWithObj = foo.bind(obj);
fooWithObj("glarb"); // "this.name = bar, arg = glarb"

// Get a reference to the `call` function from the `call` property // on `Function`. The reason `Function` has a `call` property is that // `Function` is, itself, a function, which means its prototype is // `Function.prototype`, which has `call` on it. var call = Function.call; // Get a reference to the `slice` function from `Array.prototype`'s `slice` property: var rawSlice = Array.prototype.slice; // Create a *bound* copy of `call` that, when called, will call // `call` with `this` set to `rawSlice` var callBoundToSlice = call.bind(rawSlice); 在您的问题中名为callBoundToSlice,但我使用slice来避免混淆。)将callBoundToSlice绑定到rawSlicecall处理的第一层,确定this将看作call的内容。致电this会在callBoundToSlice设置为call时致电this。然后rawSlice将调用它看作callthis)的函数,在调用期间使用其第一个参数作为rawSlice的值({{1}的第二层处理)并传递任何进一步的参数。

所以我们的this来自this的集合现在看起来像这样:

forEach

querySelectorAll返回的收集者传递给callBoundToSlice(document.querySelectorAll("div")).forEach(function(div) { // Each div here }); querySelectorAllcallBoundToSlice调用call作为thisrawSlice调用Array.prototype.slice { {1}}设置为集合。 this使用Array.prototype.slice复制数组。

所有这些都说,使用this将类似数组的对象转换为真正的数组有点过时了。 ES2015引入了Array.from方法,在尚未拥有它的JavaScript引擎上可以shimmed/polyfilled

slice