【js基础】javascript中的apply() call() bind() 方法是javascript专业职员的根基[译]

原文:javascriptissexy.com/javascript-apply-call-and-bind-methods-are-essential-for-javascript-professionals/#

Prerequisite:
— Understand JavaScript’s “this” With Ease, and Master It.
— JavaScript Objects
— Understand JavaScript Closures
(This is an intermediate to advanced topic)

先决条件:

  1. 自在领悟javascript的this,并会选取他;
  2. javascript的对象;
  3. 了然javascript中的闭包(closures)
    (那是一个中路到高档的宗旨)

Functions are objects in JavaScript, as you should know by now, if you
have read any of the prerequisite articles. And as objects, functions
have methods, including the powerful Apply, Call, and Bind methods. On
the one hand, Apply and Call are nearly identical and are frequently
used in JavaScript for borrowing methods and for setting the this value
explicitly. We also use Apply for variable-arity functions; you will
learn more about this in a bit.

(在javascript中,函数也是目的的一种,如若你读过局部关于javascript的功底小说,现在您应有了然,作为对象,函数有诸多方法,包涵强大的apply()、
call()、 以及 bind() 方法。一方面,apply() 和 call()
大约相同,而且在javascript中借调方法时和浮现的装置 this
的值时是反复的应用。大家还运用apply()在 variable-arity
函数上,你就要学习更加多在那点上。)

On the other hand, we use Bind for setting the this value in methods and
for currying functions.

一头,我们应用bind() 来安装 方法里的this 的值 来操作方法。

We will discuss every scenario in which we use these three methods in
JavaScript. While Apply and Call come with ECMAScript 3 (available on IE
6, 7, 8, and modern browsers), ECMAScript 5 (available on only modern
browsers) added the Bind method. These 3 Function methods are workhorses
and sometimes you absolutely need one of them. Let’s begin with the Bind
method.

大家将会谈论那七个法子在javascript用到的每一种方案情景。 apply()
、call() 方法从es3就用了(在IE 6 7 8
和当代浏览器中都有效),bind()方法是在es5才进入的主意(仅仅在现代浏览器中一蹴而就),那多少个函数方法都是工作马(首要的),有时你肯定会要求(用到)他们内部的他们一个,让大家初始攻读bind()
方法吧。

bind()

We use the Bind () method primarily to call a function with the this
value set explicitly. It other words, bind () allows us to easily set
which specific object will be bound to this when a function or method is
invoked.

俺们接纳bind()方法首假若显示的装置调用函数的this 值,换句话说,
在一个函数或者措施被调用时,bind()方法允许大家很不难的
将某个具体的对象绑定到这些函数或者措施上;

This might seem relatively trivial, but often the this value in methods
and functions must be set explicitly when you need a specific object
bound to the function’s this value.

本条可能看上去比较麻烦,可是你平日索要把一个现实的目的绑定到某个(调用)函数的this值上,那么那一个函数方法里面的this
值就亟须显性的装置。

The need for bind usually occurs when we use the this keyword in a
method and we call that method from a receiver object; in such cases,
sometimes this is not bound to the object that we expect it to be bound
to, resulting in errors in our applications. Don’t worry if you don’t
fully comprehend the preceding sentence. It will become clear like
teardrop in a moment.

当大家在格局中利用this关键字时而且我们从一个承受的靶子调用方法时,寻常会有bind
的急需(应用场景);在那种情景下,有时,大家盼望方法中的this绑定到这几个目标但却从未绑定,从而造成大家应用程序的荒唐。假如您无法一心知晓前边的语句,也休想操心。一会儿,他将像泪水一样清晰。

Before we look at the code for this section, we should understand the
this keyword in JavaScript. If you don’t already understand this in
JavaScript, read my article, Understand JavaScript’s “this” With
Clarity, and Master It. If you don’t understand this well, you will have
trouble understanding some of the concepts discussed below. In fact,
many of the concepts regarding setting the “this” value that I discuss
in this article I also discussed in the Understand JavaScript’s “this”
article.

在大家看这一有些的代码时,大家应当清楚 this
关键字,假诺你还尚无精通javascript中的this,
请读这篇小说,倘诺您知道好this,
你将很难明白下边研究的定义,事实上,那篇文章我要研讨的有关设置 this
值的定义,我已经在《Understand JavaScript’s “this”
article》这篇小说中钻探过了。

JavaScript’s Bind Allows Us to Set the this Value on Methods

职能一:设置方法的this值

When the button below is clicked, the text field is populated with a
random name.

当点击上面的按钮时,文本字段会被填充一个肆意名称。

//            <button>Get Random Person</button>​
​//        <input type="text">​
​
​
​var user = {
    data:[
        {name:"T. Woods", age:37},
        {name:"P. Mickelson", age:43}
    ],
    clickHandler:function (event) {
        var randomNum = ((Math.random () * 2 | 0) + 1) - 1; // random number between 0 and 1​
​
        // This line is adding a random person from the data array to the text field​
        $ ("input").val (this.data[randomNum].name + " " + this.data[randomNum].age);
    }
}
​
​// Assign an eventHandler to the button's click event​
$ ("button").click (user.clickHandler);

When you click the button, you get an error because this in the
clickHandler () method is bound to the button HTML element, since that
is the object that the clickHandler method is executed on.

当您点击按钮时,你会拿走一个荒谬,因为this 在 clickHandler()
方法中绑定的是 button 对象 ,button 对象是 clickHandler
方法在推行时的目的。

This particular problem is quite common in JavaScript, and JavaScript
frameworks like Backbone.js and libraries like jQuery automatically do
the bindings for us, so that this is always bound to the object we
expect it to be bound to.

以此特其他难题在javascript中是一对一常见的,在javascript的框架如Backbone.js
和 库 像 Jquery 自动为大家做绑定,由此 this 总是
绑定到大家盼望绑定的目的上。

To fix the problem in the preceding example, we can use the bind method
thus:
Instead of this line:

为了化解眼前例子中的难点,大家得以行使 bind 方法 如下 代替下边这一行

 $ ("button").click (user.clickHandler);

We simply have to bind the clickHandler method to the user object like
this:
我们只要求 把 clickHandler 方法 绑定到 user 对象上 像那样:

 $ ("button").click (user.clickHandler.bind (user));

Consider this other way to fix the this value: You can pass an anonymous
callback function to the click () method and jQuery will bind this
inside the anonymous function to the button object.
设想那标题其余的艺术去解决 this
值:你可以将一个匿名回调函数传递给click()方法,并且jQuery将那么些匿名函数绑定到该按钮对象。

Because ECMAScript 5 introduced the Bind method, it (Bind) is
unavailable in IE < 9 and Firefox 3.x. Include this Bind
implementation in your code, if you are targeting older browsers:

因为bind() 方法时是在es5 才提出的,他在IE 9一下和 火狐 3.x
版本中是不可用的。借使您的对象是老的浏览求,在你的代码落成中引入了bind()
方法(你需要做一些包容性处理):

那段代码挺复杂,是javascript大牛 道格拉斯写的

       // Credit to Douglas Crockford for this bind method​
            if (!Function.prototype.bind) {
                Function.prototype.bind = function (oThis) {
                    if (typeof this !== "function") {
                        // closest thing possible to the ECMAScript 5 internal IsCallable function​
                        throw new TypeError ("Function.prototype.bind - what is trying to be bound is not callable");
                    }
​
                    var aArgs = Array.prototype.slice.call (arguments, 1),
                            fToBind = this,
                            fNOP = function () {
                            },
                            fBound = function () {
                                return fToBind.apply (this instanceof fNOP && oThis
                                        ? this​
                                        : oThis,
                                        aArgs.concat (Array.prototype.slice.call (arguments)));
                            };
​
                    fNOP.prototype = this.prototype;
                    fBound.prototype = new fNOP ();
​
                    return fBound;
                };
            }

Let’s continue with the same example we used above. The this value is
also bound to another object if we assign the method (where this is
defined) to a variable. This demonstrates:
俺们继承运用方面提到的例子,若是我们将艺术赋值给一个变量,this
值也会绑定到另一个目的上。如下所示:

   // This data variable is a global variable​
            var data = [
                {name:"Samantha", age:12},
                {name:"Alexis", age:14}
            ]
​
            var user = {
                // local data variable​
                data    :[
                    {name:"T. Woods", age:37},
                    {name:"P. Mickelson", age:43}
                ],
                showData:function (event) {
                    var randomNum = ((Math.random () * 2 | 0) + 1) - 1; // random number between 0 and 1​
​
                    console.log (this.data[randomNum].name + " " + this.data[randomNum].age);
                }
​
            }
​
            // Assign the showData method of the user object to a variable​
            var showDataVar = user.showData;
​
            showDataVar (); // Samantha 12 (from the global data array, not from the local data array)​

When we execute the showDataVar () function, the values printed to the
console are from the global data array, not the data array in the user
object. This happens because showDataVar () is executed as a global
function and use of this inside showDataVar () is bound to the global
scope, which is the window object in browsers.

当大家举办showDataVar()
函数时,打印出来的值是出自全局变量的数组,不是use对象里面的data数组。这么些(现象)之所以发生,是因为
showDataVar() 是作为一个大局函数执行的,use对象的函数showDataVar()
里面的this 被绑定到全局功能域上,在浏览器里即为window 对象。

Again, we can fix this problem by specifically setting the“this” value
with the bind method:

再一次,我们可以通过使用bind()方法专门设置“this”值来缓解那些难点:

  // Bind the showData method to the user object​
            var showDataVar = user.showData.bind (user);
​
            // Now the we get the value from the user object because the this keyword is bound to the user object​
            showDataVar (); // P. Mickelson 43​

Bind () Allows us to Borrow Methods

功能二:借用方法。

In JavaScript, we can pass functions around, return them, borrow them,
and the like. And the bind () method makes it super easy to borrow
methods.
Here is an example using bind () to borrow a method:
在javascript 中,大家得以传递函数,再次回到函数,借用函数等等。bind()
方法可以让我们很简单的兑现借用方法。

     // Here we have a cars object that does not have a method to print its data to the console​
            var cars = {
                data:[
                    {name:"Honda Accord", age:14},
                    {name:"Tesla Model S", age:2}
                ]
            }
​
            // We can borrow the showData () method from the user object we defined in the last example.​
            // Here we bind the user.showData method to the cars object we just created.​
            cars.showData = user.showData.bind (cars);
            cars.showData (); // Honda Accord 14​

(那里也拔取了闭包。。。)
(其实本质上或者突显设置 user 对象里 this 值)

One problem with this example is that we are adding a new method
(showData) on the cars object and we might not want to do that just to
borrow a method because the cars object might already have a property or
method name showData. We don’t want to overwrite it accidentally. As we
will see in our discussion of Apply and Call below, it is best to borrow
a method using either the Apply or Call method.

那几个事例有一个难点:当大家在小车对象上添加一个新的格局(showData),大家恐怕不想意外地掩盖它,因为小车对象可能早就有一个质量或方法名称showData。可是我们用bind()方法就曾经覆盖了cars对象中的showData方法。其实我们只有想借用一个主意不想覆盖。正如我辈在底下的apply()、call()的研究大校会看出,最好使用Apply或Call方法借用一种办法。

举个例证:

       var data = [
                {name:"Samantha", age:12},
                {name:"Alexis", age:14}
            ];

            var user = {
                data:[
                    {name:"T. Woods", age:37},
                    {name:"P. Mickelson", age:43}
                ],
                showData:function (event) {
                    var randomNum = ((Math.random () * 2 | 0) + 1) - 1; 
                    console.log (this.data[randomNum].name + " " + this.data[randomNum].age);
                }
            };
            // var showDataVar = user.showData;

            // showDataVar (); // Samantha 12 (from the global data array, not from the local data array)​


            var cars = {
                data:[
                    {name:"Honda Accord", age:14},
                    {name:"Tesla Model S", age:2}
                ],

                showData:function(){//注意这里,他会被覆盖
                    console.log("hello guy");
                }

            };

           cars.showData = user.showData.bind(cars);
           cars.showData (); // Honda Accord 14​/Tesla Model S 2

JavaScript’s Bind Allows Us to Curry a Function

功效三:柯里化函数(MDN上称之为Partial Functions[偏函数])

Function Currying, also known as partial function application, is the
use of a function (that accept one or more arguments) that returns a new
function with some of the arguments already set. The function that is
returned has access to the stored arguments and variables of the outer
function. This sounds way more complex than it actually is, so let’s
code.
函数柯里化,也叫做(partial function
application)是用一个函数(接受一个或八个参数),该函数重返一个已经安装的参数的一个新函数。再次来到的函数可以访问存储的外表函数的参数和变量。那听起来比其实更扑朔迷离,所以让我们看代码吧。

Let’s use the bind () method for currying. First we have a simple greet
() function that accepts 3 parameters:

