一切都以此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
会发生同样的情况吗?
无论如何,我想将其作为参考资料
答案 0 :(得分:2)
我害怕你走错了方向。这一行:
var slice = Function.call.bind(Array.prototype.slice);
永远不会调用Function
,也永远不会安排稍后调用它。唯一正在使用的Function
是call
属性。 Function
可能是Object
或Date
或RegExp
或任何其他功能,或者可能是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
上呼叫foo
,call
呼叫foo
,this
设置为obj
并传递"glarb"
1}} argment。
call
根据this
调用期间的call
知道应该调用哪个函数。在foo.call
到this
期间call
设置了foo
。这可能令人困惑,所以让我们来看看它:
foo.call(obj, "glarb")
来电call
:
call
看到this = foo
,参数obj
和"glarb"
call
来电this
(foo
):
foo
看到this = obj
和单个参数"glarb"
关于slice
,您通常会看到call
用于从数组创建数组 - ,如,它不是一个真正的数组:
var divArray = Array.prototype.slice.call(document.querySelectorAll("div"));
或
var divArray = [].slice.call(document.querySelectorAll("div"));
在那里,我们调用call
,this
设置为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
绑定到rawSlice
是call
处理的第一层,确定this
将看作call
的内容。致电this
会在callBoundToSlice
设置为call
时致电this
。然后rawSlice
将调用它看作call
(this
)的函数,在调用期间使用其第一个参数作为rawSlice
的值({{1}的第二层处理)并传递任何进一步的参数。
所以我们的this
来自this
的集合现在看起来像这样:
forEach
将querySelectorAll
返回的收集者传递给callBoundToSlice(document.querySelectorAll("div")).forEach(function(div) {
// Each div here
});
,querySelectorAll
将callBoundToSlice
调用call
作为this
,rawSlice
调用Array.prototype.slice
{ {1}}设置为集合。 this
使用Array.prototype.slice
复制数组。
所有这些都说,使用this
将类似数组的对象转换为真正的数组有点过时了。 ES2015引入了Array.from
方法,在尚未拥有它的JavaScript引擎上可以shimmed/polyfilled:
slice