简体   繁体   English

Function.prototype.call.bind 是如何工作的?

[英]How does Function.prototype.call.bind work?

I am having some trouble wrapping my head around this function:我在思考这个 function 时遇到了一些麻烦:

var toStr = Function.prototype.call.bind( Object.prototype.toString );
toStr([]) // [object Array]​​​​​​​​​​​​​​​​​​​​​​​​​​​

How does this function accept an argument as seen in line 2?如第 2 行所示,这个 function 如何接受参数?

Well,好,

  • Function.prototype.call references the "call" function, which is used to invoke functions with chosen this values; Function.prototype.call引用了“call”函数,用于调用具有选定this值的函数;
  • The subsequent .bind refers to the "bind" function on the Function prototype (remember: "call" is a function too), which returns a new function that will always have this set to the passed-in argument.随后的.bind指的是 Function 原型上的“bind”函数(记住:“call”也是一个函数),它返回一个新函数,该函数总是将this设置为传入的参数。
  • The argument passed to "bind" is the "toString" function on the Object prototype, so the result of that whole expression is a new function that will run the "call" function with this set to the "toString" function.传递给“bind”的参数是对象原型上的“toString”函数,因此整个表达式的结果是一个新函数,它将运行“call”函数,并将this设置为“toString”函数。

The result, therefore, is like this code: Object.prototype.toString.call( param ) .因此,结果就像这样的代码: Object.prototype.toString.call( param ) Then, the "console.log" call passes that function an array, and there you have it.然后,“console.log”调用将该函数传递给一个数组,您就拥有了它。

edit Note that Object.prototype.toString.call( param ) is like param.toString() really, when "param" is an object.编辑注意Object.prototype.toString.call( param )实际上就像param.toString() ,当“param”是一个对象时。 When it's not, then the semantics of the "call" function are to turn it into one in the normal ways JavaScript does that (numbers -> Number, strings -> String, etc).如果不是,则“调用”函数的语义是以 JavaScript 的正常方式(数字 -> 数字、字符串 -> 字符串等)将其转换为一个。

edit, 24 May2016 — That last sentence above is not accurate with ES2015.编辑,2016年 5月 24 日— 上面的最后一句话在 ES2015 中不准确。 New JavaScript runtimes do not "autobox" primitive types when those are involved with a function call as a this value.当作为this值参与函数调用时,新的 JavaScript 运行时不会“自动装箱”原始类型。

I assume you already know what .call and .bind do我假设你已经知道.call.bind做什么的

toStr is now a function that essentially does: toStr现在是一个函数,它本质上是:

function toStr( obj ) {
    return Function.prototype.call.call( Object.prototype.toString, obj );
}

IE it .call s the .call function with context argument set to the .toString function. IE it .call.call函数,上下文参数设置为.toString函数。 Normally that part is already taken care of because you normally use .call as a property of some function which sets the function as the context for the .call .通常这部分已经被处理了,因为您通常使用.call作为某个函数的属性,该函数将函数设置为.call的上下文。

The two lines of code are a function definition and then execution call of that definition with an empty array passed inside.这两行代码是一个函数定义,然后执行调用该定义并传入一个空数组。 The complexity lies in interpreting what 'this' will point to and why.复杂性在于解释“this”将指向什么以及为什么。

To help deduce the value of this I copied content from two links below to MDN's definitions of call and bind.为了帮助推断这个值,我将下面两个链接中的内容复制到 MDN 的调用和绑定定义中。

The bind () function creates a new function (a bound function) with the same function body as the function it is being called on (the bound function's target function) with the this value bound to the first argument of bind(). bind () 函数创建一个新函数(绑定函数),其函数体与调用它的函数(绑定函数的目标函数)相同,并将 this 值绑定到 bind() 的第一个参数。 Your code looks similar to a 'shortcut function' described on the bind page.您的代码看起来类似于绑定页面上描述的“快捷方式功能”。

var unboundSlice = Array.prototype.slice; // same as "slice" in the previous example
var slice = Function.prototype.call.bind(unboundSlice);

// ... // ...

slice(arguments);切片(参数);

With call , you can assign a different this object when calling an existing function.使用call ,您可以在调用现有函数时分配不同的 this 对象。 this refers to the current object, the calling object.With call, you can write a method once and then inherit it in another object, without having to rewrite the method for the new object. this 指的是当前对象,调用对象。有了call,你可以编写一次方法,然后在另一个对象中继承它,而不必为新对象重写方法。

When toStr is called it passes in an array to bind, of which the this pointer is bound.当 toStr 被调用时,它传入一个要绑定的数组,其中绑定了 this 指针。 With bind(), this can be simplified.使用 bind(),这可以简化。

toStr() is a bound function to the call() function of Function.prototype, with the this value set to the toStr() function of Array.prototype. This means that additional call() calls can be eliminated toStr() is a bound function to the call() function of Function.prototype, with the this value set to the toStr() function of Array.prototype. This means that additional call() calls can be eliminated . toStr() is a bound function to the call() function of Function.prototype, with the this value set to the toStr() function of Array.prototype. This means that additional call() calls can be eliminated

In essence, it looks like a shortcut function override to the toString method.本质上,它看起来像是 toString 方法的快捷函数覆盖。

bind() - Creates a new function that, when called, itself calls this function in the context of the provided this value, with a given sequence of arguments preceding any provided when the new function was called. bind() - 创建一个新函数,当被调用时,它自己在提供的 this 值的上下文中调用这个函数,在调用新函数时提供的任何参数之前都有给定的参数序列。

Read this documentation for more information about bind() in JavaScript 阅读此文档以了解有关 JavaScript 中 bind() 的更多信息

Angular example:角度示例:

Parent component where we have a defined function and bind it to an object:父组件,我们在其中定义了一个函数并将其绑定到一个对象:

public callback: object;

constructor() {
    this.callback= this.myFunction.bind(this);
}

public myFunction($event: any) {
    // Do something with $event ...
}

(Parent html) passing the binded object to child component: (父 html)将绑定对象传递给子组件:

<child-component (callbackFunction)="callback($event)"></child-component>

Child component that receives the object that is bind to the parent function:接收绑定到父函数的对象的子组件:

@Output() callbackFunction: EventEmitter<object> = new EventEmitter<object>();

public childFunction() {
    ...
    this.callbackFunction.emit({ message: 'Hello!' });
    ...
}

JS to English translation - JS到英文翻译——

var toStr = Function.prototype.call.bind( Object.prototype.toString ); var toStr = Function.prototype.call.bind( Object.prototype.toString );

The bind creates a new call function of Object.prototype.toString . bind创建了一个新的Object.prototype.toString call函数。

Now you can call this new function with any context which will just be applied to Object.prototype.toString .现在,您可以使用任何仅应用于Object.prototype.toString上下文来调用这个新函数。

Like this:像这样:

toStr([]) // [object Array]​​​​​​​​​​​​​​​​​​​​​​​​​

Why not just calling Object.prototype.toString.call([]) ??为什么不直接调用Object.prototype.toString.call([]) ??

Answer:回答:

Of course, you could.当然,你可以。 But the OPs method creates a dedicated and de-methodized function just for this purpose.但是 OPs 方法只是为此目的创建了一个专用的和非方法化的函数。

This really is called demethodizing.这真的被称为去方法化。

You could do :你可以这样做:

var toStr = Object.prototype.toString.call([]);

Problem with this is : call executes instantly.问题是:调用立即执行。 What you want is to delay the execution of call.你想要的是延迟调用的执行。

*As function is an object too in Javascript, you can use any function as the first argument in ' call ' instead of passing an object as 1st argument.*Also, you can use the dot on call like on any object. *由于函数在 Javascript 中也是一个对象,您可以使用任何函数作为“调用”中的第一个参数,而不是将对象作为第一个参数传递。*此外,您可以像在任何对象上一样使用调用点。

Function.prototype.call.bind( Object.prototype.toString ) , makes a copy of the call function with it's ' this ' sets to Object.prototype.toString . Function.prototype.call.bind( Object.prototype.toString ) ,制作调用函数的副本,将它的“ this ”设置为Object.prototype.toString You hold this new copy of call function in 'toStr'.您将这个新的调用函数副本保存在“toStr”中。

var toStr = Function.prototype.call.bind( Object.prototype.toString );

Now you can executes this new copy of call any time you need without the need of setting 'this' as it's 'this' is already bind to Object.prototype.toString .现在您可以随时执行这个新的 call 副本,而无需设置 'this',因为它的 'this' 已经绑定到 Object.prototype.toString 。

  1. This should make sense to you这对你来说应该是有意义的
Object.prototype.toString.call([]) //work well
  1. You think this form is too long and cumbersome and you want to simplify it?你觉得这个表格太长太麻烦,想简化一下? This makes it easier to use later:这使得以后使用起来更容易:
const toStr = Object.prototype.toString.call
toStr([]) // unfortunately, this does not work
  1. You need to use bind to correct where this points to.您需要使用bind来更正this指向的位置。
const toStr = Object.prototype.toString.call.bind(Object.prototype.toString)
toStr([]) //work well
  1. Object.prototype.toString.call is just the same as Function.prototype.call Object.prototype.toString.callFunction.prototype.call相同
const toStr = Function.prototype.call.bind(Object.prototype.toString)
toStr([]) //done

summary概括

function f(){console.log(this, arguments)}

f.call is just the same as Function.prototype.call.bind(f) f.callFunction.prototype.call.bind(f)相同

f.call(1,2,3) is just the same as Function.prototype.call.bind(f,1)(2,3) f.call(1,2,3)Function.prototype.call.bind(f,1)(2,3)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM