Learn more about function calls in JavaScript

  • 2021-08-05 08:58:17
  • OfStack

Definition

Probably many people in the process of learning JavaScript encountered function parameters pass the confusion, in the spirit of in-depth, I want to find some answers in the source code, but before doing this, first clear a few concepts. Abandon the inherent names such as drop value transfer and reference transfer and return to English:

call by reference & & call by value & & call by sharing

They are reference passing and value passing in C + +. The third kind is confusing, and the official explanation is receives the copy of the reference to object. Let me explain it in popular words:

Object can be understood as the collection of key, and the data pointed by Object to key is referential (whether it is pointer implementation or C + + reference implementation is not delved into here). The function receives copy of a variable, and the variable contains the reference of Object, which is a value pass.

Then obviously, when the function passes parameters, the object parameters we receive are actually copies of arguments, so it is not feasible to directly change the direction of parameters; Since the key of Object itself is a reference, it is feasible to modify the pointing of key.

Proof

It can be proved by a few pieces of code

Code 1: The function can modify the data pointed to by key


let func = obj => { obj.name = 'Dosk' };
let obj = {name : 'Alxw'};
console.log(obj); //{ name: 'Alxw' }
func(obj)
console.log(obj); //{ name: 'Dosk' }

Code 2: Function cannot modify obj


let func = obj => { obj = {} };
let obj = {name : 'Alxw'};
console.log(obj); //{ name: 'Alxw' }
func(obj)
console.log(obj); //{ name: 'Alxw' }

Code 3: Internal obj and external = = = result equal


let def = {name : 'Alxw'};
let func = obj => { console.log(obj === def) };
func(def); //true

So the code in paragraph 3 may be in question. Since obj is a copy of def, why can the === operation still be true? Isn't it said that the = = = operation for Object is compared to the address in memory, if it is copied, it should be false?

So let's go back to the source code of Google V 8 to look at this matter.

In-depth Google V8

Let's take a look at the strictly equal operation code part of the source code:


bool Object::StrictEquals(Object* that) {
 if (this->IsNumber()) {
  if (!that->IsNumber()) return false;
  return NumberEquals(this, that);
 } else if (this->IsString()) {
  if (!that->IsString()) return false;
  return String::cast(this)->Equals(String::cast(that));
 } else if (this->IsSimd128Value()) {
  if (!that->IsSimd128Value()) return false;
  return Simd128Value::cast(this)->Equals(Simd128Value::cast(that));
 }
 return this == that;
}

It seems that it should be the last case. In theory, if def and obj are different objects, then false should be returned. Isn't this overturning the above? In fact, I ignore one thing, that is, when instantiating an Object in Google V8, it is dynamic instantiation itself, but we know that in compiled languages, if dynamic instantiation can only be on heap memory, it can only be referenced by pointers. This conclusion is that the proof involves Local, Handle and other class implementation, I think too much trouble, there is a simple way to prove, that is, search the source code to get all calls Object::StrictEquals All the places are passed in directly without taking the address.

However, some people may ask, since the variable passed by the value contains a reference to Object, it is theoretically possible to modify Object. Why can't the code in paragraph 3 be modified?

Very simple reason, because our so-called operation at the logical level of JavaScript language is just calling the method of the instance side of Google V8, and it is impossible to operate to this point (of course, the potential BUG does not count-. -)

Redefine

I think we can reinterpret call by sharing here:

Yes, it's a value pass, but it contains a pointer to Object, and it can't be modified. It's shared by multiple variables.

Another simple proof

Come on, come on, look at the source code


V8_DEPRECATE_SOON("Use maybe version",
         Local<Value> Call(Local<Value> recv, int argc,
                  Local<Value> argv[]));
V8_WARN_UNUSED_RESULT MaybeLocal<Value> Call(Local<Context> context,
                       Local<Value> recv, int argc,
                       Local<Value> argv[]);

The above is the interface that is about to be deprecated. It happens that this version of the code I saw contains a lot of this code that is about to be deprecated. Just look at it. The focus is on the second interface, which is the only one call interface of the function. Inside Local<Value> Eventually the bit copy of C + + will be called, so it can be simply proved that it is value passing.

Could be the point

Don't forget, the variables we define are all similar Handle<Object> In this form, so the objects between them are shared, and the variables in JavaScript do not directly refer to the instances of Object! ! !

Last last

It may be difficult and even wrong to understand, but it is important to be able to identify the features at the JavaScript level.


Related articles: