了解 Function.call.bind - 循序渐进
Understanding Function.call.bind - step-by-step
一切都从这个问题开始
然后是@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'
函数。这被视为函数'adder'
(有界Function.call
)的'this'
?
明白了(或者我误解了?)直到现在,但是那时下面的代码是如何工作的?
var slice = Function.call.bind(Array.prototype.slice);
function fn(){
var arr = slice(arguments);
}
在我的情况下,adder 的第一个参数被丢弃(或者Function.call
认为它是'this'
的),上面的slice
也应该发生同样的情况,对吗?
无论如何,我想记录下来以供参考
怕你走错了方向。这一行:
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"
在那里,因为我们在foo
上打电话给call
,call
打电话给foo
,this
设置为obj
并传递"glarb"
。
call
根据call
调用期间this
知道它应该调用什么函数。 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
,这是相同的函数),并将 querySelectorAll
返回的集合作为第一个参数传入。 call
调用它认为this
的函数,使用它的第一个参数作为该调用的this
,并传递任何其他参数。
所以这是第一层this
的东西。
bind
是函数具有的另一个函数,它与call
相似但不同:call
使用给定的this
和参数调用目标函数,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
)的函数,使用其第一个参数作为调用期间this
的值(this
处理的第二层)并传递任何进一步的参数。
因此,我们的forEach
包含来自querySelectorAll
的集合现在看起来像这样:
callBoundToSlice(document.querySelectorAll("div")).forEach(function(div) {
// Each div here
});
这会将querySelectorAll
返回的集合传递到callBoundToSlice
, 调用 call
this
作为rawSlice
,调用Array.prototype.slice
集合设置this
。 Array.prototype.slice
使用this
来复制数组。
综上所述,使用 slice
将类似数组的对象转换为真正的数组有点过时了。ES2015 引入了 Array.from
方法,该方法可以在还没有它的 JavaScript 引擎上进行填充/填充:
var divArray = Array.from(document.querySelectorAll("div"));
- 直接在函数声明上使用function.prototype.bind
- 显示&作为&在jsp中使用angularjs而不使用ng-bind-html
- 如何使jQuery的“bind”或“on”事件处理程序幂等
- Replacing jQuery.bind with jQuery.on
- 无法使用.bind更改分配给此对象的值
- 你什么时候用_.bind和_.bindAll
- jQuery change()和bind(“change”)不起作用
- Angular 1.4解析ng-bind-html的内容
- Javascript:函数bind.click&对于每个复选框
- requestAnimationFrame的Function.prototype.bind导致属性不可读
- jQuery.bind或.on习惯于绑定到新记录
- 如何创建自定义属性以添加if.bind
- Vue.js-插值错误-如何将样式修改为v-bind:style
- clearInterval.bind()不能作为传递到addEventListener的参数
- 蓝鸟承诺的困难.bind()
- JSHint”;可能存在严重违规行为"当使用“bind”时
- 通过fn.apply或fn.bind将函数传递给setTimeout
- .bind()无法设置cookie
- 如何防止bind在使用async.series时更改node.js中的原始对象
- 了解 Function.call.bind - 循序渐进