about
Bits Objects JavaScript
02/08/2024
0
Bits Repo Code Bits Repo Docs

Bits: JavaScript Objects

library and user-defined classes and objects

Synopsis:

This page demonstrates uses of JavaScript User-Defined types and their objects. The purpose is to quickly acquire some familiarity with user-defined types and their implementations.
  • JavaScript defines one special class method constructor().
  • The compiler will generate an empty constructor method if the class does not.
  • Also, this is the first set of examples to partition code into several files. That supports readability, may improve translation times, and makes maintenance significantly easier.
Demo Notes  
All of the languages covered in this demonstration support classes. Each class provides a pattern for laying out a memory footprint and defines how data within are accessed. Three of the languages: C++, Rust, and C# provide generics. Each generic function or class is a pattern for defining functions and classes of a specific type. Thus a generic is a pattern for making patterns. The other two, Python and JavaScript, are dynamically typed and already support defining functions and classes for multiple types, e.g., no need for generics. This demonstration illustrates use of classes and objects, which for C++, Rust, and C#, are defined in a stackframe or in the heap or both. All data for Python and JavaScript are stored in managed heaps.
The examples below show how to use library and user defined types with emphasis on illustrating syntax and basic operations.

1.0 Source Code

This source code is partitioned into an HTML file, Bits_ObjectsJs.html, with embedded JavaScript and CSS styles, and two script files, Point.js and Analysis.js. Partitioning enables building parts that focus on a single mission. That makes the code base easier to understand and maintain.

1.1 Point user-defined type

JavaScript has an object creation process using the JavaScript type Object. All objects have a prototype pointer __proto__ used to form inheritance chains. Prototype chains terminate with an instance of Object. Object provides methods like toString() that all objects can access. When a function is invoked on an object, but not found in the object's methods, lookup walks up the prototype chain until it finds the method or fails to find the method in the terminal Object instance. Failure results in a thrown exception. Since the release of the JavaScript standard ECMAScript 6, the class construct has provided a wrapper around this basic object prototype model. In this first code block we use a class, but will illustrate later the underlying object model in Sections 1.3, 1.4, and 1.5. Point4D is a user-defined type defined with a JavaScript class.
/*----------------------------------------------
    using JavaScript class
*/

  const nlp = "<br />";
  const tabp = "  "

  class Point4D {
    constructor(x, y, z) {
      this.x = x;
      this.y = y;
      this.z = z;
      this.t = new Date();
    }
    show(name) {
      document.write(name, ": Point4D {", nlp, tabp);
      document.write(this.x, ", ", this.y, ", ", this.z, nlp, tabp);
      document.write(this.t);
      document.write(nlp, "}", nlp);
    }
    update_time() {
      this.t = new Date();
    }
  }

Concept:

Point4D holds data for a point in 3 dimensional space and a time when something was at that point. These points could be collected into an array that represents a trajectory of movement of a game controller.

JavaScript class syntax:

Member data, like all JavaScript data, resides in a managed heap. A class's members are attached at time of construction, not defined statically as in C++, Rust, and C#. Each class provides a constructor method that defines the name and value of its data items. There are no other special methods required for JavaScript objects, but methods can be added as show here with the show(name) and update_time() methods.

1.2 Source Code Structure

This block presents the Bits_ObjectsJS.html with all of the demonstration code details elided, allowing us to see clearly how the page is composed from its parts.
<!DOCTYPE html>
<html>
<!--
  Js_Objects.html

  Illustrate creation and use of JavaScript objects.

  JavaScript Types.
    Number, Bigint, Boolean, String,
    Undefined, Null, Symbol, Object
    - arrays are typed as objects
    Other important library types:
    - Date, Maps, Sets, JSON,

    All of these are reference types.
    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures
-->
<head>
    <script src="Analysis.js"></script>
    <script src="Point.js"></script>
    <script>

    /*----------------------------------------------
      display text heading
    */
    function heading() {
      /*-- code elided --*/
    }
    /*----------------------------------------------
      built in objects
    */
    function demo_builtin() {
      /*-- code elided --*/
    }
    /*----------------------------------------------
        crafting object by hand
    */
    function demo_Object() {
      /*-- code elided --*/
    }
    /*----------------------------------------------
      using JavaScript class
    */
    function demo_Point4D() {
      /*-- code elided --*/
    }
    /*----------------------------------------------
      exploring concequences of JS object model
    */
    function demo_reftype() {
      /*-- code elided --*/
    }

    /*------------------------------------------------
      Demonstration starts here
    */
    function execute() {
      showNote("Demo Objects")

      demo_builtin();
      demo_Object();
      demo_Point4D();
      demo_reftype();

      print(nl + "That's all Folks!" + nl);
    }
  </script>
  <style>
    body {
      font-family:'Comic Sans MS', Tahoma;
      padding:2em;
    }
  </style>