我们来利用bind()方法进行调用。首先大家有一个概括的greet()函数,它承受3个参数:

  function greet (gender, age, name) {
                // if a male, use Mr., else use Ms.
                var salutation = gender === "male" ? "Mr. " : "Ms. ";

                if (age > 25) {
                    return "Hello, " + salutation + name + ".";
                }
                else {
                    return "Hey, " + name + ".";
                }
            }

And we use the bind () method to curry (preset one or more of the
parameters) our greet () function. The first argument of the bind ()
method sets the this value, as we discussed earlier:
俺们使用bind()方法来柯里化(预设一个或多个参数)大家的greet()函数。bind()方法的首个参数设置了
this值,如前所述:

  // So we are passing null because we are not using the "this" keyword in our greet function.
        var greetAnAdultMale = greet.bind (null, "male", 45);

        greetAnAdultMale ("John Hartlove"); // "Hello, Mr. John Hartlove."

        var greetAYoungster = greet.bind (null, "", 16);
        greetAYoungster ("Alex"); // "Hey, Alex."
        greetAYoungster ("Emma Waterloo"); // "Hey, Emma Waterloo."

When we use the bind () method for currying, all the parameters of the
greet () function, except the last (rightmost) argument, are preset. So
it is the rightmost argument that we are changing when we call the new
functions that were curried from the greet () function. Again, I discuss
currying at length in a separate blog post, and you will see how we can
easily create very powerful functions with Currying and Compose, two
Functional JavaScript concepts.

当大家选用bind()方法开展柯里化时,greet()函数的享有参数除了最终一个(最左侧的)参数之外都被预设。当大家调用一个已经从greet()函数柯里化的新函数时,最右侧的函数就会被设置。再度,我在一个独自的博客文章中大书特书柯里化,您将见到哪些通过Currying和Compose三个jsvascript函数作用,分外轻松创立强大的函数。

So, with the bind () method, we can explicitly set the this value for
invoking methods on objects, we can borrow
and copy methods, and assign methods to variable to be executed as
functions. And as outlined in the Currying Tip
earlier,
you can use bind for currying.
汇总,用bind()方法,大家可以显式地设置那this值来调用对象的方法,大家可以借用
和复制方法,并函数执行时的参数也能够是艺术。而且如
前边提到的柯里化部分中所述,
你可以动用bind举办柯里化。

JavaScript’s Apply and Call Methods

apply() 和 call()

The Apply and Call methods are two of the most often used Function
methods in JavaScript, and for good reason: they allow us to borrow
functions and set the this value in function invocation. In addition,
the apply function in particular allows us to execute a function with an
array of parameters, such that each parameter is passed to the function
individually when the function executes—great for variadic functions; a
variadic function takes varying number of arguments, not a set number of
arguments as most functions do.

apply() 和call()
方法在javascript中函数中的使用是不行广阔的。有很好的说辞:他们同意大家借用函数,并安装函调用数的this值。其余,尤其地,apply函数允许大家执行一个参数是数组的函数,使得当函数执行时,每个参数被单独传递给函数

  • 对于可变参数函数是很好的;
    一个可变函数须要分化数额的参数,而不是像超过半数函数一样设置好参数数量。

Set the this value with Apply or Call

作用一:设置this 值

Just as in the bind () example, we can also set the this value when
invoking functions by using the Apply or Call methods. The first
parameter in the call and apply methods set the this value to the object
that the function is invoked upon.

ECMAScript,似乎bind()中的例子一样,当大家经过apply()
call()方法调用函数时,大家也足以设置 函数中 this 值。调用apply()
和call()方法中的第二个参数将this值设置为调用该函数的靶子。

Here is a very quick, illustrative example for starters before we get
into more complex usages of Apply and Call:
在大家进去复杂的施用apply 和call之前,那里有一个开首的事例:

// global variable for demonstration
        var avgScore = "global avgScore";

        //global function
        function avg (arrayOfScores) {
            // Add all the scores and return the total
            var sumOfScores = arrayOfScores.reduce (function (prev, cur, index, array) {
                return prev + cur;
            });

            // The "this" keyword here will be bound to the global object, unless we set the "this" with Call or Apply
            this.avgScore = sumOfScores / arrayOfScores.length;
        }

        var gameController = {
            scores  :[20, 34, 55, 46, 77],
            avgScore:null
        }

        // If we execute the avg function thus, "this" inside the function is bound to the global window object:
        avg (gameController.scores);
        // Proof that the avgScore was set on the global window object
        console.log (window.avgScore); // 46.4
        console.log (gameController.avgScore); // null

        // reset the global avgScore
        avgScore = "global avgScore";
   // To set the "this" value explicitly, so that "this" is bound to the gameController,
        // We use the call () method:
        avg.call (gameController, gameController.scores);

        console.log (window.avgScore); //global avgScore
        console.log (gameController.avgScore); // 46.4

