Arguments and this are silently passed to the function during a function call and can be referenced within the function body to access information about the function. Arguments is a class array structure that holds all the arguments passed to the function when called. This is the context object in which the function executes, and this object has somewhat confusing behavior. They are discussed separately below.
1. arguments
1.1 background
JavaScript allows a function to be called with a different number of arguments than it was defined with. For example, if a function is defined with n arguments, it does not have to be called with n arguments. For example:
// 1. Define a function fn() with a parameter
function fn(arg){}
// 2. No error is reported when zero or more arguments are passed in the call
fn(); // Pass in 0 arguments
fn(1.'a'.3); // Pass multiple arguments
Copy the code
Arguments and parameters
The arguments is a kind of array structure, it stores the function in the all arguments of the incoming call by accessing its length attribute can be saved by the number of arguments, and can pass the arguments [n] out of the incoming in sequence for each parameter (n = 1, 2,… , the arguments.) length – 1.
Arguments are stored in the same order as they were passed in, as well as declared in the same order as parameters, for example:
function fn(arg1, arg2, arg3){
console.log(arg1 === arguments[0]); // true
console.log(arg2 === arguments[1]); // true
console.log(arg3 === arguments[2]); // true
}
fn(1.2.3); / / call
Copy the code
Arguments [n]; arguments[n]; arguments[n]; arguments[n];
// Define a function with a single parameter
function fn(arg1){
console.log('length of arguments is:'.arguments.length);
console.log('arguments[0] is:'.arguments[0]); // Gets the value of arg1, the first argument passed in
console.log('arguments[1] is:'.arguments[1]); // Gets the value of the second argument, with no form involved
console.log('arguments[2] is:'.arguments[2]); // Gets the value of the second argument, with no form involved
}
fn(1.2.3); // Pass in three arguments
// We can get the actual number of arguments passed in and get all the arguments
// length of arguments is: 3
// arguments[0] is: 1
// arguments[1] is: 2
// arguments[2] is: 3
Copy the code
1.3 Arguments correspond to the values of the parameters
In non-strict mode, changing the element value in Arguments changes the corresponding parameter value; Similarly, changing the value of a parameter changes the value saved in the corresponding arguments. The following experiment can illustrate:
function fn(arg1, arg2){
// 1. Modify the arguments element and the corresponding parameters will be modified
arguments[0] = 'Modified arguments';
console.log(arg1);
// 2. Change the parameter value, and the corresponding arguments are changed
arg2 = 'Modified parameter values';
console.log(arguments[1]);
}
fn(1.2);
// 'change arguments'
// 'change the parameter value'
Copy the code
However, this is not the case in strict mode, where arguments and parameter values lose their corresponding relationship:
'use strict'; // Enable strict mode
function fn(arg1, arg2){
// If you modify the arguments element, the corresponding parameters will also be modified
arguments[0] = 'Modified arguments';
console.log(arg1);
// Change the parameter value, and the corresponding arguments are changed
arg2 = 'Modified parameter values';
console.log(arguments[1]);
}
fn(1.2);
/ / 1
/ / 2
Copy the code
Note: Arguments behaves and properties like an array, but it is not an array, just a kind of array structure:
function fn(){
console.log(typeof arguments); // object
console.log(arguments instanceof Array); // false
}
fn();
Copy the code
1.4 Why do you want to know arguments
In ES6, you can use a more flexible deconstruction approach (… Symbol) gets the arguments passed in when the function is called, and the arguments obtained this way are stored in a real array, for example:
function fn(. args){ // Get arguments by deconstructing them
console.log(args instanceof Array); // args is a real array
console.log(args); // And args also holds the arguments passed in
}
fn(1.2.3);
// true
// Array(3) [1, 2, 3]
Copy the code
So why know arguments when you have this more flexible approach? The reason is that you might have to use it to maintain older code.
2. Function context: this
During a function call, the this parameter is also accessible inside the function body, which represents the object associated with the function call, known as the function context.
The direction of this is influenced by the way functions are called, which can be divided into four types:
- Call directly, for example: fn()
- Methods are called as objects, for example: obj.fn()
- Is used as a constructor, for example: new Fn()
- Call with call() or apply(), for example: obj.apply(fn)/obj.call(fn)
The following sections discuss the reference to this in each of the above four calls.
2.1 Reference to this when calling a function directly
Some sources say that when a function is called directly, the value of this refers to the window. This is only true in non-strict mode and in the browser environment. It is more accurate to say that in non-strict mode, the value of this refers to the global context (e.g. window in the browser, Node.js is global. In strict mode, the value of this is undefined. The experimental code is as follows:
// Non-strict mode
function fn(){
console.log(this);
}
fn(); // global || Window
Copy the code
In strict mode:
'use strict';
function fn(){
console.log(this);
}
fn(); // undefined
Copy the code
Conclusion: When a function is called directly, its this pointer is divided into two cases: in non-strict mode it refers to the global context, and in strict mode it refers to undefined.
2.2 called as a method by an object
When a function is called by an object as a method, the function’s this refers to the calling object. The code verification is as follows:
// Define an object
let xm = {
getThis (){ // Define a function
return this; // This function returns its own this pointer}}let thisOfFunc = xm.getThis(); // Call a function from an object to get the function's this pointer
console.log(thisOfFunc === xm); // true, the function's this refers to the object calling it
Copy the code
For this reason, the attributes of an object can be accessed through this. If you add a name attribute to Xm, you can get the attribute value from xm.name, or you can get the attribute value from this.name in a function, that is, this.name is vm. Further, this===xm. The experiment is as follows:
let xm = {
name: 'Ming'.// Add an attribute to xm, which can be accessed by xm.name
getName (){
return this.name; // Returns the name attribute to which this points}}console.log(xm.name, xm.getName()); // Xiaoming xiaoming
Copy the code
2.3 is called as a constructor
2.3.1 Do not use constructors as normal functions
Constructors are essentially functions; a function is called a constructor only when called by the new operator. Having said that, however, since the purpose of writing a constructor is to use it to create an object, there are conventions that limit the concept and avoid using constructors as normal functions. For example, constructors can be called directly, but don’t, because this is something a normal function can do, for example:
function Person(name){
this.name = name;
return 1; // Do not treat constructors like this
}
let n = Person(); // Do not use constructors like this
Copy the code
2.3.2 What happens when constructors are used to create objects
When the constructor is called with the new keyword, the end result is a new object, which is generated as follows:
- Create an empty object {}
- Put the object’s
prototype
Link to the constructorprototype
on - Use this new object as a pointer to this
- If the constructor does not return a value of a reference type, the new object constructed above is returned
If the above is to be fully understood, you also need to know about prototypes. If we use the constructor, this refers to the generated object. The result of the experiment is as follows:
function Person(){
this.getThis = function(){ // This function returns this
return this; }}let p1 = new Person(); // The constructor is called and a new object is returned
console.log(p1.getThis() === p1); // true
let p2 = new Person();
console.log(p2.getThis() === p2); // true
Copy the code
2.3.3 conclusion
It follows from the above that when a function is used as a constructor, this refers to the new object returned
2.4 When called by call() or apply()
The call and apply functions allow you to specify this when a function is called.
fn.call(targetThis, arg1, arg2,... ArgN) fn. Apply (targetThis, [arg1, arg2,.., argN]) fn: the function to call targetThis: the function to call fnthisArgument: The argument to be passed to fnCopy the code
For example, define an object as follows:
let xm = {
name: 'Ming',
sayName(){
console.log(this.name); }}; xm.sayName();// The object calls the function output 'xiaoming'
Copy the code
The above defines an object whose name attribute is’ Xiaoming ‘; The sayName attribute is a function that prints the value of the object’s name attribute. According to part 2.2, this of the sayName function refers to an XM object. This. name is xm.name. Let’s define a new object and point xm.sayName’s this to the newly defined object.
Define a new object xh:
let xh = {
name: 'little red'
};
Copy the code
Xh has only the name attribute, but no sayName attribute. If you want xh to use the sayName function to print its own name, you need to call sayName with this pointing to a small red. This. Name equals xh. Name. This can be done with the call and apply functions. To implement this requirement, use the call function as an example:
xm.sayName.call(xh); / / the little red
xm.sayName.apply(xh); / / the little red
Copy the code
Where fn is xm.sayName; TargetThis is xh because targetThis refers to xH, as shown in Section 2.2.
2.4.1 Difference between Call and apply
The difference between call and apply is only in the form of arguments passed to fn: for apply, the argument passed to FN is an array consisting of all arguments; For call, the argument passed to fn is a sequence of arguments, which can be written one by one. For example, to pass fn three arguments: 1, 2, and 3.
fn.call(targetThis, 1.2.3); // pass 1,2,3 directly
fn.apply(targetThis, [1.2.3]); // combine 1,2, and 3 into arrays as arguments
Copy the code
2.5 Arrow functions andbind
function
The arrow and bind functions handle this differently than normal functions and are separate from each other.
2.5.1 Arrow function
Unlike traditional functions, the arrow function itself does not contain this; its this inherits from the upper level of the scope chain where it was defined. Also, the arrow function cannot be used as a constructor, and it does not have the arguments attribute described in Part 1 of this article.
Here’s an example of where the arrow function this comes from:
function Person(){
this.age = 24;
setTimeout(function(){
console.log(this.age); // undefined
console.log(this= = =window); // true
}, 1000);
}
var p = new Person(); // The timer is executed immediately when an instance is created
Copy the code
As you can see, the normal anonymous function defined inside the timer cannot access the Age property of Person. This is because setTimeout is a global function. The this inside of setTimeout refers to the window, and the window has no age property. So I get undefined. If this === window is true, this refers to window.
After replacing the normal function with the arrow function, you can see the following:
function Person(){
this.age = 24;
setTimeout((a)= > {
console.log(this.age); / / 24
console.log(this === p); // true
}, 1000);
}
var p = new Person();
Copy the code
As you can see from the above code, this in the arrow function points to instance P, that is, its this points to the upper level of the scope chain at which it was defined.
Note: This example is only used to draw out the source to which the arrow function’s this points. Do not use the constructor like this.
2.5.2 bind function
The bind function creates a new function from an old one, with the syntax newFn = oldFn. Bind (thisTarget). It will make a copy of the old function as the new one, bind the new function’s this to the context thisTarget points to forever, and return the new function, and every time the new function is called, nothing can change the this reference of the new function. Such as:
// Create an object with the name and sayName attributes
let p1 = {
name: 'P1',
sayName(){
console.log(this.name); // Access the name attribute of this that the function points to
}
}
p1.sayName(); // P1
// Create an object p2 and bind it to this
let p2 = {
name: 'P2'
}
// bind this of p1's sayName function to p2, generate a new function sayP2Name and return
let sayP2Name = p1.sayName.bind(p2);
SayP2Name = sayP2Name;
So even if sayP2Name is called directly as described in section 2.1, its this refers to P2, not to the global context or undefined
sayP2Name(); // P2
// Define a new object and try pointing sayP2Name's this to p3
let p3 = {
name: 'P3'
}
// Try using call and apply to refer this of sayP2Name to p3,
// But since sayP2Name's this has been permanently bound to p2 by bind, this.name is still p2.name
sayP2Name.call(p3); // P2
sayP2Name.apply(p3); // P2
Copy the code
Once you bind this, you can’t change the direction of this.
Thank you for pointing out any mistakes! Reference article: << JavaScript Ninja Secrets >> JavaScript new Keyword MDN