</head>
<body>
  <div id="objects"></div>
  <script>
    heading();
    execute();
  </script>
</body>
</html>

Page structure:

An html element contains head and body elements. head provides declarations for its document with <script> and <style> elements. The body element contains child elements that are rendered, and script blocks that are executed. It is important that executing JavaScript works with a completely loaded document, so script elements in the body should always be placed at its end.

Dependencies:

This demonstration depends on loaded files "Analysis.js"e, providing analysis and display functions, and "Point.js" that defines a Point4D type. The head element defines five demonstration functions that partition processing into small digestiable blocks and an execute() function that invokes each of the demonstration functions in order.

Execution:

Functions defined in the head are translated but not immediately invoked. At the bottom of the body element there is a script block that invokes heading() and execute(). Each of the code blocks, below, illustrates code and output for one of the demonstration functions.

1.3 Built-in Types

JavaScript types are determined not by declarations, but by the way variables are initialized. Initialization assigns literals, like "3.14159" or the result of a construction, like "new Date() to a label, e.g., variable name, as in "let dt = new Date(). This demo illustrates creation and simple use of doubles, strings, arrays, and objects.
function demo_builtin() {
  showNote("Built-in instances", 25);
  let d = 3.1415927;
  showType(d, "d");
  println("---");

  let s = "s";
  showType(s, "string");
  println("---");

  let a = [1, 2, 3];
  showType(a, "array");
  println("---");

  let o = new Object();
  o.elem = "some element";
  o.say = function() { document.write("Hello" + nl)};
  showType(o, "o");
  o.say();

  showOp("more elaborate data");
  let arr = [1, 'z', [1, 2, 3], true];
  showType(arr, "arr");
  println("---");

  /* add show method to existing array */
  println(
    "you can add new elements to any object, including" + nl +
    "scalar data, composite data like arrays and functions."
  )
  arr.show = function(nm) {
    document.write(nm, " [ ");
    arr.forEach(element => {
      document.write(element, " ");
    });
    document.write("]" + nl);
  }
  showOp("arr.show(nm)");
  arr.show("arr");
  println(nil);

  println(
    "Here see the results of using two other analyzer methods" +nl +
    "on the arr array:"
  )
  /*------------------------------------------------------------------
    showTypeShowable uses show(...) method provided by analyzed type.
    It works with any object that provides a show(...) method.
  */
  /* so now showTypeShowable can be used */
  showOp("showTypeShowable(arr, \"arr\")");
  showTypeShowable(arr, "arr");
  showOp("showObject(arr, \"arr\")");
  showObject(arr, "arr");
  print(nl);
}
-------------------------
  Built-in instances
-------------------------
d: number
size: 8, value: 3.1415927
---
string: string
size: 2, value: s
---
type: object
array: [
    1, 2, 3
]
size: 24
---
type: object
o: {
    "elem":"some element"
}
size: 24
Hello
--- more elaborate data ---
type: object
arr: [
    1, "z", [1,2,3], true
]
size: 38
---
you can add new elements to any object, including
scalar data, composite data like arrays and functions.
--- arr.show(nm) ---
arr [ 1 z 1,2,3 true ]

Here see the results of using two other analyzer methods
on the arr array:
--- showTypeShowable(arr, "arr") ---
arr, object, size: 38
value: arr [ 1 z 1,2,3 true ]
--- showObject(arr, "arr") ---
arr: [
    1, "z", [1,2,3], true
]














1.4 User-defined Objects

