Home > Article > Web Front-end > Detailed introduction to the usage of bind, call, and apply functions in JavaScript
When I introduced js to other programs in our project team, I prepared a lot of content, but it seemed to have little effect. As expected, just talking about it is not enough, you must do it. A few days ago, someone asked me about the usage of call() function in the code. I asked him to read a book. I recommend that programmers who use js to write servers read 《javascriptprogrammingessence》 This book, crockford master really didn’t write it. Later, I saw a similar question on segmentfault. After answering it there, I just made a note here.
First of all, regarding the method of defining a class or object in js, please refer to w3school here. The writing is very detailed and clear, so I won’t go into details.
In order to introduce the usage of the three functions bind, call, and apply, I have to introduce some settings of the functions in js. Regarding this part, it is recommended to read Chapter 4 of "The Essence of JavaScript Programming". Everything I say here can be found in the book.
For a detailed introduction to these three functions, please refer to the MDN documentation: bind, call, apply.
Let’s start to move the bricks and modify my previous answer on segmentfault:
There are 4 modes of function calling in js: method calling and normal function calling , constructor function call, apply/call call.
At the same time, no matter what kind of function call, in addition to the formal parameters defined when you declare it, 2 formal parameters will be automatically added, namely this and arguments.
arguments does not involve the above three functions, so we only talk about this here. The value of this will be bound to different values in the calling mode in 4 above. Let’s talk about it separately:
Method call:
This is easy to understand. The function is the attribute of an object, such as
var a = { v : 0, f : function(xx) { this.v = xx; } } a.f(5);
At this time, This in the above function is bound to this object a. So this.v can get the attribute v of object a.
Normal function call: Still looking at the code
function f(xx) { this.x = xx; } f(5);
At this time, this in function f is bound to the global object. If it is an interpreter running in the browser , generally the window object. So what this.x here actually accesses is window.x. Of course, if window does not have an x attribute, then if you write it like this, according to the cheating syntax of js, you will add an x attribute to the window object and assign a value at the same time.
Constructor function call:
Constructor function has always been what I think is the most annoying part in js, because it is similar to the original design of js The prototype-based Object-oriented implementation is out of place, as if it is specially designed to cater to the habits that everyone has been spoiled by other class-based object-oriented implementations.
If you call a function with the new keyword in front of it, js will create a prototype attribute that is a new object of this function. At the same time, when calling this function, this is bound to this new object. Of course, the new keyword will also change the behavior of the return statement, but I won’t talk about it here. Look at the code
function a(xx) { this.m = xx; } var b = new a(5);
There is no difference between the writing of the above function and the normally called function, except that the keyword new is added in front of the function name when calling. In this way, this is no longer bound to The global object mentioned earlier is the new object created here, so this method is actually very dangerous, because just looking at the function, you will not know whether this function is intended to be used as a constructor or not. Used for general functions. So we can see that in jslint, it will require all constructors you write, that is, once it finds that you have used the new keyword, the first letter of the subsequent function must be capitalized. In this way, the first letter of the function must be capitalized. To distinguish, I personally have only one opinion: cheating:)
apply/call call:
我们知道,在 js 里,函数其实也是一个对象,那么函数自然也可以拥有它自己的方法,有点绕,在js 里,每个函数都有一个公共的 prototype —— Function,而这个原型自带有好几个属性和方法,其中就有这里困惑的 bind、call、apply 方法。先说 apply 方法,它让我们构造一个参数数组传递给函数,同时可以自己来设置 this 的值,这就是它最强大的地方,上面的 3 种函数调用方式,你可以看到,this 都是自动绑定的,没办法由你来设,当你想设的时候,就可以用 apply()了。apply 函数接收 2 个参数,第一个是传递给这个函数用来绑定 this 的值,第二个是一个参数数组。
看代码
function a(xx) { this.b = xx; } var o = {}; a.apply(o, [5]); alert(a.b); // undefined alert(o.b); // 5
是不是很神奇,函数 a 居然可以给 o 加属性值。当然,如果你 apply 的第一个参数传递 null,那么在函数 a 里面 this 指针依然会绑定全局对象。
call() 方法和 apply() 方法很类似,它们的存在都是为了改变 this 的绑定,那 call() 和apply() 有什么区别呢?就我个人看来,没啥鸟区别。。。开玩笑!刚刚说了,上面 apply() 接收两个参数,第一个是绑定 this 的值,第二个是一个参数数组,注意它是一个数组,你想传递给这个函数的所有参数都放在数组里,然后 apply() 函数会在调用函数时自动帮你把数组展开。而 call()呢,它的第一个参数也是绑定给 this 的值,但是后面接受的是不定参数,而不再是一个数组,也就是说你可以像平时给函数传参那样把这些参数一个一个传递。
所以如果一定要说有什么区别的话,看起来是这样的
function a(xx, yy) { alert(xx, yy); alert(this); alert(arguments); } a.apply(null, [5, 55]); a.call(null, 5, 55);
仅此而已。
最后再来说 bind() 函数,上面讲的无论是 call() 也好, apply() 也好,都是立马就调用了对应的函数,而 bind() 不会, bind() 会生成一个新的函数,bind() 函数的参数跟 call() 一致,第一个参数也是绑定 this 的值,后面接受传递给函数的不定参数。 bind() 生成的新函数返回后,你想什么时候调就什么时候调,看下代码就明白了
var m = { "x" : 1 }; function foo(y) { alert(this.x + y); } foo.apply(m, [5]); foo.call(m, 5); var foo1 = foo.bind(m, 5); foo1();
末了来个吐槽,你在 js 里想定义一个函数,于是你会这么写:
function jam() {};
其实这是 js 里的一种语法糖,它等价于:
var jam = function() {};
然后你想执行这个函数,脑洞大开的你会这么写:
function jam() {}();
但是这么写就报错了,其实这种写法也不算错,因为它确实是 js 支持的函数表达式,但是同时 js 又规定以function 开头的语句被认为是函数语句,而函数语句后面是肯定不会带 () 的,所以才报错,于是聪明的人想出来,加上一对括号就可以了。于是就变成了这样:
1(function jam() {}());
这样就定义了一个函数同时也执行它,详情参加 ECMAScript 的 Expression Statement 章节。
The above is the detailed content of Detailed introduction to the usage of bind, call, and apply functions in JavaScript. For more information, please follow other related articles on the PHP Chinese website!