In-depth understanding of JavaScript series (19): Evaluation strategy
This article mainly introduces how to thoroughly understand the JavaScript series (19): Evaluation strategy (Evaluation strategy, this article describes general theories, passing by value, transferring by reference, calling by sharing, and passing by share are special cases of passing by value, for more information, see
Introduction
This chapter describes how to transfer parameters to function functions in ECMAScript.
In computer science, this strategy is generally called "evaluation strategy" (Uncle Note: Some people say that translation is a value-seeking policy, and some people translate it into a value-assignment policy. Let's look at the following content, I think the assignment policy is more appropriate. anyway, the title should be written as an easy-to-understand evaluation policy. For example, in programming languages, you can set rules for values or calculation expressions. The policy for passing parameters to a function is a special case.
Http://dmitrysoshnikov.com/ecmascript/chapter-8-evaluation-strategy/
The reason for writing this article is that someone on the Forum asked for an accurate explanation of some parameter passing policies. We have provided corresponding definitions here, hoping to help you.
Many programmers are convinced that in JavaScript (or even some other languages), the object is passing parameters by reference, and the original value type is passing parameters by value. In addition, many articles talk about this "fact", but many people really understand this term, and how many of them are correct? We will explain this article one by one.
General Theory
It should be noted that in the assignment theory, there are generally two assignment policies: strict -- that is, the parameter is calculated before it enters the program; not strict-it means that the parameter calculation is based on the computing requirements (that is, it is equivalent to the delay calculation ).
Next, we will consider the basic function parameter passing policy, which is very important from the starting point of ECMAScript. Note that strict parameter transfer policies are used in ECMAScript (or even other languages such as C, JAVA, Python, and Ruby.
In addition, the computational order of passing parameters is also very important-the ECMAScript is left-to-right, And the introspection sequence (from right to do) implemented by other languages is also usable.
Strict parameter passing policies are also divided into several seed policies. The most important strategies are discussed in this chapter.
Not all of the policies discussed below are used in ECMAScript. Therefore, we use pseudo code to demonstrate the specific behaviors of these policies.
Pass by value
Passing by value many developers understand that the parameter value is a copy of the object value passed by the caller ), changing the parameter value inside the function does not affect the External Object (the parameter value is outside). Generally, the new memory is re-allocated (we do not pay attention to how the allocated memory is implemented-that is, stack or dynamic memory allocation). The value of the new memory block is a copy of the external object, and its value is used inside the function.
The Code is as follows:
Bar = 10
Procedure foo (barArg ):
BarArg = 20;
End
Foo (bar)
// The internal change value of foo does not affect the internal bar value.
Print (bar) // 10
However, if the parameter of the function is not the original value but a complex structure object, it will bring a lot of performance problems. C ++ has this problem, when the structure is passed as a value to the function, it is a complete copy.
Let's give a general example and use the following value assignment policy to check whether a function accepts two parameters. The value of the 1st parameter is the object value, 2nd are Boolean tags used to indicate whether to completely modify the passed-in object (assign a value to the object) or only modify some attributes of the object.
The Code is as follows:
// Note: The following are all pseudo code, not JS implementation.
Bar = {
X: 10,
Y: 20
}
Procedure foo (barArg, isFullChange ):
If isFullChange:
BarArg = {z: 1, q: 2}
Exit
End
BarArg. x = 100
BarArg. y = 200
End
Foo (bar)
// Pass by value, external objects are not changed
Print (bar) // {x: 10, y: 20}
// Completely change the object (new value)
Foo (bar, true)
// No changes
Print (bar) // {x: 10, y: 20} Instead of {z: 1, q: 2}
Pass by reference
Another well-known transfer by reference is not to receive a copy of the value, but an implicit reference of the object, such as the direct external reference address of the object. Any change to the parameter inside the function affects the value of the object outside the function, because the two reference the same object, that is, the parameter is equivalent to an alias of the external object.
Pseudocode:
The Code is as follows:
Procedure foo (barArg, isFullChange ):
If isFullChange:
BarArg = {z: 1, q: 2}
Exit
End
BarArg. x = 100
BarArg. y = 200
End
// Use the same object as the previous example
Bar = {
X: 10,
Y: 20
}
// The result of calling by reference is as follows:
Foo (bar)
// The object property value has been changed
Print (bar) // {x: 100, y: 200}
// The object is also affected when the new value is re-assigned.
Foo (bar, true)
// This object is a new object now.
Print (bar) // {z: 1, q: 2}
This policy can more effectively pass complex objects, such as large structured objects with large batches of attributes.
Call by sharing)
We all know the above two strategies, but one of the strategies mentioned here may not be quite familiar (in fact, they are academic strategies ). However, we will soon see that this is the policy that plays a key role in the parameter transfer strategy of ECMAScript.
This policy is also synonymous with "passing by object" or "passing by object sharing ".
This strategy was proposed by Barbara Liskov for CLU programming language in 1974.
The main point of this policy is that the function receives an object copy (copy). The reference copy is associated with the form parameter and its value.
The reference here cannot be called "pass by reference" because the parameter received by the function is not a direct object alias, but a copy of the reference address.
The most important difference is that the function does not affect the external objects (and the case passed by reference in the previous example) after the parameter is re-assigned. However, because the parameter is an address copy, therefore, both the external access and the internal access are the same object (for example, the external object does not want to pass the same copy as the value ), changing the attribute value of this parameter object will affect the external object.
The Code is as follows:
Procedure foo (barArg, isFullChange ):
If isFullChange:
BarArg = {z: 1, q: 2}
Exit
End
BarArg. x = 100
BarArg. y = 200
End
// Use the object structure
Bar = {
X: 10,
Y: 20
}
// Contribution-based transmission will affect the object
Foo (bar)
// The object property has been modified.
Print (bar) // {x: 100, y: 200}
// The Value assignment does not take effect.
Foo (bar, true)
// Still the above value
Print (bar) // {x: 100, y: 200}
The assumption of this processing is that the objects used in most languages are not the original values.
Passing by share is a special case of passing by value
This policy is used in many languages such as Java, ECMAScript, Python, Ruby, and Visual Basic. In addition, this term has been used in the Python community, and can be used in other languages, because other names often make people feel confused. In most cases, for example, in Java, ECMAScript, or Visual Basic, this policy is also called passing by value -- meaning: Special Value -- reference copy (copy ).
On the one hand, it is like this-the parameter passed to the function is only a name of the bound value (reference address) and does not affect external objects.
On the other hand, without in-depth research, these terms are really considered to be incorrect, because many forums are talking about how to pass objects to JavaScript Functions ).
In general, there is indeed a saying of passing by value: But at this time, this value is what we call address copy (copy), so it does not break the rules.
In Ruby, this policy is called transfer by reference. Let's talk about it: it is not transmitted by copying a large structure (for example, not by value). On the other hand, we have not processed the reference of the original object and cannot modify it. Therefore, this cross-Term Concept may cause confusion.
In theory, there is no special case for passing by reference like a special case for passing by value.
However, it is still necessary to understand these policies in the above mentioned technologies (Java, ECMAScript, Python, Ruby, and other). In fact, the policies they use are passed by share.
Share and pointer
For counter/Counter ++, this policy is the same in mind as passing by pointer value, but there is an important difference-this policy can cancel the reference pointer and completely change the object. However, in general, assign a value (Address) pointer to the new memory block (that is, the referenced memory block remains unchanged ); changing the object attributes through pointers will affect the external objects of Adong.
Therefore, we can see from the pointer type that this is passed by the address value. In this case, pass by share is just a "syntactic sugar", like a pointer assignment (but cannot cancel the reference), or modify attributes like a reference (you do not need to cancel the reference operation ), sometimes it can be named "Security Pointer ".
However, except/distinct ++ has a special syntax sugar when referencing object attributes without explicit pointer Resolution:
The Code is as follows:
Obj-> x instead of (* obj). x
This ideology closely related to C ++ can be seen from the implementation of "smart pointer". For example, in boost: shared_ptr, the value assignment operator and copy constructor are overloaded, in addition, the reference counter of the object is used to delete the object through GC. This data type even has a similar name-share _ ptr.
ECMAScript implementation
Now we know the policy of passing objects as parameters in ECMAScript-pass by share: modifying the attribute of a parameter will affect the external, and re-assigning a value will not affect the external object. However, as we mentioned above, ECMAScript developers generally call it "pass by value", but this value is a copy of the reference address.
The inventor of JavaScript, fig, also wrote that the reference copy (address copy) is passed ). Therefore, the value-based transmission that everyone once said in the Forum is correct under this explanation.
More specifically, this behavior can be understood as a simple assignment. We can see that there are completely different objects inside, but the same value is referenced, that is, the address copy.
ECMAScript code:
The Code is as follows:
Var foo = {x: 10, y: 20 };
Var bar = foo;
Alert (bar = foo); // true
Bar. x = 100;
Bar. y = 200;
Alert ([foo. x, foo. y]); // [100,200]
That is, two Identifiers (name binding) are bound to the same object in the memory, sharing this object:
Foo value: addr (0xFF) =>{ x: 100, y: 200} (address 0xFF) <= bar value: addr (0xFF)
In the case of re-assignment, the binding is a new object identifier (new address) without affecting the previously bound objects:
The Code is as follows:
Bar = {z: 1, q: 2 };
Alert ([foo. x, foo. y]); // [100,200]-unchanged
Alert ([bar. z, bar. q]); // [1, 2]-But now the new object is referenced
That is, foo and bar have different values and different addresses:
The Code is as follows:
Foo value: addr (0xFF) =>{ x: 100, y: 200} (address 0xFF)
Bar value: addr (0xFA) =>{ z: 1, q: 2} (address 0xFA)
Here, the object value is address rather than the object structure itself. assign a variable to another variable, which is a reference to the value. Therefore, the two variables reference the same memory address. The next value is a new address, which is used to resolve the address bound to the old object and then bind it to the address of the new object. This is the most important difference from passing by reference.
In addition, if we only consider the abstract hierarchy provided by the ECMA-262 standard, we can see in the algorithm that only the concept of "value" is implemented to pass the "value" (can be the original value, can also be an object), but according to the above definition, it can also be called "pass by value", because the reference address is also a value.
However, to avoid misunderstanding (why attributes of external objects can be changed inside the function), we still need to consider the implementation details here-what we see is passing by share, or in other words-pass by security pointer, and the security pointer cannot unreference or change the object, but can modify the attribute value of the object.
Term version
Let's define the term version of this policy in ECMAScript.
It can be called "pass by value" -- the value mentioned here is a special case, that is, the value is the address copy ). At this level, we can say that all objects except exceptions in ECMAScript are passed by value, which is actually the abstract level of ECMAScript.
Or in this case, it is called "transfer by share". This shows the difference between the traditional transfer by value and transfer by reference. In this case, there are two possible cases: 1: Passing original values by value; 2: passing objects by share.
The phrase "object to function via reference type" is irrelevant to ECMAScript and is incorrect.
Conclusion
I hope this article will help you learn more details and implement it in ECMAScript. As always, if you have any questions, you are welcome to discuss them.