Note that the first argument to call () sets the this value. In the
preceding example, it is set to
the gameController object. The other arguments after the first argument
are passed as parameters to the
avg () function.

注意, avg.call (gameController, gameController.scores);
call()的率先个参数是设置 函数 this 值,在上述的例证,this
指向gameComtroller对象,另一个参数作为avg()函数的参数。

The apply and call methods are almost identical when setting the this
value except that you pass the function parameters to apply () as an
array, while you have to list the parameters individually to pass them
to the call () method. More on this follows. Meanwhile, the apply ()
method also has another feature that the call () method doesn’t have, as
we will soon see.
apply() 和call() 方法在装置 this
值时大约一致。在传递参数方面是例外的,你传递函数的参数给apply()
必须如果数组(后者类数组对象),但是传递参数给call()必须求分头逐个传。(能够参考js高级程序设计第三版117p),更加多关于这点。同时,apply()方法还有另一个特点,即call()方法没有,大家很快就见面到。

Use Call or Apply To Set this in Callback Functions

成效二:在回调函数中安装this值

  // Define an object with some properties and a method​
    // We will later pass the method as a callback function to another function​
    var clientData = {
    id: 094545,
    fullName: "Not Set",
    // setUserName is a method on the clientData object​
    setUserName: function (firstName, lastName)  {
    // this refers to the fullName property in this object​
    this.fullName = firstName + " " + lastName;
    }
    }

 function getUserInput (firstName, lastName, callback, callbackObj) {
            // The use of the Apply method below will set the "this" value to callbackObj​
            callback.apply (callbackObj, [firstName, lastName]);
        }

The Apply method sets the this value to callbackObj. This allows us to
execute the callback function with the this value set explicitly, so the
parameters passed to the callback function will be set on the clientData
object:

apply()方法设置this 值为callbackObj.那允许大家在调用回调函数时白纸黑字的安装
this值。所以传递给回调函数的参数被装置在clientData
object对象上。(假设不那样做个话,this 会指向window)

 // The clientData object will be used by the Apply method to set the "this" value​
    getUserInput ("Barack", "Obama", clientData.setUserName, clientData);
    // the fullName property on the clientData was correctly set​
    console.log (clientData.fullName); // Barack Obama​

The Apply, Call, and Bind methods are all used to set the this value
when invoking a method, and they do it in slightly different ways to
allow use direct control and versatility in our JavaScript code. The
this value in JavaScript is as important as any other part of the
language, and we have the 3 aforementioned methods are the essential
tools to setting and using this effectively and properly.
当调用一个主意时,apply() call() bind() 方法都被用于安装 this
值应用,并以稍微差距的措施允许大家在JavaScript代码直接控制和多用途。JavaScript中的
this
值与语言的其他任何部分同样主要,大家有上述3种办法是可行和不错地安装和动用
this 的主导工具。

Borrowing Functions with Apply and Call (A Must Know)

效果三:用apply()和call() 来借用函数(必须领会)

The most common use for the Apply and Call methods in JavaScript is
probably to borrow functions. We can borrow functions with the Apply and
Call methods just as we did with the bind method, but in a more
versatile manner.
在javascript中,apply() 和call()
方法最广泛的用处可能是借用函数。大家借用函数用apply()
和call()方法似乎大家运用bind()
方法一致。可是她们更常用。(透过测试自己发觉bind()方法不可能借用数组方法
Consider these examples:

Borrowing Array Methods

借用数组方法

Arrays come with a number of useful methods for iterating and modifying
arrays, but unfortunately, Objects do not have as many native methods.
Nonetheless, since an Object can be expressed in a manner similar to an
Array (known as an array-like object), and most important, because all
of the Array methods are generic (except toString and toLocaleString),
we can borrow Array methods and use them on objects that are
array-like.
在迭代和修改数组方面,数组有这一个实惠的主意。不过不幸的是,对象没有那样多的原生方法。即使这么,因为对象在自然水准上得以像数组一样表明。(称为类数组对象),最重大的是,由于所有数组的艺术是通用的(除了toString()
和tlLocaleString()),大家大家得以借用数组的格局,用在那一个类数组对象上。

An array-like object is an object that has its keys defined as
non-negative integers. It is best to specifically add a length property
on the object that has the length of the object, since the a length
property does not exist on objects it does on Arrays.
一个类数组对象是一个键定义为非负整数的对象,他最好在有长度对象上明显的加一个length
属性,因为length
属性不存在在Object(原型)对象上,却存在在Array(原型)对象上。(在意大家和好在布局一个类数组对象时,一定要加length属性,不然会失效

I should note (for clarity, especially for new JavaScript developers)
that in the following examples, when we call Array.prototype, we are
reaching into the Array object and on its prototype (where all its
methods are defined for inheritance). And it is from there—the
source—that we are borrowing the Array methods. Hence the use of code
like Array.prototype.slice—the slice method that is defined on the Array
prototype.
大家理应注意到(为了清晰起见,尤其是一个js新手)在底下的例子。当我们调用Array.prototype,大家正在触及数组对象和他的原型((其兼具办法都被定义为持续)。而且是从那里

  • 源码- 大家借用了Array方法。由此拔取像Array.prototype.slice那样的代码-
    其实是在应用Array原型上定义的slice方法。(了然原型的可以一贯忽略,太难翻译了)

Let’s create an array-like object and borrow some array methods to
operate on the our array-like object. Keep in mind the array-like object
is a real object, it is not an array at all:
大家来创立一个类数组对象然后来借出一些数组的点子去操作咱们的类数组对象。请牢记,数组类似对象是一个真真对象,它实在不是数组:

     // An array-like object: note the non-negative integers used as keys​
                var anArrayLikeObj = {0:"Martin", 1:78, 2:67, 3:["Letta", "Marieta", "Pauline"], length:4 };

Now, if wish to use any of the common Array methods on our object, we
can:

当今只要大家希望利用一个常见的数组方法在大家的目的上,我得以这么做:

  // Make a quick copy and save the results in a real array:​
                // First parameter sets the "this" value​
                var newArray = Array.prototype.slice.call (anArrayLikeObj, 0);
​
                console.log (newArray); // ["Martin", 78, 67, Array[3]]​
​
                // Search for "Martin" in the array-like object​
                console.log (Array.prototype.indexOf.call (anArrayLikeObj, "Martin") === -1 ? false : true); // true​
​
                // Try using an Array method without the call () or apply ()​
                console.log (anArrayLikeObj.indexOf ("Martin") === -1 ? false : true); // Error: Object has no method 'indexOf'​
​
                // Reverse the object:​
                console.log (Array.prototype.reverse.call (anArrayLikeObj));
                // {0: Array[3], 1: 67, 2: 78, 3: "Martin", length: 4}​
​
                // Sweet. We can pop too:​
                console.log (Array.prototype.pop.call (anArrayLikeObj));
                console.log (anArrayLikeObj); // {0: Array[3], 1: 67, 2: 78, length: 3}​
​
                // What about push?​
                console.log (Array.prototype.push.call (anArrayLikeObj, "Jackie"));
                console.log (anArrayLikeObj); // {0: Array[3], 1: 67, 2: 78, 3: "Jackie", length: 4}​

We get all the great benefits of an object and we are still able to use
Array methods on our object, when we setup our object as an array-like
object and borrow the Array methods. All of this is made possible by the
virtue of the call or apply method.
俺们取得一个对象的持有好处,而且当大家将目的设置为类数组的靶子并借用Array方法时,大家还能在目标上采用Array方法。所有那所有都足以由此call()或apply()方法的独到之处来落到实处。

The arguments object that is a property of all JavaScript functions is
an array-like object, and for this reason, one of the most popular uses
of the call () and apply () methods is to extract the parameters passed
into a function from the arguments object.
arguments
对象是拥有javascript函数中的一个特性,他是一个类数组对象,因为这些原因,call()
和apaly()一个最受欢迎的用途就是从arguments类数组对象中领到参数传递给函数。

Here is an example I took from the Ember.js source, with comments I
added:
此处有一个例证,我是从Ember.js找来的源码,我添加了诠释:

   function transitionTo (name) {
                    // Because the arguments object is an array-like object​
                    // We can use the slice () Array method on it​
                    // The number "1" parameter means: return a copy of the array from index 1 to the end. Or simply: skip the first item​
​
                    var args = Array.prototype.slice.call (arguments, 1);
​
                    // I added this bit so we can see the args value​
                    console.log (args);
​
                    // I commented out this last line because it is beyond this example​
                    //doTransition(this, name, this.updateURL, args);​
                }
​
                // Because the slice method copied from index 1 to the end, the first item "contact" was not returned​
                transitionTo ("contact", "Today", "20"); // ["Today", "20"]​

The args variable is a real array. It has a copy of all the parameters
passed to the transitionTo function.
args变量是一个确实的数组。它具备传递给transitionTo函数的享有参数的副本。

From this example, we learn that a quick way to get all the arguments
(as an array) passed to a function is to do:
从那几个例子中,大家精通一个飞跃的措施来取得传递给函数的有所参数(作为一个数组):

     // We do not define the function with any parameters, yet we can get all the arguments passed to it​
                function doSomething () {
                    var args = Array.prototype.slice.call (arguments);
                    console.log (args);
                }
​
                doSomething ("Water", "Salt", "Glue"); // ["Water", "Salt", "Glue"]​

We will discuss how to use the apply method with the arguments
array-like object again for variadic functions. More on this later.
稍后,大家将探讨什么通过arguments类数组对象来利用apply()方法重复用于可变参数函数。

Borrowing String Methods with Apply and Call

用apply()和call()借用字符串方法

Like the preceding example, we can also use apply () and call () to
borrow String methods. Since Strings are immutable, only the
non-manipulative arrays work on them, so you cannot use reverse, pop and
the like.
像上述的例证一样,我们也足以运用apply() 和 call() 方法去借用String
对象的方法。因为字符串对象是不行更改的,所以唯有非操作数组在它们上干活,所以你无法利用reverse(),pop()等方法。

Borrow Other Methods and Functions

借用其他的章程和函数

Since we are borrowing, lets go all in and borrow from our own custom
methods and functions, not just from Array and String:
既是大家正在借用,就让大家从友好的自定义方法和函数中借用,而不光是从数组和字符串中借用:

 var gameController = {
                    scores  :[20, 34, 55, 46, 77],
                    avgScore:null,
                    players :[
                        {name:"Tommy", playerID:987, age:23},
                        {name:"Pau", playerID:87, age:33}
                    ]
                }
​
                var appController = {
                    scores  :[900, 845, 809, 950],
                    avgScore:null,
                    avg     :function () {
​
                        var sumOfScores = this.scores.reduce (function (prev, cur, index, array) {
                            return prev + cur;
                        });
​
                        this.avgScore = sumOfScores / this.scores.length;
                    }
                }
​
                // Note that we are using the apply () method, so the 2nd argument has to be an array​
                appController.avg.apply (gameController);
                console.log (gameController.avgScore); // 46.4​

                // appController.avgScore is still null; it was not updated, only gameController.avgScore was updated​
                console.log (appController.avgScore); // null​

Sure, it is just as easy, even recommended, to borrow our own custom
methods and functions. The gameController object borrows the
appController object’s avg () method. The “this” value defined in the
avg () method will be set to the first parameter—the gameController
object.
当然,借用大家友好的自定义方法和函数也是很简单的,甚至是引进的。
gameController对象借用appContoller对象的avg()方法,avg()函数里的this值即被定义成调用avg()方法里的首先个参数——gameControlller
对象.

You might be wondering what will happen if the original definition of
the method we are borrowing changes. Will the borrowed (copied) method
change as well, or is the copied method a full copy that does not refer
back to the original method? Let’s answer these questions with a quick,
illustrative example:

【上面{}部分上书没什么意思】(可以直接忽略)
{你可能会想了解如若我们借用的方法的原始定义爆发变化(自家的了解就对象的质量(或者措施不是五回性在对象{}中增加的,前边手动添加的),会时有暴发什么。借来的(复制)方法是或不是也会改变,或者借用的方法是一个总体的副本,不可能回到原来的法子?)
俺们用一个不难的例证来解惑这么些难点:

    appController.maxNum = function () {
            this.avgScore = Math.max.apply (null, this.scores);
        }
​
        appController.maxNum.apply (gameController, gameController.scores);
        console.log (gameController.avgScore); // 77​

As expected, if we change the original method, the changes are reflected
in the borrowed instances of that method. This is expected for good
reason: we never made a full copy of the method, we simply borrowed it
(referred directly to its current implementation).
正如预期的那样,即便大家转移原先的方法,这么些生成突显在该措施的借来的实例中。那是有充足理由的:大家一向不曾完全复制该方法,我们只是借用它(直接引用其眼前兑现)。
}

Use Apply () to Execute Variable-Arity Functions

用apply()去执行可变参数函数

To wrap up our discussion on the versatility and usefulness of the
Apply, Call, and Bind methods, we will discuss a neat, little feature of
the Apply method: execute functions with an array of arguments.
为了成功大家的关于apply() call() bind() 方法的通用性和实用性
,大家将探讨一下apply()方法的一个很粗略的施用:执行函数参数是一个数组。

We can pass an array with of arguments to a function and, by virtue of
using the apply () method, the function will execute the
items in the array as if we called the function like this:
我们可以将一个暗含参数以数组的花样传递给一个函数,通过利用apply()方法,该函数将实施数组中的每一项,就像是下边那样调用函数一样:

createAccount (arrayOfItems[0], arrayOfItems[1], arrayOfItems[2], arrayOfItems[3]);

This technique is especially used for creating variable-arity, also
known as variadic functions.
These are functions that accept any number of arguments instead of a
fixed number of arguments. The arity of a function specifies the number
of arguments the function was defined to accept.
那种技能是任重(英文名:rèn zhòng)而道远用来制造变量的多寡,也被称呼可变参数函数。
可变参数函数:接受其余参数个数而不是承受一定的参数个数。函数的artity指定函数在概念是经受的参数个数。

The Math.max() method is an example of a common variable-arity function
in JavaScript:
Math.max()方法是javascript中可变参数函数的一个事例:

 // We can pass any number of arguments to the Math.max () method​
    console.log (Math.max (23, 11, 34, 56)); // 56

But what if we have an array of numbers to pass to Math.max? We cannot
do this:
可是如果大家有一个数组来传递给Math.max呢?大家不可能这么做:

var allNumbers = [23, 11, 34, 56];
    // We cannot pass an array of numbers to the the Math.max method like this​
    console.log (Math.max (allNumbers)); // NaN

This is where the apply () method helps us execute variadic functions.
Instead of the above, we have to pass the array of numbers using apply
() thus:
那是apply()方法扶助大家执行可变函数的地点。而不是上述,我们必须经过运用apply()的数组数组:

var allNumbers = [23, 11, 34, 56];
    // Using the apply () method, we can pass the array of numbers:​
    console.log (Math.max.apply (null, allNumbers)); // 56

As we have learned earlier, the fist argument to apply () sets the
“this” value, but “this” is not used in the Math.max () method, so we
pass null.

Here is an example of our own variadic function to further illustrate
the concept of using the apply () method in
this capacity:

如前所述,apply()的首先个参数设置了“this”值,然而在Math.max()方法中并未利用“this”,所以大家传递null。

此处是大家协调的可变函数的一个事例,以更为印证在
此容量中利用apply()方法的定义:

    var students = ["Peter Alexander", "Michael Woodruff", "Judy Archer", "Malcolm Khan"];
​
    // No specific parameters defined, because ANY number of parameters are accepted​
    function welcomeStudents () {
        var args = Array.prototype.slice.call (arguments);
​
        var lastItem = args.pop ();
        console.log ("Welcome " + args.join (", ") + ", and " + lastItem + ".");
    }
​
    welcomeStudents.apply (null, students);
    // Welcome Peter Alexander, Michael Woodruff, Judy Archer, and Malcolm Khan.

Final Words

结束语

The Call, Apply, and Bind methods are indeed workhorses and should be
part of your JavaScript repertoire for setting the this value in
functions, for creating and executing variadic functions, and for
borrowing methods and functions. As a JavaScript developer, you will
likely encounter and use these functions time and again. So be sure you
understand them well.

Be Good. Imagine. Create.

“call()”,“apply()”和“bind()”方法广为使用,并且应该是您的JavaScript技能的一部分,用于在函数中设置this值,用于创建和实践可变参数函数以及借用方法和函数。作为JavaScript开发人士,您或许会一遍又一四处境遇并行使这一个函数。所以必然要过得硬驾驭他们。

其它一些参考资料:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind