I'm getting a very odd error when I try to require a node module. To illustrate the problem here is the code I am trying to require:
module.exports = (function(){
this.say = function(message) {
console.log(message);
}
})();
Now when I require this module I get 'Cannot read property 'say' of undefined when I try to use it as follows:
var person = require('./Person.js')
person.say('Hello World!');
And yet, if I define the module as follows it works fine ...
module.exports = {
say : function(message) {
console.log(message);
}
};
I even tried this notation that also worked ...
module.exports = new Person();
function Person(){
this.say = function(message) {
console.log(message);
}
};
Does anyone have any idea why the first notation doesn't work properly?
The reason is your first notation doesn't return anything to export.
module.exports = (function(){
this.say = function(message) {
console.log(message);
}
return this;
})();
I guess this should solve your problem.
module.exports is an object that will be returned upon require calls for that file.
So assume you want write a library that does some logic, some is private, other is public.
and you want to expose only your public function to other people to invoke,
what your file may look like is:
// Some require calls you maybe using in your lib
function privateFunc(s) {
console.log(s);
}
function publicFunc(s) {
privateFunc("new log: " + s);
}
module.exports = {
log: publicFunc
}
You later will use it as follows:
var logger= require('myLib');
logger.log("my log");
This will output:
new log: my log
Thats maybe deeper than what you actually wanted, but it is meant to understand the flow of things
Related
I am reading how to mock google cloud functions for firebase and have issues of properly mocking the following code:
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
var db = admin.firestore();
The example in the link uses the following code to mock initializeApp which does work
admin = require('firebase-admin');
adminInitStub = sinon.stub(admin, 'initializeApp');
Now admin.firestore is defined in firebase-namespace.js as following:
Object.defineProperty(FirebaseNamespace.prototype, "firestore", {
get: function () {
var ns = this;
var fn = function (app) {
return ns.ensureApp(app).firestore();
};
return Object.assign(fn, require('#google-cloud/firestore'));
},
enumerable: true,
configurable: true
});
I've tried various things to stub this but I fail
Results in firestore is not a function:
Object.defineProperty(admin, "firestore", {
get: function () {
return 32;
}
});
Does not mock firestore() at all and calls the original function which fails hard:
sinon.stub(admin, 'firestore').returns({get() { }});
TypeError: Cannot stub non-existent own property get
firestoreStub = sinon.stub(admin.firestore, 'get').callsFake(function () {return {data:"Foo"}});
I lack understanding what admin.firebase() actually is. It does not look like it is a property because AFAI when I mock a getter of a property, I would call admin.firebase and not a function admin.firebase(). But it is also not mockable via a function.
That really took me too long.
To be able to mock the admin.firebase() the getter function of the property should actually return a function.
My initial assumption was that firebase() is a function, which it was not. Then by looking at the implementation I understood that this is a property with a custom getter. However I tried to return some json data block via the getter.
I initially failed to understand that admin.firestore is indeed a property but I was missing the key on why I have to call the property as a function, which is typically not needed on the property itself.
After getting to the point I understood that the getter of the property actually returned a function and that the admin.firebase() can be read like
var method = admin.firebase; // calling the property getter function
method(); // assuming the getter returned a function object
So for my future self ;) this does the trick:
sinon.stub(admin, 'firestore')
.get(function() {
return function() {
return "data";
}
});
Originally I was trying to do
sinon.stub(admin, 'firestore').get( function () { return "data"; } ); which failed because the admin.firestore() ultimately yielded in "data"(), which made no sense.
this is my object
var Controller = (function () {
var self = this;
self.get = function (req, res) {
res.send({
success: 'you got me'
});
}
return self;
})()
module.exports = Controller;
and below is how i am trying to pass parameters to the get function from another document.
var Controller = require('../Controller.js');
Controller.get(arg1, arg2);
However nodejs throws 'TypeError: Controller.get is not a function', what am i doing wrong here? Thanks
There are several issues with that code, but it will not cause the TypeError: Controller.get is not a function you describe.
The way you're calling your anonymous function that creates Controller means that this within it will be the global object (loose mode) or undefined (strict mode). Let's assume loose mode as you haven't said you're getting an error assigning get to undefined. That means you're creating a global function called get. It also means that Controller returns the global object.
Neither of those is a good thing. :-)
If you want to export an object with a get function, you don't need to do anything nearly so complicated:
var Controller = {
get: function (req, res) {
res.send({
success: 'you got me'
});
}
};
module.exports = Controller;
Or perhaps
function get() {
res.send({
success: 'you got me'
});
}
module.exports = { get: get };
Since this is in the context of a NodeJS module, that doesn't define a global function (modules are called in a private scope).
Or, if you meant Controller to be a constructor, then you need to call it via new and reorganize it slightly:
function Controller() {
var self = this; // If you need it for something, you don't in your example
self.get = function get() {
res.send({
success: 'you got me'
});
};
}
module.exports = Controller;
then use it via new:
var Controller = require('./.Controller.js');
var c = new Controller();
c.get("foo", "bar");
It's also probably worth pointing out that require('../Controller.js') uses the Controller.js file from the parent directory, not the current directory. Just in case that wasn't on purpose and you're getting the TypeError: Controller.get is not a function because you're getting the wrong file.
I have a Curl.js module defined as:
define("Portfolio", ["jquery"], function(jquery) {
var $ = jquery;
var Portfolio = (function() {
$("#output").text("Getting Stuff");
var name = "";
var holdings = [];
return {
"stupid": function() {
$.getScript("app/myScript.js", function(dog) {
//var dog = new Dog();
dog.speak();
}).fail(function(jqxhr, settings, exception) {
console.log(exception);
});
}
}
})();
return Portfolio;
});
/app/myScript.js looks like this:
(function() {
var breed = "Poodle";
return {
speak: function() {
alert("Woof");
}
};
})();
I am calling the "stupid" method from the console in Chrome as follows:
curl(['Portfolio'], function(Portfolio){
Portfolio.stupid();
});
And Chrome says:
Uncaught TypeError: Object (function() {
var breed = "Poodle";
return {
speak: function() {
alert("Woof");
}
};
})(); has no method 'speak'
In myScript.js i could use var Dog = (function(){....})(); which would work but I don't want to pollute the global namespace that way.
I could also use function Dog(){....} and in my getScript callback use new Dog().speak() but then Dog wont be a module in that I would have private properties, and it would also be bound to the global scope.
It seems that $.getScript() does not bind the returned value of the script called to any variable that is accessible form the callback function of getScript(); at least none that I could find. It does return data but that is only the text of the script called. I did find a cheat that I can take the returned script and run it through eval(). Oddly this is pretty much exactly what $.getScript() method itself does. Reworking the Stupid method to the following code:
"stupid": function() {
$.get("/app/myScript.js", function(Dog) {
var dog = new (eval(Dog));
console.log("Breed:" + dog.getBreed());
d.setBreed("Lab");
console.log("Breed: " + dog.getBreed());
});
}
This does work but it feels a bit hacky and wrong.
How can I use getScript() to call /app/myScript.js that is written as a module or anonymous self-executing function and then call one of the returned functions? getScript is supposed to execute the script which I thought, as I have it written, return an object bount to the getScript return object that I could then call? Obviously I am missing something here.
Why you no work Javascript?
if once you use curl.js maybe it is better to forget about JQuery.getScript()
read curl's wiki!
I have a file stats.js.
It's contents are
(function () {
func1 = function () {
}
func2 = function () {
}
module.exports = this;
}).call(this);
Alegedly, when I do
var stats = require("./stats");
I should be able to get func1 and func2 with stats.func1, stats.func2, right?
Well, I can't. The stats object is just empty. A few traces in the stats.js revealed that "this" is also an empty object.
What gives?
First and foremost see this link.
Now lets see your code -
var stats = require("./stats");
//My steps -
//First Log
console.log(stats.func1); // returns undefined
//Second Log
console.log(global.func1, global === GLOBAL); // returns [Function], true
Take aways from this code -
1. In the browser the global object is window object.
2. In node.js it is the global object.
3. Defining something using var in a module will only create a variable with a module scope.
4. Defining something without the var keyword will create a variable in the global scope.
So func1 and func2 were defined in the global scope. Passing this to module.exports will pass the current module object only.
hope it helps, happy coding!
No it shouldnt? That format is nothing like what Node.js needs in order to do its job.
"What gives" is that you didn't read up on how node works. Node.js isn't just "JavaScript", it's a proramming model with a much richer API and specific behaviours. Requires use the "module.exports" object, so it would be a good idea to actually read up on how to use node.
mything.js:
var func3 = function() { ... },
prop = "something";
...
module.exports = {
func1: function() { ... },
func2: function() { ... },
func3: funct3,
prop: prop,
...
};
which is identical to:
var func3 = function() { ... },
prop = "something",
...
MyLib = {
func1: function() { ... },
func2: function() { ... },
func3: funct3,
prop: prop,
...
};
...
module.exports = MyLib;
app.js:
var mything = require("mything);
Let's say I am writing code at the main page level and 2 dependencies require the same instance of an object and also state that as a dependency. What is the appropriate way to go about this?
Basically what I want to do is say, "If this dependency isn't loaded... then load it. Otherwise, use the same instance that was already loaded and just pass that one."
You would make that a module-level variable. For example,
// In foo.js
define(function () {
var theFoo = {};
return {
getTheFoo: function () { return theFoo; }
};
});
// In bar.js
define(["./foo"], function (foo) {
var theFoo = foo.getTheFoo(); // save in convenience variable
return {
setBarOnFoo: function () { theFoo.bar = "hello"; }
};
}
// In baz.js
define(["./foo"], function (foo) {
// Or use directly.
return {
setBazOnFoo: function () { foo.getTheFoo().baz = "goodbye"; }
};
}
// In any other file
define(["./foo", "./bar", "./baz"], function (foo, bar, baz) {
bar.setBarOnFoo();
baz.setBazOnFoo();
assert(foo.getTheFoo().bar === "hello");
assert(foo.getTheFoo().baz === "goodbye");
};
Just provide an API for your singleton as you would.
And make sure its lazily loaded. The easiest way is to use an abstraction library like underscore that supplies cross browser helpers. Other options are ES5 Object.defineProperty or custom getter/setters.
In this case _.once ensures that constructor's result is cached after the first call, it basically lazy loads it.
define(function() {
var constructor = _.once(function() {
...
});
return {
doStuffWithSingleton: function() {
constructor().doStuff();
}
};
});
_.once from underscore.
Combining Raynos's concerns about encapsulation with the OP's clarification that he wants to expose a couple of methods on a messaging service, this is I think the right way to go about it:
// In messagingServiceSingleton.js
define(function () {
var messagingService = new MessagingService();
return {
notify: messagingService.listen.bind(messagingService),
listen: messagingService.notify.bind(messagingService)
};
});
// In bar.js
define(["./messagingServiceSingleton"], function (messagingServiceSingleton) {
messagingServiceSingleton.listen(/* whatever */);
}
// In baz.js
define(["./messagingServiceSingleton"], function (messagingServiceSingleton) {
messagingServiceSingleton.notify(/* whatever */);
}
Function.prototype.bind will not be present in all browsers, so you would need to include a polyfill like the one Mozilla provides.
An alternate (and in my opinion probably better) approach would be to make the messaging service object itself a module. This would look something like
// In messagingService.js
define(function () {
var listenerMap = {};
function listen(/* params */) {
// Modify listenerMap as appropriate according to params.
}
function notify(/* params */) {
// Use listenerMap as appropriate according to params.
}
return {
notify: notify
listen: listen
};
});
Since you expose the same notify and listen methods to everyone who uses your module, and those always refer to the same private listenerMap variable, this should do what you want. It also obviates the need for Function.prototype.bind, and gets rid of the rather-unnecessary distinction between the messaging service itself and the module which enforces singleton usage of it.
Here's a version where the module itself is the shared variable instead of a variable within that module.
define('foo', [], {bar: "this text will be overwritten"});
define('bar', ["foo"], function (foo) {
return {
setBarOnFoo: function () { foo.bar = "hello"; }
};
});
define('baz', ["foo"], function (foo) {
return {
setBazOnFoo: function () { foo.baz = "goodbye"; }
};
});
require(["foo", "bar", "baz"], function (foo, bar, baz) {
bar.setBarOnFoo();
baz.setBazOnFoo();
$('#results').append(foo.bar + ' ' + foo.baz);
});
// reads: hello goodbye
As a variation of Domenic's answer, you can use the 'exports' magic module to automatically generate a reference for the module -- "Properties added to the exports object will be on the public interface of the module, no need to return any value." This avoids having to call the getTheFoo() function to obtain a reference.
// In foo.js
define(['exports'], function (foo) {
foo.thereCanBeOnlyOne = true;
});
// In bar.js
define(["exports", "./foo"], function (bar, foo) {
bar.setBarOnFoo = function () { foo.bar = "hello"; };
});
// in baz.js
define(["exports", "./foo"], function (baz, foo) {
baz.setBazOnFoo = function () { foo.baz = "goodbye"; };
});
// In any other file
define(["./foo", "./bar", "./baz"], function (foo, bar, baz) {
bar.setBarOnFoo();
baz.setBazOnFoo();
assert(foo.bar === "hello");
assert(foo.baz === "goodbye");
assert(foo.thereCanBeOnlyeOne);
});
To address the comment below, I personally have found the above convention to be useful. Your mileage may vary, but feel free to adopt the convention if you think it is useful. The convention boils down to these two rules:
Declare 'exports' as the first dependency in the define array.
Name the parameter in the function after the JavaScript file.
Using the name of file, e.g. for foo.js name the variable 'foo', increases the readability of the code as most developers will define 'foo' as the parameter for the foo.js dependency. When scanning the code or using grep, it is easy to find all references to 'foo' use both inside and outside the module and it makes it easy to pick out what the module is exposing to the public. For example, renaming bar.setBarOnFoo to bar.setFooBar is much easier if the declaration in the bar.js module mirrors the usage in other files. A simple search and replace of bar.setBarOnFoo to bar.setFooBar across all files will accomplish the task.
I was in this scenario:
For different reasons I needed to call a function that was on a requirejs module, but the click that fired that call was out of require.
The way I fixed this was creating a requirejs modure that writes over the window object.
define("one", [], function() {
window.popupManager = (function () {
console.log ('aca');
var popUpManager = function () {
self = this;
self.CallMe = function ()
{
alert ('someone calls');
};
};
return new popUpManager();
})();
});
require(['one']);
window.popupManager.CallMe();
This way if any piece of code that is out of the require spectrum (I know it shouldn't be this way) can call functions of this require that writes over the window object.
I really know this is not an "elegant" solution, but it may help you in case of an emergency.