Advanced JavaScript Snippets in vRO [CB10099]

Learn about some advanced JavaScript concepts that can be used seamlessly inside vRO and enhance your code functionality. Scroll down to read more.

By

min read

Advanced JavaScript Snippets in vRO [CB10099]

Introduction

vRO JS code is generally plain and basic just enough to get the job done. But I was wondering, how to fancy it? So, I picked some slightly modern JS code (ES5.1+) and tried running it on my vRO 8.3. I found some interesting things which I would like to share in this article.

Snippets

Here are some JS concepts that you can use writing vRO JavaScript code to make it more compelling and beautiful.

External Modules

To utilize modern features, you can use modules like lodash.js for features such as map or filter etc. Other popular module is moment.js for complex Date and Time handling in vRO.

var _ = System.getModule("fr.numaneo.library").lodashLibrary();
var myarr = [1,2,3];
var myarr2 = [4,5,6];
var concatarr = _.concat(myarr, myarr2);
System.log(concatarr); // [1,2,3,4,5,6];

Find more information on how to leverage Lodash.js in vRO here.

First-class Functions

First-class functions are functions that are treated like any other variable. For example, a function can be passed as an argument to other functions, can be returned by another function and can be assigned as a value to a variable.

// we send in the function as an argument to be
// executed from inside the calling function
function performOperation(a, b, cb) {
    var c = a + b;
    cb(c);
}

performOperation(2, 3, function(result) {
    // prints out 5
    System.log("The result of the operation is " + result);
})

Ways to add properties to Objects

There are 4 ways to add a property to an object in vRO.

// supported since ES3
// the dot notation
instance.key = "A key's value";

// the square brackets notation
instance["key"] = "A key's value";

// supported since ES5
// setting a single property using Object.defineProperty
Object.defineProperty(instance, "key", {
    value: "A key's value",
    writable: true,
    enumerable: true,
    configurable: true
});

// setting multiple properties using Object.defineProperties
Object.defineProperties(instance, {
    "firstKey": {
        value: "First key's value",
        writable: true
    },
    "secondKey": {
        value: "Second key's value",
        writable: false
    }
});

Custom Class

You can create your own custom classes in vRO using the function keyword and extend that function’s prototype.

// we define a constructor for Person objects
function Person(name, age, isDeveloper) {
    this.name = name;
    this.age = age;
    this.isDeveloper = isDeveloper || false;
}

// we extend the function's prototype
Person.prototype.writesCode = function() {
    System.log(this.isDeveloper? "This person does write code" : "This person does not write code");
}

// creates a Person instance with properties name: Bob, age: 38, isDeveloper: true and a method writesCode
var person1 = new Person("Bob", 38, true);
// creates a Person instance with properties name: Alice, age: 32, isDeveloper: false and a method writesCode
var person2 = new Person("Alice", 32);

// prints out: This person does write code
person1.writesCode();
// prints out: this person does not write code
person2.writesCode();

Both instances of the Person constructor can access a shared instance of the writesCode() method.

Private variable

A private variable is only visible to the current class. It is not accessible in the global scope or to any of its subclasses. For example, we can do this in Java (and most other programming languages) by using the private keyword when we declare a variable

// we  used an immediately invoked function expression
// to create a private variable, counter
var counterIncrementer = (function() {
    var counter = 0;

    return function() {
        return ++counter;
    };
})();

// prints out 1
System.log(counterIncrementer());
// prints out 2
System.log(counterIncrementer());
// prints out 3
System.log(counterIncrementer());

Label

Labels can be used with break or continue statements. It is prefixing a statement with an identifier which you can refer to.

var str = '';

loop1:
for (var i = 0; i < 5; i++) {
  if (i === 1) {
    continue loop1;
  }
  str = str + i;
}

System.log(str);
// expected output: "0234"

with keyword

The with statement extends the scope chain for a statement. Check the example for better understanding.

var box = {"dimensions": {"width": 2, "height": 3, "length": 4}};
with(box.dimensions){
  var volume = width * height * length;
}
System.log(volume); //24

// vs

var box = {"dimensions": {"width": 2, "height": 3, "length": 4}};
var boxDimensions = box.dimensions;
var volume2 = boxDimensions.width * boxDimensions.height * boxDimensions.length;
System.log(volume2); //24

Function binding

The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.

const module = {
  x: 42,
  getX: function() {
    return this.x;
  }
};

const unboundGetX = module.getX;
System.log(unboundGetX()); // The function gets invoked at the global scope
// expected output: undefined

const boundGetX = unboundGetX.bind(module);
System.log(boundGetX());
// expected output: 42

Prototype Chaining

const o = {
  a: 1,
  b: 2,
  // __proto__ sets the [[Prototype]]. It's specified here
  // as another object literal.
  __proto__: {
    b: 3,
    c: 4,
  },
};

// o.[[Prototype]] has properties b and c.
// o.[[Prototype]].[[Prototype]] is Object.prototype (we will explain
// what that means later).
// Finally, o.[[Prototype]].[[Prototype]].[[Prototype]] is null.
// This is the end of the prototype chain, as null,
// by definition, has no [[Prototype]].
// Thus, the full prototype chain looks like:
// { a: 1, b: 2 } ---> { b: 3, c: 4 } ---> Object.prototype ---> null

System.log(o.a); // 1
// Is there an 'a' own property on o? Yes, and its value is 1.

System.log(o.b); // 2
// Is there a 'b' own property on o? Yes, and its value is 2.
// The prototype also has a 'b' property, but it's not visited.
// This is called Property Shadowing

System.log(o.c); // 4
// Is there a 'c' own property on o? No, check its prototype.
// Is there a 'c' own property on o.[[Prototype]]? Yes, its value is 4.

System.log(o.d); // undefined
// Is there a 'd' own property on o? No, check its prototype.
// Is there a 'd' own property on o.[[Prototype]]? No, check its prototype.
// o.[[Prototype]].[[Prototype]] is Object.prototype and
// there is no 'd' property by default, check its prototype.
// o.[[Prototype]].[[Prototype]].[[Prototype]] is null, stop searching,
// no property found, return undefined.

That’s all in this post for now. I will be updating new snippets as soon as I discover more. Thanks for reading. Don’t forget to subscribe to get the new articles first.

Leave a Reply

Related Posts

%d bloggers like this: