I'm new to OOP in JavaScript. Could someone please point out how I would go about calling an internal function from within a Class.
For example, from the below code how would I call the hello function from with the myFunction:
// app.js file
var Api = require('Api')
var api = new Api();
api.myFunction();
//server.js file
/**
* API client.
*/
function Api() {
this.my_var = 'my variable';
}
/**
* My Function
*/
Api.prototype.myFunction = function() {
// have tried this
this.hello();
// and this
Api.hello();
}
/**
* Hello
*/
Api.prototype.hello = function() {
console.log('Hello!');
}
// expose the Api class
module.exports = Api;
module.exports = function() {
this.my_var = 'my_variable';
this.myFunction = function() {
this.hello();
};
this.hello = function() {
console.log('hello');
};
return this;
}
Related
I am implementing a CucumberJS scenario which uses multiple steps across two different step definition files. The first step sets some variables on the World which have to be used by a step in the other step definition file.
The variable gets set correctly but when the step on the other file tries to read it it's undefined. Any ideas how to solve this apart from merging the step definition files?
example:
world.js
var World = function World() {
this.client = '';
};
module.exports.World = World;
test.feature
Given a variable A
Then some other step
step1.steps.js
module.exports = function () {
this.World = require(process.cwd() + '/test/features/support/world').World;
this.Given(/^a Variable A$/, function () {
this.client = 'abc';
});
};
step2.steps.js
module.exports = function () {
this.World = require(process.cwd() + '/test/features/support/world').World;
this.Then(/^some other step$/, function () {
console.log(this.client);
});
};
You are setting this.client instead of this.World.client. Moreover you should use an object and not a constructor in world.js:
world.js
module.exports = {
client: ''
};
step1.steps.js
var world = require('./test/features/support/world.js');
module.exports = function () {
this.Given(/^a Variable A$/, function () {
world.client = 'abc';
});
};
step2.steps.js
var world = require('./test/features/support/world.js');
module.exports = function () {
this.Then(/^some other step$/, function () {
console.log(world.client);
});
};
You could directly parameterise your test.feature :
Given a variable "abc"
Then some other step
now pass this variable in your step
step1.steps.js
module.exports = function() {
this.World = require(process.cwd() + '/test/features/support/world').World;
this.Given(/^a Variable "([^"]*)"$/, function(variable) {
this.client = variable;
});
};
step2.steps.js
module.exports = function() {
this.World = require(process.cwd() + '/test/features/support/world').World;
this.Then(/^some other step$/, function() {
console.log(this.client); // would print abc
});
};
In my node project I'm using this basic template structure for a single module
(function() {
var SimpleModule;
SimpleModule = (function() {
function SimpleModule(params) {
/** private function */
this.aPrivateFunction = function() {
return "hidden";
};
}
/** public function */
SimpleModule.prototype.foo = function() {
return "bar";
}
return SimpleModule;
})();
module.exports = SimpleModule;
}).call(this);
so that the caller module will do
var SimpleModule
,simpleModuleInstance;
SimpleModule = require('./simplemodule');
simpleModuleInstance = new SimpleModule();
simpleModuleInstance.foo();
Is this a approach formally correct in Node?
How about a simpler approach? Modules are private by default, so everything's already encapsulated except what you export.
function SimpleModule(params) {
/* Not really private!! */
this.aPrivateFunction = function() {
return "hidden";
};
}
/** public function */
SimpleModule.prototype.foo = function() {
return "bar";
}
module.exports = SimpleModule;
Here is some example code:
ExampleClass = function()
{
this.initiate();
};
ExampleClass.prototype.initiate = function()
{
var connect = function()
{
this.sendNOP();
};
connect();
};
ExampleClass.prototype.sendNOP = function()
{
console.info('Sending NOP...');
var callback = function()
{
console.info('Server responded to NOP. ZzzZzzzZzz...');
};
setTimeout(callback, 1500);
};
I am very curious why I can't call this.sendNOP() in ExampleClass.initiate so that ExampleClass.initiate._connect() will pass the instanceof ExampleClass as this to ExampleClass.sendNOP(), it seems to pass window as this. Why?
EDIT:
The problem is when we call ExampleClass.initiate._connect() we only use connect() which does not specify any context. Calling ExampleClass.initiate._connect() with .apply(this) works! .apply(this) sets the context to ExampleClass.
ExampleClass.prototype.appliedInitiate = function()
{
var connect = function()
{
this.sendNOP();
};
connect.apply(this);
};
Final code
ExampleClass = function()
{
this.appliedInitiate();
};
ExampleClass.prototype.sendNOP = function()
{
console.info('Sending NOP...');
var callback = function()
{
console.info('Server responded to NOP. ZzzZzzzZzz...');
};
setTimeout(callback, 1500);
};
ExampleClass.prototype.initiate = function()
{
var connect = function()
{
this.sendNOP();
};
connect(); // Won't work. connect() is not called from any context (ie. obj.connect() )
};
ExampleClass.prototype.appliedInitiate = function()
{
var connect = function()
{
this.sendNOP();
};
connect.apply(this); // Will work, we are calling connect with apply, which sets the context to ExampleClass
};
You can't calling this.sendNOP in ExampleClass.initiate. You are calling it in connect. That the call to connect is inside the initiate function is irrelevant.
You haven't called connect with any context, so the context is the default object (window).
I have written the following code to implement logging in a separate js file logger.js by using OOP.
var console;
function Logger() {
init();
}
var init = function() {
if(!window.console){
console = {
log: function(message){},
info: function(message){},
warn: function(message){},
error: function(message){}
};
} else {
console = window.console;
}
};
Logger.prototype.log = function(message) {
console.log(message);
}
Logger.prototype.logInfo = function(message) {
console.info(message);
}
Logger.prototype.logWarn = function(message) {
console.warn(message);
}
Logger.prototype.logError = function(message) {
console.error(message);
}
I am using it from another js file, site.js as:
var logger = new Logger(); //global variable
var getComponentById = function(id) {
var component = null;
if(id) {
try {
component = AdfPage.PAGE.findComponentByAbsoluteId(id);
}catch(e){
logger.logError(e);
}
}
return component;
}
I was wondering
If I have implemented the Logger class in proper way, by maintaining OOP of JavaScript.
Will it handle the scenario where the browser don't have any console?
How can I make init() method inaccessible from other js file or method? I mean how can I make it private?
Any pointer would be very helpful to me.
Update
From another SO thread I found information about private method and I changed my approach:
function Logger() {
init();
}
Logger.prototype = (function() {
var console;
var init = function() {
if(!window.console){
this.console = {
log: function(message){},
info: function(message){},
warn: function(message){},
error: function(message){}
};
} else {
this.console = window.console;
}
};
return {
constructor: Logger,
log: function(message) {
this.console.log(message);
},
logInfo: function(message) {
this.console.info(message);
},
logWarn: function(message) {
this.console.warn(message);
},
logError: function(message) {
this.console.error(message);
}
};
})();
But in this case I am getting error that init is not defined.
To answer your questions:
your implementation of the class is a bit odd. You're accessing the console variable with a closure, having it as a property on the Logger makes more sense.
if the browser has no console, you wont get an error (but the logger wont do anything)
To make you init function private you could wrap it in an IIFE (immediately invoked function expression)
I took your code and changed it slightly to come up with this:
// Create the Logger function with an IIFE, this keeps all of the private
// variables out of the global scope, the only thing in the global scope
// is the function returned by the IIFE.
var Logger = (function (w) {
var Logger,
DummyConsole;
DummyConsole = function () {
this.log = function (message) {
alert(message);
};
this.info = function (message) {
// Implement however you want.
};
this.warn = function (message) {
// ...
};
this.error= function (message) {
// ...
};
};
Logger = function () {
if (!w.console) {
this.console = new DummyConsole();
} else {
this.console = w.console;
}
};
Logger.prototype.log = function(message) {
this.console.log(message);
};
Logger.prototype.logInfo = function(message) {
this.console.info(message);
};
Logger.prototype.logWarn = function(message) {
this.console.warn(message);
};
Logger.prototype.logError = function(message) {
this.console.error(message);
};
return Logger;
}(window));
// create a logger instance to check that the Logger class logs to the console.
var a = new Logger();
a.log("hello");
// Remove the console.
window.console = null;
// Create a new logger checking that it falls back to the dummy console implementation.
var b = new Logger();
// An (annoying) alert is shown.
b.log("Hi");
Code is available as a JSFiddle here: http://jsfiddle.net/mtufW/
I have the following:
mod.a = (function() {
var myPrivateVar = 'a';
function myPrivateFct() {
//do something I will need in my sub-module (mod.a.b)
}
return {
//some public functions
}
})();
mod.a.b = (function() {
// some local vars and functions
return {
mySubModuleFct:function() {
// here I want to call mod.a.myPrivateFct();
}
})();
I want to create a sub-module and call a private function from my parent module mod.a. How can I do this while following the best practices of the module pattern?
A coworker showed me how to do it. It's actually very elegant.
mod.a = (function() {
var myPrivateVar = 'a';
function myPrivateFct() {
//do something I will need in my sub-module (mod.a.b)
}
return {
b: {
bPublicMethod:function() {
myPrivateFct(); // this will work!
}
}
//some public functions
}
})();
//call like this
mod.a.b.bPublicMethod(); // will call a.myPrivateFct();
I would suggest using John Resig's Simple Inheritance code for more object-oriented approach to javascript:
http://ejohn.org/blog/simple-javascript-inheritance/
It allows you to write this:
var Person = Class.extend({
init: function(isDancing){
this.dancing = isDancing;
}
});
var Ninja = Person.extend({
init: function(){
this._super( false );
}
});
var p = new Person(true);
p.dancing; // => true
var n = new Ninja();
n.dancing; // => false