how to make nodejs exports a static object - node.js

i wonder to know is the code below runs right
a.js:
var obj = {
name: 'a'
};
module.exports = obj;
b.js
var b = require('./a');
module.exports = b;
c.js
var a = require('./a');
console.log(a); // {name: 'a'}
a.name = 'b';
console.log(require('./a')); // {name: 'b'}
console.log(require('./b')); // {name: 'b'}
so, i can change a module exports from outside
if i cange the a.js to a.json
a.json
{
"name": "a"
}
i got the same result
how can i export a module can't modify or override form outside

You can freeze an object:
// in order for people to not add properties through the prototype
var o = Object.create(null);
o.name = 'a';
Object.freeze(o); // no one can change properties
Object.seal(o); // no one can add properties;
module.exports = o;
If you're using a modern version of nodejs (read io.js) you can also use a proxy:
var o = {name: 'a'};
var p = new Proxy(o, {
set: function(obj, prop, value) {
// unlike the freeze approach, this also throws in loose mode
throw new TypeError("Can't set anything on this object");
}
});
return p;
That said, who are you guarding against? Why would people change the object in another module?

Related

How to define a class AND constants in a CommonJS module

I have seen this thread on how to share constants across CommonJS modules:
How do you share constants in NodeJS modules?
However, if I want the same file to also have a class which should be exposed in the module, then how do I achieve that?
If I do:
module.exports = class A { ... }
Then I "used" the module.exports object.
Is there a way to mix both class AND constants in the same file?
In es6, I would simple add the term "export" before each one...
module.exports = ... is a bad practice if there's a chance that a module can have more than one exported value.
There's already existing module.exports object that is aliased as exports, it's purpose is similar to named exports in ES modules:
exports.A = class A { ... };
exports.b = 'constant';
Got it to work.
In file X.js I write:
constant B = "value";
class A {
}
modules.exports = {
A: A,
B: B
};
In the client code I use:
const X = require('./X');
let a = new X.A();
This is fairly easy to figure out. Now, let's say you have a code like this.
export class A { }
export const y= 5;
Which you basically want. But this is same as
class A { }
const x = 5;
exports.A = A;
exports.x = 5;
Now, you can figure it out also. open up babel repl and paste your ES6 code there. It will give you the ES5 equivalent in the right pane.
I pasted that ES6 code and got back
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var A = exports.A = function A() {
_classCallCheck(this, A);
};
var y = exports.y = 5;
Don't worry about _classCallCheck it is just a safeguard so that you cannot just call A() instead of new A()

I just started learning node.js and i implemented a demo code exhibiting event listeners. I got an error

I am getting this error in my code
TypeError: account.on() is not a function
Where did i go wrong?
Code
var events = require('events');
function Account() {
this.balance = 0;
events.EventEmitter.call(this);
this.deposit = function(amount) {
this.balance += amount;
this.emit('balanceChanged');
};
this.withdraw = function(amount) {
this.balance -= amount;
this.emit('balanceChanged');
};
}
Account.prototype._proto_ = events.EventEmitter.prototype;
function displayBalance() {
console.log('Account balance : $%d', this.balance);
}
function checkOverdraw() {
if (this.balance < 0) {
console.log('Account overdrawn!!!');
}
}
function checkgoal(acc, goal) {
if (acc.balance > goal) {
console.log('Goal Achieved!!!');
}
}
var account = new Account();
account.on('balanceChanged', displayBalance);
account.on('balanceChanged', checkOverdraw);
account.on('balanceChanged', function() {
checkgoal(this, 1000);
});
account.deposit(220);
account.deposit(320);
account.deposit(600);
account.withdraw(1200);
Your example code is not idiomatic Node JS.
I'd strongly recommend you follow the recommended best practices when creating new inheritable objects, as in:
var util=require('util');
var EventEmitter = require('events').EventEmitter;
var Account = function(){
EventEmitter.call(this); // should be first
this.balance=0; // instance var
};
util.inherits(Account,EventEmitter);
Account.prototype.deposit = function(amount){
this.balance += amount;
this.emit('balanceChanged');
};
Account.prototype.withdraw = function(amount){
this.balance -= amount;
this.emit('balanceChanged');
};
var account = new Account();
var displayBalance = function(){
console.log("Account balance : $%d", this.balance);
};
account.on('balanceChanged',displayBalance);
account.deposit(200);
account.withdraw(40);
// ... etc. ....
Which, when run displays:
Account balance : $200
Account balance : $160
Best practices are there so that
your code can be expressed in a way that is easy for others to understand
you don't run into unexpected problems when you try to replicate functionality that is already defined, possibly complex and difficult to understand.
The reason that util.inherits exists is so you don't have to worry about how the prototype chain is constructed. By constructing it yourself, you will often run into the problem you experienced.
Also, since the current Node runtime (>6.0) also includes most of the ES6 spec, you can also (and really should) write your code as:
const util = require('util');
const EventEmitter = require('events').EventEmitter;
const Account = () => {
EventEmitter.call(this);
this.balance = 0;
};
util.inherits(Account,EventEmitter);
Account.prototype.deposit = (val) => {
this.balance += val;
this.emit('balanceChanged');
};
Account.prototype.withdraw = (val) => {
this.balance -= val;
this.emit('balanceChanged');
};
The use of the const keyword assures the variables you create cannot be changed inadvertently or unexpectedly.
And the use of the "fat arrow" function definition idiom (() => {}) is more succinct and thus quicker to type, but also carries the added benefit that it preserves the value of this from the surrounding context so you never have to write something like:
Account.prototype.doSomething = function() {
var self = this;
doSomething(val, function(err,res){
if(err) {
throw err;
}
self.result=res;
});
};
which, using the 'fat arrow' construct becomes:
Account.prototype.doSomething = () => {
doSomething(val, (err,res) => {
if(err) {
throw err;
}
this.result=res; // where 'this' is the instance of Account
});
};
The "fat arrow" idiom also allows you to do some things more succinctly like:
// return the result of a single operation
const add = (a,b) => a + b;
// return a single result object
const getSum = (a,b) => {{a:a,b:b,sum:a+b}};
Another way to create inheritable "classes" in ES6 is to use its class construction notation:
const EventEmitter = require('events');
class Account extends EventEmitter {
constructor() {
super();
this._balance = 0; // start instance vars with an underscore
}
get balance() { // and add a getter
return this._balance;
}
deposit(amount) {
this._balance += amount;
this.emit('balanceChanged');
}
withdraw(amount) {
this._balance -= amount;
this.emit('balanceChanged');
}
}
It should be noted that both ways of constructing inheritable prototypal objects is really the same, except that the new class construction idiom adds syntactic "sugar" to bring the declaration more in-line with other languages that support more classical object orientation.
The ES6 extensions to node offer many other benefits worthy of study.

node.js - why this local function can modify global variables?

Here is my code:
var handleCondition = function(condition,params){
var dup_condition;
dup_condition = condition;
var isArray = function(obj) {
return Object.prototype.toString.call(obj) === '[object Array]';
};
var __replace = function(str){
var reg_slot = /^#(.+)/;
if(reg_slot.test(str) == true){
var ss = reg_slot.exec(str)[1];
return params[ss];
}else{
return str;
}
};
var compare = function(a){
var arr = a;
if(params != undefined){
for(var j =1;j<arr.length;j++){
arr[j] = __replace(arr[j]);
}
}
switch(arr[0]){
case "$eq":
case "==":
return (arr[1] == arr[2]);
default:
return (arr[1] == arr[2]);
}
};
if(isArray(dup_condition)){
var im = function (arr){
for(var i=0;i<3;i++){
if(isArray(arr[i])){
arr[i] = im(arr[i]);
}
}
return compare(arr);
};
var res = im(dup_condition);
return res;
}
};
/*Here are test data*/
var c = {
"beforeDNS":
["$eq","#host",["$eq",10,10]]
,
"afterDNS":["$match",/^10\.+/,"#ip"]
};
var params ={
host:"dd"
};
console.log(c["beforeDNS"]); // ==> ["$eq","#host",["$eq",10,10]]
handleCondition(c["beforeDNS"],params);
console.log(c["beforeDNS"]); // ==> ["$eq","dd",true]
handleCondition(c["beforeDNS"],params);
The first time I run the code with the expected result;
However , when I tried to run the function second time,to my surprise,the value of c["beforeDNS"] has changed unexpectedly!
In fact,I haven't write any code in my function to modify the value of this global variable,but it just changed.
So please help me find the reason of this mysterious result or just fix it.Thanks!
Your dup_condition variable isn't duping anything. It's just a reference to the argument you pass in.
Thus when you pass it to the im function, which modifies its argument in place, it is just referencing and modifying condition (which is itself a reference to the c["beforeDNS"] defined outside the function).
To fix this you might use slice or some more sophisticated method to actually dupe the arguments. slice, for example, would return a new array. Note though that this is only a shallow copy. References within that array would still refer to the same objects.
For example:
if (isArray(condition)) {
var dup_condition = condition.slice();
// ...
}
In javascript the objects are passed by reference. In other words, in handleCondition dup_condition still points to the same array. So, if you change it there you are actually changing the passed object. Here is a short example which illustrates the same thing:
var globalData = {
arr: [10, 20]
};
var handleData = function(data) {
var privateData = data;
privateData.arr.shift();
privateData.arr.push(30);
}
console.log(globalData.arr);
handleData(globalData);
console.log(globalData.arr);
The result of the script is:
[10, 20]
[20, 30]
http://jsfiddle.net/3BK4b/

Object Based EventListener/EventEmitter in NodeJS?

I suddenly realized that event emitter in NodeJS is usually like a static method in Java.. Example:
// This illustrated that event listener is universal
function A(a){
var that = this;
this.a = a;
this.cnt = 0;
this.done = function(){
this.emit("done");
};
this.say = function(){
console.log(a + " = " + that.cnt);
};
this.inc = function(){
that.cnt++;
};
}
A.prototype = new events.EventEmitter;
var a = new A("a"),
b = new A("b"),
c = new A("c");
a.on("done",function(){a.inc()});
b.on("done",function(){b.inc()});
c.on("done",function(){c.inc()});
c.done();
c.done();
a.say();
b.say();
This code would give output:
a = 2
b = 2
While I'm actually expecting:
a = 0
b = 0
I believe this is because of the line:
A.prototype = new events.EventEmitter;
and I think the "prototype" kind of definition would be used like "static" in Java.
In order to have per-object based event listener, I changed the above code to be:
function B(a){
var that = this;
this.evt = new events.EventEmitter;
this.a = a;
this.cnt = 0;
this.done = function(){
this.evt.emit("done");
};
this.say = function(){
console.log(a + " = " + that.cnt);
};
this.inc = function(){
that.cnt++;
};
}
var a = new B("a"),
b = new B("b"),
c = new B("c");
a.evt.on("done",function(){a.inc()});
b.evt.on("done",function(){b.inc()});
c.evt.on("done",function(){c.inc()});
c.done();
c.done();
a.say();
b.say();
This would be per-object event listener, but I don't really think that is a good design/implementation because it breaks the chaining of EventEmitter. I.e., like code bellow:
// can chain another method of A after the on() method
a.on("event",functionCallback).anotherMethodOfA();
I'd like to ask, what's a proper implementation of the per-object event listener in NodeJS?
You can use addListener or on to attach listeners to your custom events. You won't need to chain calls on these methods. Of course you can inherit any object from EventEmitter and add emitting functionality to your object. You can inherit your object from an instance of EventEmitter. There's is function called inherit in the util library which does that for you.
var util = require('util');
var eventEmitter = require('events').EventEmitter;
// Now create your constructor/object.
function MyObj(a, b) {
this.a = a;
this.b = b;
.
.
.
}
util.inherits(MyObj,eventEmitter);
// Implement your methods and add the functionality you need.
MyObj.prototype.aMethod = function(arg) {
.
.
.
// Define how to emit events
if (arg == 'A')
this.emit('eventA', this.a);
else if (arg == 'B')
this.emit('eventB');
// Return this for chaining method calls
return this;
}
MyObj.prototype.anotherMethod = function() {
// Add more functionality...
.
.
.
return this;
}
// Now instantiate the constructor and add listenters
var instanceOfMyObj = new MyObj('a parameter', 'another parameter');
instanceOfMyObj.on('eventA', function(a){
// Handle the event
});
// Now chain calls..
instanceOfMyObj.aMethod('A').anotherMethod(); // This will trigger eventA...

Writing a javascript library

I want to write a JS library and handle it like this:
var c1 = Module.Class();
c1.init();
var c1 = Module.Class();
c2.init();
And of course, c1 and c2 can not share the same variables.
I think I know how to do this with objects, it would be:
var Module = {
Class = {
init = function(){
...
}
}
}
But the problem is I can't have multiple instances of Class if I write in this way.
So I'm trying to achieve the same with function, but I don't think I'm doing it right.
(function() {
var Module;
window.Module = Module = {};
function Class( i ) {
//How can "this" refer to Class instead of Module?
this.initial = i;
}
Class.prototype.execute = function() {
...
}
//Public
Module.Class = Class;
})();
I don't have a clue if it's even possible, but I accept suggestions of other way to create this module.
I don't know if it's relevant also, but I'm using jQuery inside this library.
Usage:
var c1 = Module.Class("c");
var c2 = Module.Class("a");
var n = c1.initial(); // equals 'c'
c1.initial("s");
n = c1.initial(); // equals 's'
Module Code:
(function(window) {
var Module = window.Module = {};
var Class = Module.Class = function(initial)
{
return new Module.Class.fn.init(initial);
};
Class.fn = Class.prototype = {
init: function(initial) {
this._initial = initial;
},
initial: function(v){
if (v !== undefined) {
this._initial = v;
return this;
}
return this._initial;
}
};
Class.fn.init.prototype = Class.fn;
})(window || this);
This is using the JavaScript "Module" Design Pattern; which is the same design pattern used by JavaScript libraries such as jQuery.
Here's a nice tutorial on the "Module" pattern:
JavaScript Module Pattern: In-Depth

Resources