JavaScript Jems - Objects Are Anonymous Singletons |
Written by Mike James | |||||
Monday, 05 February 2024 | |||||
Page 2 of 4
There Is Only Reference - BoxingSimple though it is, the use of reference rather than value is still the source of confusion. As the actual assignment mechanism is the same in both cases – the contents of variables are always copied – it is what is copied that varies, a value or a reference. This being the case it should be possible to think of it as a single mechanism and it is. The key is to keep in mind that everything is an object and now consider the assignment that we previously considered a value assignment: let myVar1=42; let myVar2=myVar1; myVar2=0; Now think of the first assignment as myVar references the Number object 42. The second assignment assigns the reference to myVar2 now both variables reference the same object i.e. 42. Finally when we set myVar2 to reference Number object 0 obviously this has no effect on number object 42 or what myVar1 references. If you think of numbers as instances of the Number object then there is no value assignment. OK, you might want to argue that this is a very thin reinterpretation, so what about something a little more complicated like: let myVar1=42; let myVar2=myVar1+1; Again there is no problem with interpreting this as reference semantics as long as you interpret the arithmetic expression as an object expression. As explored in Jem 6. an object expression takes the values of any objects within it, and combines them to create a new numeric object. Now myVar2 can be thought of as referencing the new Number object 43. You can explore this idea a little more – primitives have corresponding objects and these objects have properties. For example: let myVar1=new Number(42); myVar1.myProperty="deep thought"; alert(myVar1.myProperty); let myVar2=myVar1; alert(myVar2.myProperty); Although this may seem a little strange, it is reference semantics in action with something you would usually consider a value. In this case 42 really is a Number object and we have added a property. Now when we assign to myVar2 a reference assignment occurs and myVar2 references the same 42 object that myVar1 does. As a result you see deep thought displayed each time. What happens if you use a Number object in an expression? The expression makes use of the Number object’s value and creates a new value as the result. So for example: let myVar2=myVar1+1; alert(myVar2.myProperty); In this case myVar2 is assigned to a brand new 43 object and the resulting alert displays undefined as the new object doesn’t have a myProperty. Of course, this isn’t exactly what happens. The 43 stored in myVar2 is actually a value and not an object. The reason is that this is the way things have to be done for efficiency. However, this doesn’t stop us from thinking about it in the way described. Some languages make use of an idea called “autoboxing” to allow the illusion that everything is an object to extend to primitive values. Autoboxing promotes any value to a real object if you do something that needs the value to be an object. For example: let myVar1=42; myVar1.myProperty="deep thought"; alert(myVar1.myProperty); First myVar1 is stored the primitive value 42. When we use the value as an object in the second line, autoboxing converts the 42 into a full Number object, and everything works. However, if you try this out you will discover that the alert displays undefined. The reason is that JavaScript’s autoboxing isn’t persistent. As soon as possible, the primitive value is unboxed and returned to a primitive value, again for reasons of efficiency. This is a shame because it spoils the illusion that everything is an object. JavaScript would be a more elegant language with persistent autoboxing. There are only two occasions when JavaScript autoboxes a value. The first, as we have seen, is when you make use of a value as if it was an object, but this is a temporary boxing. The second is when you set this to a value in call or apply. This is because both apply and call assume that you are calling a method and need an object for this. The boxing only applies for the duration of the function call. The point is that if everything is an object then there are only references and reference semantics. The fact that we have to deal with the confusion of value semantics is purely because we have to use values for reasons of efficiency. In an ideal world values would not exist as a concept. Objects Are AnonymousSo far everything is standard and much as you will find in almost any object-oriented language. Objects are not stored in variables - references to objects are stored in variables. This also has the implication that objects don't have an immutable name associated with them. They are essentially anonymous. For example: let center=new Point(10,10); is often thought of as creating a new object, an instance of Point, called center. Of course, this isn't the case. The variable center is only associated with the instance of the object until it is assigned to reference another object. Other variables with completely inappropriate names could also reference the instance: let button=center; This is the case in languages, such as Java, that are class-based and strongly-typed. Strong typing, however, does insist that both button and center are of type Point and this is thought to be an advantage, even though it doesn't stop you using inappropriate names for variables. The key idea, and this is true in most object-oriented languages, is that objects do not have fixed names - just references. In a class-based language at least the class name is fixed and gives an object some form of identity, but the idea that we name objects is myth - we name variables that reference them. Functions Are AnonymousThis section really has nothing to add because, as long as you accept that functions are just objects and objects are anonymous, then it is obvious that functions are also anonymous. The problem is that we really don't believe that functions are anonymous. For example if you write a function: function sum(A,B){ return A+B; } then the function's name is sum and this reflects what it does. However, sum is just a reference to the function object and you can create new references and change the original. For example: let mul=sum; let sum=myObject; Now you can call the summation function using: mul(1,2); and if you try to call the summation function using the sum variable you will see an error message. The reason for the function statement is to make JavaScript functions seem more like functions in other languages. The function declaration: function sum(A,B){ return A+B; } is very similar to: let sum=function(A,B){ return A+B; } where the assignment of a reference to a variable is made explicit. However, there are some differences. The most important is that the function statement is hoisted, as explained in Jem 13, whereas the = assignment isn't. In addition, most implementations of JavaScript keep the name associated with a function declaration so that debugging is easier, i.e. errors are reported along with the function's name. In this sense functions do have fixed names, but not as part of the runtime behavior. |
|||||
Last Updated ( Monday, 05 February 2024 ) |