In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-30 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
In this issue, the editor will bring you about how to achieve JavaScript sharing and value delivery. The article is rich in content and analyzes and describes for you from a professional point of view. I hope you can get something after reading this article.
There are many misunderstandings and arguments on the Internet about how JavaScript passes values to functions. It is generally believed that parameters are passed by value when they are raw data classes, and data types such as arrays, objects, and functions are passed by reference.
The main difference between passing parameters by value and passing parameters by reference can be simply said:
Pass by value: changing the passed value in the function will not affect the outside
Reference passing: changing the value passed in the function will affect the outside.
But the answer is that JavaScript uses pass-by-value for all data types. It uses pass-by-value for arrays and objects, but this is used in shared or copied references to. This is a bit abstract, so let's start with a few examples, and then we'll look at JavaScript's memory model during function execution to see what's actually going on.
Pass parameters by value
In JavaScript, the data of the original type passes parameters by value; the object type, like Java, copies a reference to the original object and manipulates it. But in JS, string is a primitive type data rather than an object class.
Let setNewInt = function (I) {ii = I + 33;}; let setNewString = function (str) {str + = "cool!";}; let setNewArray = function (arr1) {var b = [1,2]; arr1 = b;}; let setNewArrayElement = function (arr2) {arr2 [0] = 105;}; let I =-33; let str = "I am"; let arr1 = [- 4,-3]; let arr2 = [- 19,84] Console.log ('I is:'+ I +', str is:'+ str +', arr1 is:'+ arr1 +', arr2 is:'+ arr2); setNewInt (I); setNewString (str); setNewArray (arr1); setNewArrayElement (arr2); console.log ('now, I is:' + I +', str is:'+ str +', arr1 is:'+ arr1 +', arr2 is:'+ arr2)
Running result
I is:-33, str is: I am, arr1 is:-4 is 3, arr2 is:-19 am 84 now, I is:-33, str is: I am, arr1 is:-4 arr1 is 3, arr2 is: 105
Here are two things to pay attention to:
1) * the string str is passed in through the setNewString method. If you have learned an object-oriented language, such as str str, etc., you will think that the value of the string is changed after calling this method, and the reference that is of type string in the object-oriented language is an object, and parameters are passed by reference, so the outside of changing Java in this method will also change.
But in JavaScript, as mentioned earlier, in JS, string is a primitive type data rather than an object class, so it is passed by value, so changing the value of str in setNewString does not affect the outside.
2) the second is to pass the array arr1 through the setNewArray method, because the array is an object type, so it is reference passing. In this method, we change the direction of the arr1, so if it is in this object-oriented language, we think that the value of the result arr1 of * * is the one that is re-pointed, that is, [1, 2], but the print result of * * shows that the value of arr1 is still the original value. Why?
Shared delivery
The answer given by Community Wiki on Stack Overflow is: for the object type passed to the function parameter, if you directly change the pointing address of the copied reference, it will not affect the original object; if you use the copied reference to operate on the internal value, it will change to the original object.
Please refer to the blog JavaScript Fundamentals (2)-Is JS call-by-value or call-by-reference?
Function changeStuff (state1, state2) {state1.item = 'changed'; state2 = {item: "changed"};} var obj1 = {item: "unchanged"}; var obj2 = {item: "unchanged"}; changeStuff (obj1, obj2); console.log (obj1.item); / / obj1.item will be changed console.log (obj2.item); / / obj2.item will not be changed
Reason: the above state1 is equivalent to obj1, and then the item attribute inside the obj1.item = 'changed', object obj1 is changed, which naturally affects the original object obj1. Similarly, state2 is also obj2. In the method, state2 points to a new object, that is, to change the original reference address, which will not affect the external object (obj2). This phenomenon is more professionally called call-by-sharing, which is temporarily called shared delivery for convenience.
Memory model
JavaScript allocates three parts of memory to the program during execution: the code area, the call stack, and the heap. The combination of these is called the address space of the program.
Code area: this is the area where the JS code to be executed is stored.
Call heap:: this area tracks the currently executing function, performs calculations, and stores local variables. Variables are stored in the stack using a later-in-first-out method. * one comes in and the other goes out, and the numerical data types are stored here.
For example:
Var corn = 95
Let lion = 100
Here, the variables corn and lion values are stored in the stack during execution.
Heap: this is where JavaScript reference data types, such as objects, are allocated. Unlike the stack, memory allocation is randomly placed and there is no LIFO policy. To prevent memory vulnerabilities in the heap, the JS engine has a memory manager to prevent them from happening.
Class Animal {} / / Stack value for storing new Animal instance / / tiger at memory address 0x001232 is 0x001232 const tiger = new Animal () / / Stack value for storing new Objec instance / / `lion` at memory address 0x000001 is 0x000001 let lion = {strength: "Very Strong"}
Here,lion and tiger are reference types whose values are stored in the heap and pushed onto the stack. Their value in the stack is the memory address of the location in the heap.
Activation record (Activation Record), parameter passing
Now that we've seen the memory model of the JS program, let's see what happens when functions are called in JavaScript.
/ / example 1: function sum (num1,num2) {var result = num1 + num2 return result} var a = 90 var b = 100 sum (a, b)
Whenever a function is called in JS, all the information needed to execute the function is placed on the stack. This information is called Activation Record.
This Activation Record, I literally translated as activation record, found a lot of information, did not see a better translation in Chinese, if friends know, welcome to leave a message.
The information on the activation record includes the following:
SP stack pointer: the current position of the stack pointer before the method is called.
RA return address: this is the address to continue execution after the function execution is complete.
RV return value: this is optional, and the function can return a value or no value.
Parameters: push the parameters required by the function onto the stack.
Local variables: the variables used by the function are pushed to the stack.
We must know that the code we write in the js file is compiled into the machine language by the JS engine (such as V8 Magi Rhino SpiderMonke y, etc.) before execution.
So the following code:
Let shark = "Sea Animal"
Will be compiled into the following machine code:
01000100101010 01010101010101
The above code is equivalent to our js code. There is a language between machine code and JS, which is assembly language. The code generator in the JS engine compiles the js code into assembly code before finally generating the machine code.
In order to understand what actually happened and how to push the activation record onto the stack during a function call, we must understand how the program is represented in assembly.
To track how the parameters are passed in JS during a function call, we use assembly language to represent the code in example 1 and track its execution.
Let's start with a few concepts:
ESP: (Extended Stack Pointer) is an extended stack pointer register, a kind of pointer register, which is used to store the pointer at the top of the function stack. The counterpart is EBP (Extended Base Pointer), which extends the base pointer register, also known as the frame pointer register, for storing the bottom pointer of the function stack.
EBP: the extended base address pointer register (extended base pointer) holds a pointer to the bottom of the top stack frame of the system stack.
EBP only accesses ESP at a certain time, that is, after entering a function, cpu assigns the value of ESP to EBP. At this time, you can use EBP to operate on the stack, such as obtaining function parameters and local variables. In fact, you can also use ESP.
/ / example-function sum (num1,num2) {var result = num1 + num2 return result} var a = 90 var b = 100 var s = sum (a, b)
We see that the sum function has two arguments, num1 and num2. The function is called, passing an and b with values of 90 and 100, respectively.
Remember: the value data type contains values, while the reference data type contains memory addresses.
Push its parameters onto the stack before calling the sum function
ESP- > [.] ESP- > [100] [90] [.]
It then pushes the return address to the stack. The return address is stored in the EIP register:
ESP- > [Old EIP] [100] [90] [.]
Next, it saves the base pointer
ESP- > [Old EBP] [Old EIP] [100] [90] [.]
Then change the EBP and push the call save register onto the stack.
ESP- > [Old ESI] [Old EBX] [Old EDI] EBP- > [Old EBP] [Old EIP] [100] [90] [.]
Allocate space for local variables:
ESP- > [] [Old ESI] [Old EBX] [Old EDI] EBP- > [Old EBP] [Old EIP] [90] [.]
Add is performed here:
Mov ebp+4, eax; 100add ebp+8, eax; eaxeax = eax + (ebp+8) mov eax, ebp+16 ESP- > [190] [Old ESI] [Old EBX] [Old EDI] EBP- > [Old EBP] [Old EIP] [100] [90] [.]
Our return value is 190, which is assigned to EAX.
Mov ebp+16, eax
EAX is the "accumulator", which is the default register for many addition and multiplication instructions.
Then, all register values are restored.
DELETED [Old ESI] DELETED [Old EBX] DELETED [Old EDI] DELETED [Old EBP] DELETED [Old EIP] DELETED ESP- > [100] [90] EBP- > [.]
The control is returned to the calling function, and the parameters pushed to the stack are cleared.
DELETED [Old ESI] DELETED [Old EBX] DELETED [Old EDI] DELETED [Old EBP] DELETED [Old EIP] DELETED [90] DELETED [90] DELETED [ESP, EBP]-> [.]
The calling function now retrieves the return value from the EAX register to the memory location of s.
The location of the mov eax, 0x000002; / / s variable in memory
We have seen what happens in memory and how to pass parameters to assembly code functions.
Before calling the function, the caller pushes the parameters onto the stack. Therefore, it is correct to say that passing a parameter in js is a copy of the input value. If the called function changes the value of the parameter, it does not affect the original value, because it is stored somewhere else, and it handles only one copy.
Function sum (num1) {num1 = 30} let n = 90 sum (n) / / `n` is still 90
Let's see what happens when you pass a reference data type.
Function sum (num1) {num1 = {number:30}} let n = {number:90} sum (n) / / `n` is still {number:90}
To express in assembly code:
N-> 0x002233 Heap: Stack: 002254 012222... 012223 0x002233 002240 012224 002239 012225 002238 002237 002236 002235 002234 002233 {number: 90} 002232 002231 {number: 30} Code:... 000233 main: / / entry point 000234 push n / / n value is 002233, which points to the address stored in the heap {number: 90}. N is pushed to the 0x12223 of the stack. 000235; / / Save all registers... 000239 call sum; / / Jump to the `sum` function 000240... 000270 sum: 000271 in memory; / / create the object {number: 30} inner address main 0x002231 000271 mov 0x002231, (ebp+4); / / move the memory address to 0x002231 {number: 30} to the stack (ebp+4). (ebp+4) is the address 0x12223, that is, the address where n is also the location of object {number: 90} in the heap. Here, the stack position is overridden by the value 0x002231. Now, num1 points to another memory address. 000272; / / Clean the stack... 000275 ret; / / return to the caller's location (000240)
We see here that the variable n holds the memory address that points to its value in the heap. When the sum function executes, the parameters are pushed to the stack and received by the sum function.
The sum function creates another object {number:30}, which is stored in another memory address 002231 and placed in the parameter location of the stack. Replace the memory address of the object {number:90} at the parameter location on the previous stack with the memory address of the newly created object {number:30}.
This keeps n unchanged. Therefore, the copy reference policy is correct. The variable n is pushed onto the stack so that it becomes a copy of n when sum executes.
This statement num1 = {number:30} creates a new object in the heap and assigns the memory address of the new object to the parameter num1. Note that before num1 points to n, let's test to verify:
/ / example1.js let n = {number: 90} function sum (num1) {log (num1 = n) num1 = {number: 30} log (num1 = n)} sum (n) $node example1 true false
Yes, we are right. As we see in the assembly code. Initially, num1 refers to the same memory address as n, because n is pushed onto the stack.
Then, after creating the object, reassign the num1 to the memory address of the object instance.
Let's further modify our example 1:
Function sum (num1) {num1.number = 30} let n = {number: 90} sum (n) / / n becomes {number: 30}
This will have almost the same memory model and assembly language as the previous one. Only a few things are different here. In the implementation of the sum function, no new object is created, and this parameter is directly affected.
... 000270 sum: 000271 mov (ebp+4), eax; / / copy the parameter values to the eax register. Eax is now 0x002233 000271 mov 30, [eax]; / / move 30 to the address pointed to by eax
Num1 is (ebp+4) and contains the address of n. The value is copied into eax and 30 is copied into the memory pointed to by eax. The curly braces [] on any register tell CPU not to use the value found in the register, but to get the value of the memory address number corresponding to its value. Therefore, the {number: 90} value of 0x002233 is retrieved.
Take a look at the answer:
The original data type is passed by value and the object is passed through a copy of the reference.
Specifically, when you pass an object (or array), you pass a reference to the object invisibly, and you can modify the contents of the object, but if you try to overwrite the reference, it will not affect the copy of the object-that is, the reference itself is passed by value:
Function replace (ref) {ref = {}; / / this code does not affect the passed object} function update (ref) {ref.key = 'newvalue'; / / this code does affect the content of the object} var a = {key:' value'}; replace (a); / a still has its original value, it has no modified update (a); / / the content of / a has been changed
From what we see in the assembly code and the memory model. The answer is correct. Inside the replace function, it creates a new object in the heap and assigns it to the ref parameter, and the an object's memory address is rewritten.
The update function references the memory address in the ref parameter and changes the key property of the object stored in the memory address.
Summary
From what we have seen above, we can say that copies of the original and reference data types are passed to the function as arguments. The difference is that, in the original data types, they are only referenced by their actual values. JS does not allow us to get their memory addresses, unlike in C and C++ programming learning and experimental systems, reference data types refer to their memory addresses.
The above is the editor for you to share how to achieve JavaScript sharing transmission and by value delivery, if you happen to have similar doubts, you might as well refer to the above analysis to understand. If you want to know more about it, you are welcome to follow the industry information channel.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.