JavaScript objects have been traditionally defined using a literal construction:
let obj1 = { a:"...", b:"...", ... }
or by using the default object constructor:
let obj2 = new Object();
obj2.a = "..."; obj2.b = "...", ...
You saw an example use of the object constructor in Section 1.3. In this section find an example of the literal construction method.
function demo_Object() {
  showNote("User-defined object literal", 35);

  const dev = {
    name:"Jim",
    job:"Retired from Syracuse University",
    hobby:"Developing software",
    projects: [ 'Bits language comparisons', 'Stories', 'Bites' ]
  }
  showObject(dev, "dev");

  /* creating show function tailored to dev objects */
  dev.show = function(nm) {
    document.write(nm, ": {",nl,tab,"name: ", this.name,
    nl, tab, "job: ", this.job, nl, tab, "hobby: ",
    this.hobby, nl, tab, "projects: ", this.projects,
    nl, "}<br />");
  }
  /* using 3 ways to display information about an object */
  showOp("dev.show(\"dev\")");
  dev.show("dev");
  showOp("showTypeShowable(dev, \"dev\")");
  showTypeShowable(dev, "dev");
  showOp("showType(dev, \"dev\")");
  showType(dev, "dev", 4, 1);
}




-----------------------------------
  User-defined object literal
-----------------------------------
dev: {
    "name":"Jim", "job":"Retired from Syracuse University", "hobby":"Developing software", "projects":["Bits language comparisons","Stories","Bites"]
}
--- dev.show("dev") ---
dev: {
  name: Jim
  job: Retired from Syracuse University
  hobby: Developing software
  projects: Bits language comparisons,Stories,Bites
}
--- showTypeShowable(dev, "dev") ---
dev, object, size: 182
value: dev: {
  name: Jim
  job: Retired from Syracuse University
  hobby: Developing software
  projects: Bits language comparisons,Stories,Bites
}
--- showType(dev, "dev") ---
type: object
dev: {
    "name":"Jim",
    "job":"Retired from Syracuse University",
    "hobby":"Developing software",
    "projects":["Bits language comparisons","Stories","Bites"]
}
size: 182

1.5 Point4D

This section illustrates use of the Point4d type defined in Points.js and discussed in Section 1.1.
function demo_Point4D() {
  showNote("Using JavaScript class", 30);
  let p1 = new Point4D(1, 2, 3);
  showOp("showObject(p1, \"p1\")");
  showObject(p1, "p1");
  showOp("p1.show(\"p1\")");
  p1.show("p1");
  showOp("showTypeShowable(p1, \"p1\")");
  showTypeShowable(p1, "p1");
  showOp("showType(p1, \"p1\")");
  showType(p1, "p1: Point1");
  println(nil);

}










------------------------------
  Using JavaScript class
------------------------------
--- showObject(p1, "p1") ---
p1: {
    "x":1, "y":2, "z":3, "t":"2024-02-08T16:38:22.965Z"
}
--- p1.show("p1") ---
p1: Point4D {
  1, 2, 3
  Thu Feb 08 2024 10:38:22 GMT-0600 (Central Standard Time)
}
--- showTypeShowable(p1, "p1") ---
p1, object, size: 24
value: p1: Point4D {
  1, 2, 3
  Thu Feb 08 2024 10:38:22 GMT-0600 (Central Standard Time)
}
--- showType(p1, "p1") ---
type: object
p1: Point1: {
    "x":1, "y":2, "z":3, "t":"2024-02-08T16:38:22.965Z"
}
size: 24

1.6 Consequences of Reference Types

All Python variables are bound to their values in the managed heap by references. That means that assignment and construction from another object results in two references pointing to the same heap-based instance. That behavior is demonstrated in this section using a Point4D instance.
function demo_reftype() {
  showNote(
    "Exploring consequences of JavaScript reference types:", 65
  )
  let p1 = new Point4D(0, 1, 2);
  p1.show("p1");

  showOp("let p2 = p1");
  let p2 = p1;
  p2.show("p2");

  isSameObject(p2, "p2", p1, "p1");
  showOp("p2.z = -42");
  p2.z = -42;
  p2.show("p2");
  p1.show("p1");
  isSameObject(p2, "p2", p1, "p1");
  showNote(
    "All JavaScript variables are reference types. So assignments assign" + nl +
    "  " + "references, not values. And so changing target, p2, changed source, p1",
    85
  )
  print(nl);




-----------------------------------------------------------------
  Exploring consequences of JavaScript reference types:
-----------------------------------------------------------------
p1: Point4D {
  0, 1, 2
  Thu Feb 08 2024 10:38:22 GMT-0600 (Central Standard Time)
}
--- let p2 = p1 ---
p2: Point4D {
  0, 1, 2
  Thu Feb 08 2024 10:38:22 GMT-0600 (Central Standard Time)
}
p2 is same object as p1
--- p2.z = -42 ---
p2: Point4D {
  0, 1, -42
  Thu Feb 08 2024 10:38:22 GMT-0600 (Central Standard Time)
}
p1: Point4D {
  0, 1, -42
  Thu Feb 08 2024 10:38:22 GMT-0600 (Central Standard Time)
}
p2 is same object as p1
-------------------------------------------------------------------------------------
  All JavaScript variables are reference types. So assignments assign
  references, not values. And so changing target, p2, changed source, p1
-------------------------------------------------------------------------------------

2.0 Analysis and Display

/*------------------------------------------------
    Display and Analysis functions
*/
const nl = "<br />";
const tab = "  "
const nil = "";

function print(str) {
  document.write(str);
}
function println(str) {
  document.write(str + "<br />");
}
/*------------------------------------------------
  Display emphasized text
*/
function showNote(text, n=20) {
  let s = '-'.toString().repeat(n);
  document.write(s + "<br />");
  document.write("<span>  </span>", text, "<br />");
  document.write(s + "<br />");
}
/*------------------------------------------------
  Show an operation expression surrounded with a few dashes
*/
function showOp(text) {
  document.write("--- ");
  document.write(text)
  document.write(" ---<br />");
}
/*--------------------------------------------------------------------
Show basic type information
*/
function showType(t, nm, left=4, width=7) {
  if(typeof t != typeof Object()) {
    println(nm + ": " + typeof t);
    print("size: " + sizeof(t) + ", value: " + t);
  }
  else {
    println("type: " + typeof t);
    showObject(t, nm, left, width);
    print("size: " + sizeof(t));
  }
  println(nil);
}
/*--------------------------------------------------------------------
Show type information using object's show() method
*/
function showTypeShowable(t, nm) {
  print(nm + ", " + typeof t);
  print(", size: ");
  println(sizeof(t));
  print("value: ");
  t.show(nm);
}
/*--------------------------------------------------------------------
Do references o1 and o2 have same address (point to same instance)
*/
function isSameObject(o1, nm1, o2, nm2) {
  if (o1 === o2) {
    println(nm1 + " is same object as " + nm2)
  }
  else {
    println(nm1 + " is not same object as " + nm2)
  }
}
/*--------------------------------------------------------------------
Create a string containing n non-breaking spaces,  ....
Part of formatJSONstr(...)
*/
function indent(n) {
  let tmp = "";
  for(i=0; i<n; ++i) {
    tmp += " ";
  }
  return tmp;
}
/*--------------------------------------------------------------------
Replace comma character with comma escape, e.g., ,.
Expects index to point to comma in str. This is done to
avoid splitting inner array by JSON.stringify.
Part of formatJSONstr(...)
*/
function replaceComma(str, index) {
  if(index < 0 || str.length <= index) {
    return str;
  }
  let tmp = str.substr(0, index-1) + "," + str.substr(index);
  // document.writeln("test: " + JSON.stringify('1,2'));
  return tmp;
}
/*--------------------------------------------------------------------
Treat inner array as a single element for JSON string formatting.
Part of formatJSONstr(...)
*/
function weldArray(jstr) {
  isArray = false;
  tmp = jstr;
  let j=0;
  for(i=0; i<jstr.length; ++i) {
    j += 1;
    switch(jstr[i]) {
    case '[':
      if(i != 0) {  // don't count outer array
        isArray = true;
      }
      break;
    case ']':
      isArray = false;
      break;
    case ',':
      if(isArray) {
        tmp = replaceComma(tmp, j);
        j += 4;
      }
      break;
    }
  }
  return tmp;
}
/*--------------------------------------------------------------------
Format JSON string to indent left spaces and show rows of width elements
*/
function formatJSONstr(jstr, left=4, width=8) {
  let indtCache = indent(left);
  jstr = weldArray(jstr);
  jstr = jstr.trim();
  let char1 = jstr[0];
  let char2 = jstr[jstr.length - 1];
  let jstrm = jstr.substring(1, jstr.length - 1); // remove delimiters
  let fstr = jstrm.split(/[,]+/); // regex selects on either " " or ,
  let fm = char1 + "<br />" + indtCache;
  for(i=0; i<fstr.length; ++i) {
    fm += fstr[i] + ", ";
    if((i+1) % width === 0 && i != fstr.length -1) {
      fm += "<br />" + indtCache;
    }
  }
  fm = fm.substring(0, fm.length - 2);
  fm += "<br />" + char2 + "<br />";
  return fm;
}
/*--------------------------------------------------------------------
  Use JSONstringify to show all data members of object with body
  indented by left spaces and elements shown in rows of specified
  width. Used in showType(...)
*/
function showObject(obj, nm, left=4, width=7) {
  document.write(nm, ": ");
  let fmts = formatJSONstr(JSON.stringify(obj), left, width);
  document.write(fmts);
}
/*--------------------------------------------------------------------
Iterate through object's own keys, ignore objects, and display
  - only shows top level elements, e.g., no recursion
  - not used in demo
  - here to illustrate iterating through object elements
*/
function showObject_alt(obj, nm) {
  let str = "";
  for(let [key, value] of Object.entries(obj)) {
    if(obj.hasOwnProperty(key) && typeof value != typeof Object) {
      str += "{" + key + ": " + value + "}, ";
    }
  }
  /* remove trailing comma and space */
  str = str.substring(0, str.length - 2);
  document.write(nm, " { ", str, " }", nl);
}
/*--------------------------------------------------------------------
Evaluate object's size by iterating through own properties
// https://gist.github.com/pgpbpadilla/10344038
*/
function sizeof(object) {
  var objectList = [],
    stack = [ object ],
    bytes = 0,
    value,
    i;

  while (stack.length) {
    value = stack.pop();

    if (typeof value === 'boolean') {
      bytes += 4;
    } else if (typeof value === 'string') {
      bytes += value.length * 2;
    } else if (typeof value === 'number') {
      bytes += 8;
    } else if (typeof value === 'object'
        && objectList.indexOf(value) === -1) {
      objectList.push(value);

      for (i in value) {
        if (value.hasOwnProperty(i)) {
          stack.push(value[i]);
        }
      }
    }
  }
  return bytes;
}

Functions:

The "Analysis.js" file, loaded by "Js_Objects.html" defines 14 analysis and display functions.

Display Functions:

HTML files usually render text placed in "in-line" and "block" elements. Those are rendered onto a web page using the box model which defines how text flows, e.g., in-line elements flow left to right, block elements flow top to bottom. The box model provides margins, padding, and other styles to support rendering text in readable form. This is not how this demonstration works. With a couple of exceptions, all text is written to the page using document.write(...) statements which write into a simulated terminal in the page. That is appropriate since almost all of the page contents illustrate the results of JavaScript operations. The display functions are relatively simple and examination of their contents is left to the reader.

Analysis Functions:

showType(t, nm, left=4, width=7) displays the name, type, size, and value of its argument t. The left and width arguments control the left margin and, for collections, the number of elements in a display row, for a column of rows. showTypeShowable(t, nm) invokes the t.show() method for the object t. That allows each user-defined type to provide its own specialized formatting. isSameObject(o1, nm1, o2, nm2) displays the referential equality of the named objects, nm1 and nm2. indent(n) returns a string of n space characters. This is a helper for formatJSONstr. replaceComma(str, index) replaces comma character with escape. Another helper for formatJSONstr. weldArray(jstr) treats interior array as single object. Another helper. formatJSONstr(jstr, left=4, width=8) formats JSON string into indented array of rows of specified width. showObject(obj, nm, left=4, width=7) displays named object using formatting provided by formatJSONstr. showObject_alt(obj, nm) is not used in this demo. sizeof(object) iterates through object's own properties and accumulates the size of each.

2.0 Build

local machine

C:\github\JimFawcett\Bits\Javascript\Js_Objects
> start firefox C:\github\JimFawcett\Bits\Javascript\Js_Objects\Js_Objects.html
C:\github\JimFawcett\Bits\Javascript\Js_Objects
>

github site

  clone Bits repository and double click on Js_Objects.html

2.0 VS Code View

The code for this demo is available in github.com/JimFawcett/Bits. If you click on the Code dropdown you can clone the repository of all code for these demos to your local drive. Then, it is easy to bring up any example, in any of the languages, in VS Code. Here, we do that for JavaScript\Js_Objects. Figure 1. VS Code IDE - JavaScript Objects Figure 2. Debugging JavaScript Objects

3.0 References

Reference Description
JavaScript Tutorial - w3schools Interactive examples
JavaScript Reference - MDN Informal syntax reference