In JavaScript, call, apply and bind are the three methods that come with the Function object. This article will understand the three methods in detail through the application of several scenarios.
call()
The call() method calls a function or method using a specified this value and several specified parameter values.
When calling a function, you can assign a different this object. this refers to the current object, the first parameter of the call method.
Through the call method, you can borrow methods on one object from another object, such as Object.prototype.toString.call([]), which is an Array object borrowing methods on the Object object.
Syntax fun.call(thisArg[, arg1[, arg2[, ...]]])
thisArg
The this value specified when the fun function is running. What you need to pay attention to are the following situations
(1) Do not pass, or pass null or undefined. This in the function points to the window object
(2) Pass the function name of another function. This in the function points to a reference to this function, which is not necessarily the real this value when the function is executed
(3) This whose value is a primitive value (number, string, Boolean value) will point to the automatic packaging object of the primitive value, such as String, Number, Boolean
(4) Pass an object, and this in the function points to this object
arg1, arg2, ...
The specified parameter list.
Example
Elementary application example
function a(){ //输出函数a中的this对象 console.log(this); } //定义函数b function b(){} var obj = {name:'这是一个屌丝'}; //定义对象obj a.call(); //window a.call(null); //window a.call(undefined);//window a.call(1); //Number a.call(''); //String a.call(true); //Boolean a.call(b);// function b(){} a.call(obj); //Object
Use the call method to call an anonymous function and specify this of the context
In the following example, when the greet method is called, the this value of the method will be bound to the i object.
function greet() { var reply = [this.person, '是一个轻量的', this.role].join(' '); console.log(reply); } var i = {function greet() { var reply = [this.person, '是一个轻量的', this.role].join(' '); console.log(reply); } var i = { person: 'JSLite.io', role: 'Javascript 库。' }; greet.call(i); // JSLite.io 是一个轻量的 Javascript 库。 person: 'JSLite.io', role: 'Javascript 库。' }; greet.call(i); // JSLite.io 是一个轻量的 Javascript 库。
Use the call method to call anonymous functions
In the for loop body in the following example, we create an anonymous function, and then execute the anonymous function by calling the call method of the function, using each array element as the specified this value. The main purpose of this anonymous function is to add a print method to each array element object. This print method can print out the correct index number of each element in the array. Of course, it is not necessary to pass the array elements into the anonymous function as this value (normal parameters are enough). The purpose is to demonstrate the usage of call.
var animals = [ {species: 'Lion', name: 'King'}, {species: 'Whale', name: 'Fail'} ]; for (var i = 0; i < animals.length; i++) { (function (i) { this.print = function () { console.log('#' + i + ' ' + this.species + ': ' + this.name); } this.print(); }).call(animals[i], i); } //#0 Lion: King //#1 Whale: Fail
Use the call method to call a function and pass parameters
var a = { name:'JSLite.io', //定义a的属性 say:function(){ //定义a的方法 console.log("Hi,I'm function a!"); } }; function b(name){ console.log("Post params: "+ name); console.log("I'm "+ this.name); this.say(); } b.call(a,'test'); //Post params: test //I'm onepixel //I'm function a!
apply()
The syntax is almost identical to that of the call() method, the only difference is that the second parameter of apply must be an array (or array-like object) containing multiple parameters. This feature of apply is very important,
When calling an existing function, you can specify a this object for it. this refers to the current object, which is the object that is calling this function. Using apply, you can write the method once and then inherit it in another object, without having to write the method repeatedly in the new object.
Syntax: fun.apply(thisArg[, argsArray])
Note: It's important to note that Chrome 14 and Internet Explorer 9 still don't accept array-like objects. If array-like objects are passed in, they will throw an exception.
Parameters
thisArg
Same as the thisArg parameter of call above.
argsArray
An array or array-like object, the array elements of which will be passed as separate parameters to the fun function. If the value of this parameter is null or undefined, it means that no parameters need to be passed in. Starting from ECMAScript 5, array-like objects are available.
Example
function jsy(x,y,z){ console.log(x,y,z); } jsy.apply(null,[1,2,3]); // 1 2 3
Example of using apply to link constructor
You can use apply to link a constructor to an object, similar to Java. In the following example we will create a global Function function called construct to enable you to use an array-like object in the constructor rather than a parameter list.
Function.prototype.construct = function(aArgs) { var fConstructor = this, fNewConstr = function() { fConstructor.apply(this, aArgs); }; fNewConstr.prototype = fConstructor.prototype; return new fNewConstr(); }; function MyConstructor () { for (var nProp = 0; nProp < arguments.length; nProp++) { console.log(arguments,this) this["property" + nProp] = arguments[nProp]; } } var myArray = [4, "Hello world!", false]; var myInstance = MyConstructor.construct(myArray); console.log(myInstance.property1); // logs "Hello world!" console.log(myInstance instanceof MyConstructor); // logs "true" console.log(myInstance.constructor); // logs "MyConstructor"
Use apply and built-in functions
Smart apply usage allows you to use built-in functions in certain tasks that would otherwise be written as iterating over array variables. In the following example we will use Math.max/Math.min to find the maximum/minimum value in an array.
//里面有最大最小数字值的一个数组对象 var numbers = [5, 6, 2, 3, 7]; /* 使用 Math.min/Math.max 在 apply 中应用 */ var max = Math.max.apply(null, numbers); // 一般情况是用 Math.max(5, 6, ..) 或者 Math.max(numbers[0], ...) 来找最大值 var min = Math.min.apply(null, numbers); //通常情况我们会这样来找到数字的最大或者最小值 //比对上面的栗子,是不是下面的看起来没有上面的舒服呢? max = -Infinity, min = +Infinity; for (var i = 0; i < numbers.length; i++) { if (numbers[i] > max) max = numbers[i]; if (numbers[i] < min) min = numbers[i]; }
The parameter array is cut into pieces and passed in a loop
function minOfArray(arr) { var min = Infinity; var QUANTUM = 32768; for (var i = 0, len = arr.length; i < len; i += QUANTUM) { var submin = Math.min.apply(null, arr.slice(i, Math.min(i + QUANTUM, len))); console.log(submin, min) min = Math.min(submin, min); } return min; } var min = minOfArray([5, 6, 2, 3, 7]);
bind
The bind() function creates a new function (called a bound function)
bind is a new method in ES5
Passing parameters is similar to call or apply
The corresponding function will not be executed, call or apply will automatically execute the corresponding function
Returns a reference to the function
Syntax fun.bind(thisArg[, arg1[, arg2[, ...]]])
The following example: When a web page is clicked, EventClick is triggered and executed, and JSLite.io p1 p2 is output, indicating that this in EventClick has been changed into an obj object by bind. If you change EventClick.bind(obj,'p1','p2') into EventClick.call(obj,'p1','p2'), the page will directly output JSLite.io p1 p2
var obj = {name:'JSLite.io'}; /** * 给document添加click事件监听,并绑定EventClick函数 * 通过bind方法设置EventClick的this为obj,并传递参数p1,p2 */ document.addEventListener('click',EventClick.bind(obj,'p1','p2'),false); //当点击网页时触发并执行 function EventClick(a,b){ console.log( this.name, //JSLite.io a, //p1 b //p2 ) } // JSLite.io p1 p2
Compatible
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, // this在这里指向的是目标函数 fNOP = function () {}, fBound = function () { return fToBind.apply(this instanceof fNOP ? this //此时的this就是new出的obj : oThis || this,//如果传递的oThis无效,就将fBound的调用者作为this //将通过bind传递的参数和调用时传递的参数进行合并,并作为最终的参数传递 aArgs.concat(Array.prototype.slice.call(arguments))); }; fNOP.prototype = this.prototype; //将目标函数的原型对象拷贝到新函数中,因为目标函数有可能被当作构造函数使用 fBound.prototype = new fNOP(); //返回fBond的引用,由外部按需调用 return fBound; }; }
应用场景:继承
function Animal(name,weight){ this.name = name; this.weight = weight; } function Cat(){ // 在call中将this作为thisArgs参数传递 // Animal方法中的this就指向了Cat中的this // 所以Animal中的this指向的就是cat对象 // 在Animal中定义了name和weight属性,就相当于在cat中定义了这些属性 // cat对象便拥有了Animal中定义的属性,从而达到了继承的目的 Animal.call(this,'cat','50'); //Animal.apply(this,['cat','50']); this.say = function(){ console.log("I am " + this.name+",my weight is " + this.weight); } } //当通过new运算符产生了cat时,Cat中的this就指向了cat对象 var cat = new Cat(); cat.say(); //输出=> I am cat,my weight is 50
原型扩展
在原型函数上扩展和自定义方法,从而不污染原生函数。例如:我们在 Array 上扩展一个 forEach
function test(){ // 检测arguments是否为Array的实例 console.log( arguments instanceof Array, //false Array.isArray(arguments) //false ); // 判断arguments是否有forEach方法 console.log(arguments.forEach); // undefined // 将数组中的forEach应用到arguments上 Array.prototype.forEach.call(arguments,function(item){ console.log(item); // 1 2 3 4 }); } test(1,2,3,4);