In depth understanding of the JavaScript series (19) : evaluation policy of Evaluation strategy in detail

  • 2020-05-10 17:42:45
  • OfStack

introduce

In this chapter, we will explain the strategy of passing arguments from ECMAScript to the function function.

Computer science to this strategy 1 kind is called "evaluation strategy" (uncle note: some people say translated into evaluation strategy, some translated into assignment strategy, see the following content, I feel more properly known as assignment strategy, anyway, title or written all easy to understand the evaluation of strategy), for example, in a programming language set rules for evaluation or calculation expression. The strategy for passing arguments to a function is a special case.

http://dmitrysoshnikov.com/ecmascript/chapter-8-evaluation-strategy/
The reason for writing this article is that some people on the forum asked for an accurate explanation of 1. We have given the corresponding definition here. I hope it will be helpful to you.

Many programmers are convinced that in JavaScript (and even some other languages), objects are passed by reference, and primitive value types by value. Furthermore, many articles talk about this "fact", but many people really understand the term and are more or less correct. We're going to do this one by one.

1 a theory

It is important to note that in assignment theory 1 is like 2 in assignment strategy: strict -- meaning that the parameters are calculated before entering the program; Non-strict - means that the parameter is calculated according to the calculation requirements (i.e., equivalent to delayed calculation).

Then, here we consider the basic function pass-through strategy, which is very important from the point of view of ECMAScript. The first thing to note is that in ECMAScript (and even in other languages such as C, JAVA, Python, and Ruby) a strict parameter passing strategy is used.

The order in which the parameters are passed is also important - left to right in ECMAScript, and the order of introspection (doing from right) implemented in other languages is also available.

Strict referral strategies are also divided into several substrategies, the most important of which are discussed in detail in this chapter.

Not all of the policies discussed below are used in ECMAScript, so when we discuss the specific behavior of these policies, we use pseudocode to demonstrate them.

Pass by value

Pass by value, many developers are very understanding, the value of the parameter is a copy of the caller transfer object value (copy of value), internal function to change the value of the parameter will not affect the outside of the object (the parameter value) in the outside, 1 a, is to reallocate the new memory (we don't pay attention to allocate memory is how to achieve - and is the stack may be dynamic memory allocation), the new value of the memory block is a copy of the external object, the inside of the function and its value is used.


bar = 10
 
procedure foo(barArg):
  barArg = 20;
end
 
foo(bar)
 
// foo Internal changes do not affect internal values bar The value of the
print(bar) // 10

However, if the parameter of the function is not the original value but a complex structured object, it will cause a big performance problem. C++ has this problem, when the structure is passed into the function as a value -- it is the full copy.

To 1 to 1 example, we use the following assignment strategy to test 1, l think one function takes two parameters, the first parameter is the value of the object, the second is a Boolean flag, to identify whether completely change the incoming object (to object assignment), or just modify 1 some attributes of the object.


// Note: the following are pseudocodes, 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)
 
// Passed by value, external objects are not changed
print(bar) // {x: 10, y: 20}
 
// Completely change the object (assign a new value)
foo(bar, true)
 
// It hasn't changed
print(bar) // {x: 10, y: 20}, Rather than {z: 1, q: 2}

Pass by reference

The other is known to receive not a copy of a value by reference, but an implicit reference to an object, such as the object's external direct reference address. Any change to the parameter inside the function affects the value of the object outside the function, because both refer to the same object, that is, the parameter is equivalent to the 1 individual name of the external object.

Pseudo code:


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 in the previous example
bar = {
  x: 10,
  y: 20
}
 
// The result of the call by reference is as follows:
foo(bar)
 
// The property value of the object has been changed
print(bar) // {x: 100, y: 200}
 
// The reassignment also affects the object
foo(bar, true)
 
// At this point the object is already 1 A new object
print(bar) // {z: 1, q: 2}

This strategy makes it more efficient to pass complex objects, such as large structured objects with a large number of attributes.

Press Shared delivery (Call by sharing)
The above two strategies are known to all, but here is one strategy that you may not be familiar with (it is actually an academic strategy). However, we will soon see that this is exactly the strategy that it plays a key role in the parameter passing strategy in ECMAScript.

This strategy also has some pronouns: "pass by object" or "pass by object Shared".

This strategy was proposed in 1974 by Barbara Liskov as the CLU programming language.

The point of this strategy is that the function receives a copy (copy) of the object pair, which is associated with the parameter and its value.

The reference that occurs here cannot be called "pass by reference," because the argument that the function receives is not a direct object alias, but a copy of the address of the reference.

Is the most important difference: internal to assign a new value to the parameter function does not affect the external objects (and on cases according to the reference case), but because this parameter is the address a copy, so in access, and outside access is with one object (such as outside the object not to pass by value 1 sample completely copy), change the attributes of the object parameter values will affect the external object.


procedure foo(barArg, isFullChange):
 
  if isFullChange:
    barArg = {z: 1, q: 2}
    exit
  end
 
  barArg.x = 100
  barArg.y = 200
 
end // Again, use this object structure
bar = {
  x: 10,
  y: 20
}
 
// Passing by contribution affects the object
foo(bar)
 
// The properties of the object have been modified
print(bar) // {x: 100, y: 200}
 
// The reassignment did not work
foo(bar, true)
 
// It's still the same value up here
print(bar) // {x: 100, y: 200}

This processing assumes that most languages use objects, not raw values.

Passing by share is a special case of passing by value

This Shared delivery strategy is used in many languages: Java, ECMAScript, Python, Ruby, Visual Basic, and so on. In addition, the Python community has already used the term, and it can be used in other languages as well, since other names tend to be confusing. In most cases, such as Java, ECMAScript, or Visual Basic, this 1 policy is also known as pass by value -- meaning: special value -- reference copy.

On the one hand, it looks like this -- the argument passed to the function for internal use is just a name of the binding value (reference address) and does not affect the external object.

On the other hand, without further study, these terms are really considered wrong, as many forums are talking about how to pass objects to JavaScript functions.

The general theory does say pass by value: but in this case the value is what we call a copy of the address, so it doesn't break the rules.

In Ruby, this strategy is called pass-by-reference. One more: it is not passed as a copy of the larger structure (for example, not by value), and on the other hand, we do not process the reference to the original object and cannot modify it; As a result, this cross-term concept can be even more confusing.

In theory there is no special case1 passed by value to interview special case passed by reference.

But it's still important to understand that these policies in the techniques mentioned above (Java, ECMAScript, Python, Ruby, other) actually -- the strategy they use is to pass by share.

Press share with pointer

For С/С + +, this strategy in thinking and pass by pointer value is 1, but there is one important difference, this strategy can dereference a pointer, and completely change the object. But in case 1, allocate 1 value (address) pointer to a new memory block (that is, the previously referenced memory block remains unchanged); Through the pointer to change the object property will affect adon external objects.

So, with pointer categories, we can clearly see that this is passed by address value. In this case, passing by share is just "syntactic sugar," like pointer assignment 1 (but not dereferencing), or modifying a property like reference 1 (no dereferencing required), which can sometimes be named "safe pointer."

С/С + + if, however, in the absence of obvious pointer dereferencing, reference object properties, also has a special syntax sugar:


obj->x instead of (*obj).x

The ideology most closely related to C++ can be seen in the implementation of "smart Pointers". For example, in boost :: shared_ptr, the assignment operator and copy constructor are overridden, and 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 ECMAScript's strategy for passing objects as arguments -- pass by share: changing the properties of the arguments will affect the external objects, while re-assignment will not affect the external objects. However, as we mentioned above, ECMAScript developer 1 is generally referred to as: pass by value, except that the value is a copy of the reference address.

Brendan asch, inventor of JavaScript, also wrote: "a copy of the quote is passed." So the forum everyone said by the value of the transfer, in this interpretation, is also correct.

Rather, this behavior can be understood as a simple assignment, where we can see that internally there are completely different objects, but the same values are referenced -- that is, the address copy.

ECMAScript code:


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 bindings) are bound to the same object in memory, and this object is Shared:

foo value: addr(0xFF) = > {x: 100, y: 200} (address 0xFF) < = bar value: addr(0xFF)
For reassignment assignment, the binding is a new object identifier (new address) without affecting the previously bound object:


bar = {z: 1, q: 2};
 
alert([foo.x, foo.y]); // [100, 200] � Didn't change
alert([bar.z, bar.q]); // [1, 2] � But now you're referring to a new object

Now foo and bar have different values and different addresses:

foo value: addr(0xFF) => {x: 100, y: 200} (address 0xFF)
bar value: addr(0xFA) => {z: 1, q: 2} (address 0xFA)

Again, 1, the value of the object is the address (address), not the object structure itself, assigning a variable to another variable -- a reference to the assigned value. Therefore, both variables refer to the same memory address. The next assignment is the new address, which is resolved to bind to the address of the old object, and then to the address of the new object, which is the most important difference from passing by reference.

In addition, if we only consider the level of abstraction provided by the ECMA-262 standard, we can only see the concept of "value" in the algorithm, the "value" (either the original value or the object) that is passed by the implementation, but it can also be fully "passed by value" according to our definition above, since the reference address is also a value.

However, in order to avoid misunderstandings (why external object properties can change within the function), still need to consider the details of the implementation level - here we see the share transfer, or in other words, according to the safety Pointers, and safe pointer impossible to remove references and changing object, but you can go to modify the object property values.

The term version

Let's define the glossary version of this policy in ECMAScript.

Call this "pass by value" -- the value in question is a special case, which means that the value is a copy of the address (address copy). At this level we can say that all objects except exceptions in ECMAScript are passed by value, which is actually the level of abstraction of ECMAScript.

Or for this case, it is called "pass by share", through which we can see the difference between traditional pass by value and pass by reference. This case can be divided into two types: 1. 2: object is passed by sharing.

The phrase "putting objects into functions by reference types" has nothing to do with ECMAScript, and it's wrong.

conclusion

I hope this article will help you understand more details at the macro level, as well as the implementation in ECMAScript. As always, if you have any questions, please feel free to discuss.


Related articles: