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