1. Definition of call():
The call() method calls a function or method on the premise of using a specified this value and several specified parameter values.
The point is that we can set this to point to another object, so the data and methods in this object can be accessed
If you want to use the FN1 method in the a object to process the data in the B object, you can use FN1 call(b);
var foo = { value: 1 }; function bar() { console.log(this.value); } bar.call(foo); // 1
// Here, if you call bar (); This is because the function execution context is created when bar() is called, and this points to the object window that calls it Value is to find value in the window
// No value defined, undefined
// And bar call(foo); Point this in the bar to the foo object. When calling, first find out whether there is a value attribute in the foo object, and the output is 1
2. Function of call (obj)
(1) Changed the direction of the function active object this, pointing to the new object foo
(2) The function is then executed
3. Simulate the call() function
First of all, call wants a object to use the method of b object, so we directly add a new attribute in a object to store the method, and then call the method in A. because it is called by a object, the method this points to a object,
After the execution result is obtained, delete the attribute to complete the function
- Set function to object property
- Execute the function properties
- Delete the attribute
1: foo.fn = bar 2: foo.fn() 3: delete foo.fn
3.1 call() in the first version
The basic function of call() is realized
//Because it is called by all function objects call()method,So it should be written on the prototype object of the function According to the prototype chain fn._proto_ === Function.prototype ,definition call method Function.prototype.call = function(context){ //1.call Will receive parameters context,by this Reoriented object //2.How to get the called function? // from bar.call(obj)knowable,This is a function instance object bar,call call method,In a function called by an object this Point to the object,therefore call Internal this point bar,This gives you the function to call context.fn = this; // hold bar Endow obj.fn attribute context.fn(); // If not context call,that fn()Medium this Will point directly to window delete context.fn; //delete fn attribute }
However, call() itself can receive multiple parameters for processing, not only modify the pointed object, but also continue to modify
3.2 call() in the second edition
Question 1: because the function calling call() needs to receive different parameters, the actual problem is that call() needs to receive an indefinite number of parameters
obj object + multiple parameters, we can call the arguments object inside call(), get all the pseudo array of received parameters, remove the first one, then adjust to the parameter array of fn.
(1) Take all values with index 1 from arguments and put them into an array
// Take the above examples as an example arguments Is: // arguments = { // 0: foo, // 1: 'kevin', // 2: 18, // length: 3 // } // because arguments Is a class array object, so you can use for loop var args = []; for(var i = 1, len = arguments.length; i < len; i++) {
// arguments is an array like object, and its length is calculated in real time, so the length needs to be saved before traversal, or it will be calculated again in each cycle to filter out the first parameter args.push('arguments[' + i + ']'); } // After execution args by [foo, 'kevin', 18]
(2) Put the array as a formal parameter in fn()
Call the eval() method, construct a js statement execution block, and implement the args parameter variable with string addition
eval('context.fn(' + args +')')
// Actually executed context fn(args.toString())
args is implicitly stringed
// Second Edition Function.prototype.call2 = function(context) { context.fn = this; var args = []; for(var i = 1, len = arguments.length; i < len; i++) { args.push('arguments[' + i + ']'); } eval('context.fn(' + args +')'); delete context.fn; }
3.3 Third Edition
Question 1 when the input is null, this points to window
You only need to make a default judgment. It is recommended to use or our short circuit
var context = context || window; //If the input is null and empty, they all point to window by default
// The assignment logic is that with or without (priority value) 𞓜 default value (default value), the priority value can be taken and the default value can be taken
Question 2 the function has the return value return. Call() needs to output the contents of return
Create a variable to receive the return value processed by eval(), and finally add return
var result = eval('context.fn(' + args +')'); delete context.fn return result;
The above is the call() method based on es3 implementation
3.4 call() method based on es6 implementation
Because es6 implements the extension operator rest # so instead of using the eval() method to execute the function, you just put Args added to context fn(...args)
// ES6 call realization Function.prototype.es6Call = function (context) { var context = context || window; context.fn = this; var args = []; for (var i = 1, len = arguments.length; i < len; i++) { args.push('arguments[' + i + ']'); } const result = context.fn(...args); return result; }