What is a script include? How to work with it?
In the landscape of ServiceNow development world, one tool stands out as a repository for creating efficient, modular, and reusable code - the Script Include. What is that actually? A script include is a platform component that encapsulates JavaScript functions and classes, fostering modularity and reusability within the ServiceNow platform. Unlike business rules or client scripts that are tied to specific tables or UI actions, script includes transcend these boundaries. They serve as dedicated repositories for reusable server-side scripts. In short, it's a library of reusable functions / methods / classes.
In this blog post, we will have a look into the following topics:
- How to define a new script include? What are the options and how does it refer to the newest Javascript class concepts?
- How to call / invoke script includes and in which places of the platform it would usually be done?
- How to inherit functions from one script include into another one (class inheritance) and when would you want to do it?
- Private functions vs public functions - how to benefit from that concept?
- What is the intialize function and when would you usually use it?
- What are classless script includes?
- Keyword 'this' and some useful hints to make use of it within the script include
Creating a new script include
The process is remarkably straightforward, thanks to the user-friendly nature of ServiceNow. Simply by providing a name for the script include, the platform effortlessly generates the underlying code structure. This foundational step lays the groundwork for a class that can be enriched with a plenty of methods, each contributing to the overall functionality delivered by this class.
var MyNewClass = Class.create();
MyNewClass.prototype = {
initialize: function() {
},
coreMethod: function(param){
//Some logic here
},
type: 'MyNewClass'
};
it's essential to make strategic decisions that lay the groundwork for seamless integration. ServiceNow provides a set of additional options, each carrying its own significance. If your script include is destined for direct use on the client side, select the checkbox that facilitates this client-side usage. This choice ensures that your script include is enabled for the client side use. How does this actually work in reality? Your new class will be an extension to an already existing Ajax class. We already touchbase the concept of class inheritance here, which we will also explain in more detail in further paragraphs.
var MyNewClass = Class.create();
MyNewClass.prototype = Object.extendsObject(AbstractAjaxProcessor, {
type: 'MyNewClass'
});
It's also important to highlight the importance of considering if the methods defined within your newly created class will have to be used by different application scopes. If yes, do not forget to change the selection accordingly.
Invoking your script includes
Step 1: Point to the Class - Setting the Stage
The initial step in invoking a script include is directing the system to the class you wish to engage. This serves as the foundational link, establishing a connection between your business rule, script action, reference qualifier, fix script, transform map or any other scripting component and the reservoir of methods encapsulated within the script include.
var pointingTheClass = new MyNewClass();
Step 2: Point to the Right Method
With the stage set, the second step involves pinpointing the exact method within the chosen class that aligns with the goal we want to reach.
var pointingTheClass = new MyNewClass();
pointingTheClass.pointingTheMethod();
As you can see above, the methods are pure JavaScript functions and can easily accept parameters. That would include objects, arrays, strings and any other types of data your method would need to execute the right logic.
Step 3: Passing a parameter to your method. Using 'current' object as example
Usually, when executing scripts you also need data for the logic to process correctly. One of the very popular objects available in ServiceNow in many places is the so called 'current' object. It can be passed as parameter to our function and then used directly within the script include for further processing. It's just important to remember to not call it as 'current' in the script include as this is a reserved keyword that can be only used in predefined places like business rules, script actions and similar.
var pointingTheClass = new MyNewClass();
pointingTheClass.pointingTheMethod(current);
Script include and class inheritance
Inheritance enables you to define a class that takes all the functionality from a parent class and allows you to add more. Using class inheritance, a class can inherit all the methods and properties of another class. Inheritance is a useful feature that allows code reusability.
This is a common JavaScript concept, but how does this work in ServiceNow and the script includes?
var MyExtendingClass = Class.create();
MyExtendingClass.prototype = Object.extendsObject(MyNewClass, {
type: 'MyExtendingClass'
});
What would we achieve with the code presented above? The class with the name 'MyExtendingClass' would inherit all the functionality and methods from the class 'MyNewClass'. This might be quite powerful, especially when developing big scale applications, which functionality is extended without end, but at the same time still requires access to already existing methods.
Another common use case for extending classes in ServiceNow would be to override already existing, out of the box function with our own function. As ServiceNow usually does not allow to edit core classes, the only way to proceed is to extend out of the box class and override one of the methods defined there. See an example below:
领英推è
Class A
var MyNewClass = Class.create();
MyNewClass.prototype = {
initialize: function() {
},
coreMethod: function(param){
//Some logic here
},
type: 'MyNewClass'
};
Class B
var MyExtendingClass = Class.create();
MyExtendingClass.prototype = Object.extendsObject(MyNewClass, {
coreMethod: function(otherParam){
// Some other logic here that will override the Class A method
},
type: 'MyExtendingClass'
});
At this point, I would also like to highlight to a very important concept of JavaScript, which is known under the 'Protypal Inheritance'. This would exactly fit the way, how script include works. Every object in JavaScript has a prototype that is just a level above. If you try to invoke a method, that does not exist directly within the object, it will try to find it level above, within its protype.
Consider the scenario where we have a script include named ScriptIncludeOne housing functions for performing some calculations. Now, envision the creation of a new script include named ScriptIncludeTwo dedicated to further calculations. Instead of duplicating the logic from ScriptIncludeOne, we can easily make use of the system built-in function
gs.include('ScriptIncludeOne')
The use case for gs.include and for class extensions is different, so please do not treat it as an alternative to the concept of class inheritance.
Private vs public functions - best practices
The distinction between public and private functions emerges as a best practice, improving the code organization and reusability. Private functions, as the name suggests, are tailored for exclusive use within the confines of a specific script include. They encapsulate functionalities vital to the internal workings of that script include, fostering a modular and encapsulated design. On the flip side, public functions, marked by their accessibility beyond the concrete script include's boundaries, serve as gateways to functionality meant for global reuse.
While the distinction is more of a naming convention than a strict functional constraint, its impact on code maintenance and readability is profound. By clearly delineating functions as public or private, developers not only communicate the intended scope of each function but also contribute to the longevity and clarity of the codebase.
_privateFunction: function(){
//I'm telling you to use me only as part of the current class
}
publicFunction: function(){
//I'm telling you that you might use me platform-wide
}
Intialize function
This function is automatically invoked when JavaScript objects are instantiated from the script include, the initialize() function serves as the architect of shared variables within the script include's realm.
Variables defined within the this object in the initialize() function enjoy a special status - they become known to all other functions within the script include. This shared knowledge forms the bedrock of cohesion, enabling seamless communication and collaboration between different methods encapsulated in the same class or script include.
Typically, the initialize() function becomes a repository for variables that demand global accessibility within the script include. By strategically placing such variables here, developers ensure that they are readily available to multiple methods, fostering modularity and code elegance.
var MyNewClass = Class.create();
MyNewClass.prototype = {
initialize: function() {
this.myReusableVariable = 'Password';
this.logger = function(msg){ return gs.log(msg, 'myLogger');
},
methodA: function(){
var result = callApi(this.myReusableVariable);
this.logger('Status of my API call' + result);
},
methodB: function(){
callSameApi(this.myReusableVariable);
},
type: 'MyNewClass'
};
As you see in the example below, the intialize function is actually binding the value to the prototype. By using the keyword 'this' we can access the prototype and reuse the variable across multiple methods. It might be very helpful, when working with APIs as an example.
Classless Script Include
The on-demand Script Include, a classless entity defined by a solitary function. This singular function, crafted within the script include, becomes a server-side script, callable globally from other server-side scripts across the ServiceNow instance. Classless Script Includes will generally contain a single function definition.
function classLess(){
// Do something
}
You can use this function across the server-side by just calling it:
classLess();
Keyword 'this'
In JavaScript, the 'this' keyword is a special identifier that refers to the current execution context or the object to which a function or method belongs. The value of this is dynamically determined based on how a function is invoked. Understanding and correctly utilizing this is crucial for writing flexible and reusable code.
In the context of ServiceNow script includes, the keyword 'this' allows us to access all the different methods defined accessible within the same class, but at the same time allows us to access the global variables defined as part of the 'intialize' function.
var myClass = Class.create();
myClass.prototype = {
initialize: function() {
this.myVariable = "Set the variable value";
},
functionA: function (){
//I can access the other method by using this keyword
this.functionB();
},
functionB: function (){
//I can access the variables from the intialize function by using this keyword
gs.info("value of myVariable in functionB: " + this.myVariable);
},
type: 'myClass '
};
It's important to highlight that the 'this' and the context will get lost if a function is called by being passed to another function as a callback. In this particular scenario, you might need to explicitly bind the context to the callback function.
this.functionA(this.functionB.bind(this));