Why doesn't NodeJS execute constructors the way browsers do? - javascript

I was playing around with NodeJS and I noticed something strange.
I was just exploring the use of constructors through the code below.
// We declare the constructor.
function Personne(inName) {
console.log("go!");
if ('undefined' != typeof inName) {
this.name = inName;
}
}
// We declare the object's prototype (that will be used by the constructor).
var PersonnePrototype = {
name: 'toto',
setName: function(inName) {
this.name = inName; // "this" refers to the new object being created.
},
getName: function() {
return this.name; // "this" refers to the new object being created.
}
};
Personne.prototype = PersonnePrototype;
var p = new Personne("Tom");
console.log("p.getName(): " + p.getName());
console.log(p);
console.log(Object.getPrototypeOf(p));
First, I expected the code inside the constructor Personne(inName) to be executed while using the operator new.
Apparently, this is not the case. Below, I give the output from the execution.
$ node loop-closure.js
p.getName(): toto
{ prototype: { name: false, setName: [Function], getName: [Function] } }
{ name: 'toto', setName: [Function], getName: [Function] }
You can see that the constructor is not executed...
However, if I execute the same code on Chrome or Firefox, then the constructor is executed!
FireFox:
"go!"
"Given: Tom"
"p.getName(): Tom"
Object { name: "Tom" }
Object { name: "toto", setName: window.onload/PersonnePrototype.setName(inName), getName: window.onload/PersonnePrototype.getName() }
Chrome:
go!
Given: Tom
p.getName(): Tom
Personne {name: "Tom", setName: function, getName: function}
Object {name: "toto", setName: function, getName: function}
I thought that NodeJS is the JavaScript interpreter used by Chrome. If this is correct, then why does the interpretation differs between Chrome and NodeJS?
UPDATE
I saw the comments, and I try that:
I just copy/paste the code into a file and call NodeJs on that file.
Yes, you are right: it works as expected.
Then I found what was causing the problem.
I had extra code in the file I executed. I had put a return statement just after the piece of code I gave you. Below, I give you the complete code:
I am using NodeJs version 0.10.35:
$ node -v
v0.10.35
// We declare the constructor.
function Personne(inName) {
console.log("go!");
if ('undefined' != typeof inName) {
this.name = inName;
}
}
// We declare the object's prototype (that will be used by the constructor).
var PersonnePrototype = {
name: 'toto',
setName: function(inName) {
this.name = inName; // "this" refers to the new object being created.
},
getName: function() {
return this.name; // "this" refers to the new object being created.
}
};
Personne.prototype = PersonnePrototype;
var p = new Personne("Tom");
console.log("p.getName(): " + p.getName());
console.log(p);
console.log(Object.getPrototypeOf(p));
return;
console.log("Does the prototype has a constructor property ? " + Object.getPrototypeOf(p).hasOwnProperty('constructor'));
// Other way to say the same thing:
function Personne() {
this.prototype = {
name: false,
setName: function(inName) {
this.name = inName; // "this" refers to the new object being created.
},
getName: function() {
return this.name; // "this" refers to the new object being created.
}
}
};
var p = new Personne(); // Object "p" has a parent. This parent has been created by the prototype (which is a function).
p.setName("Tom");
console.log("The name is " + p.getName() + " / " + this.name);
console.log("Does the prototype has a constructor property ? " + Object.getPrototypeOf(p).hasOwnProperty('constructor'));
// Ou encore :
var p = Object.create(Personne.prototype);
p.setName("Tom");
console.log("The name is " + p.getName() + " / " + this.name);
// We can see the difference between the prototype and the instanced object.
// Both are objects.
// However, as you can see, they do not present the same properties.
utils.dump(Object.getPrototypeOf(p));
Object.getPrototypeOf(p).name;
utils.dump(p);
if (Object.getPrototypeOf(p).getName() != p.getName()) {
console.log("The prototype and the object have different properties.");
console.log("Prototype: " + Object.getPrototypeOf(p).getName());
console.log("Object: " + p.getName());
}
// ------------------------------------------------------------------------------------
// Heritage
// ------------------------------------------------------------------------------------
function Personne() {
this.prototype = {
name: false,
setName: function(inName) {
this.name = inName; // "this" refers to the new object being created.
},
getName: function() {
return this.name; // "this" refers to the new object being created.
}
}
};
function student() {
Personne.call(this);
}
I though that the code after the return statement did not interfere. Apparently, it does.
NodeJs compiles all the code before it executes it. Therefore, if I redefine the constructor later in the code, then it will modify the first occurrence of it.
OK, but:
var v = 1;
console.log("v = " + v);
var v = 2;
console.log("v = " + v);
Output:
$ node test1.js
v = 1
v = 2
And:
var v = 1;
console.log("v = " + v);
return;
var v = 2;
console.log("v = " + v);
Outputs:
$ node test1.js
v = 1
And (may be there is something with references):
var v = { a: 1 };
console.log("v.a = " + v.a);
return;
var v = { a: 2 };
console.log("v.a = " + v.a);
Outputs:
$ node test1.js
v.a = 1
Nothing unusual here... The code after the return statement does not seem to alter the code before the return statement.
#Alexey Ten
Thanks for the hint.
Test1.js:
function Construct() { this.name = "Tom"; }
var v = new Construct();
console.log("v.name = " + v.name);
return;
function Construct() { this.name = "Joe"; }
Test2.js:
var Construct = function() { this.name = "Tom"; }
var v = new Construct();
console.log("v.name = " + v.name);
return;
var Construct = function() { this.name = "Joe"; }
Result for Test1 is: v.name = Joe
Result for Test1 is: v.name = Tom

This post was, in fact, not about NodeJs, but about hoisting (thanks Alexey Ten)
Good explanation:
http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html
Having used languages such as C, C++, Java, PHP, Perl, Tcl, Python or GO, I expected JavaScript to behave the same way, regarding variable declaration. If a variable is not declared before it is used, then, depending upon the language:
You end up with an error.
The variable's value is undefined.
In JavaScript the result depends on how the variable is declared. Please note that the way a variable is declared determines its scope. Hoisting means that JavaScript will put all variables' declarations at the beginning if the variable's scope.
var x; // Declaration
x = 10; // Initialization: this is the first time a value is affected to the variable.
x = 20; // Affectation.
In other words:
(function() {
console.log("x = " + x + " f = " + f); // => x = undefined f = undefined
// Declaration + initialization
var x = 1;
var f = function() {};
})();
Is equivalent to:
(function() {
// Declaration
var x, f;
console.log("x = " + x + " f = " + f); // => x = undefined f = undefined
// initialization
x = 2;
f = function() {};
})();
And this is NOT equivalent to:
(function() {
try {
console.log("x = " + x + " f = " + f);
// initialization
x = 2;
f = function() {};
} catch(e) {
console.log("ERROR: " + e.message); // => ERROR: x is not defined (and f is not defined either).
}
})();
However, watch out! There are some subtle catches:
(function() {
try {
console.log("x = " + x + " f = " + f);
x = 1;
f = function() {};
} catch (e) {
console.log("ERROR: " + e.message); // => ERROR: x is not defined (and f is not defined either).
}
})();
// x and f should be defined ???
console.log("x = " + x + " f = " + f); // => ReferenceError: x is not defined.
Should x and f be defined? In fact, the code that defines x and f is not executed because en exception is raised just before. If you try this :
(function() {
try {
x = 1;
f = function() {};
} catch (e) {
console.log("ERROR: " + e.message);
}
})();
console.log("x = " + x + " f = " + f); // => x = 1 f = function () {}
OR:
(function() {
try {
console.log("x = " + x + " f = " + f); // => x = undefined f = undefined
x = 1;
f = function() {};
} catch (e) {
console.log("ERROR: " + e.message);
}
})();
console.log("x = " + x + " f = " + f); // => x = 1 f = function () {}
var x = 10, f;

Related

Find name of property owner in javascript

An example from some javascript course that I am following:
var Tornado = function(name, cities, degree) {
this.name = name;
this.cities = cities;
this.degree = degree;
};
Tornado.prototype = {
nCities: function() {
return this.cities.length
},
valueOf: function() {
return this.nCities() * this.degree;
},
toString: function() {
return this.cities[0][0].toString() + " " + this.name;
}
}
cities = [["Washington", 1], ["Rotterdam", 2]]
var x = new Tornado("crazy", cities, 3)
console.log(x.nCities())
console.log(x.valueOf())
console.log(x + 16)
console.log(x.toString() + "... wow!")
Object.prototype.findOwnerOfProperty = function(propName) {
var currentObject = this;
while(currentObject !== null) {
if(currentObject.hasOwnProperty(propName)) {
return currentObject;
} else {
currentObject = currentObject.__proto__;
}
}
return "No property found!";
};
console.log(x.findOwnerOfProperty("toString"));
The findOwnerOfProperty function returns the object where the property is defined. This is nice, but it would be nicer to also have the name of that object (Tornado.prototype in this example), how can I do that?
No built-in solution. but you can make a property
this._constructor = arguments.callee.name;
inside Tornado function and make a
getConstructor:function(){
return this._constructor;
}
inside prototype.
BTW , forgot to mention that you should remake
var Tornado = function
to:
function Tornado

Serialize and deserialize JS object

I lately was experimenting with the object serialization in JavaScript. I have already been looking through some of the questions concerning the serialization and deserialization of predefined object in Javascript, but I am looking for a more general solution. An example of this would be:
function anObject(){
var x = 1;
this.test = function(){return x;};
this.add = function(a){x+a;};
}
var x = new anObject();
x.add(2);
console.log(x.test());
>>> 3
var y = deserialize(serialize(x));
console.log(y.test());
>>> 3
Is there a way to serialize this object and deserialize it, such that the deserialized object still have access to the local variable x without the use of the prototype of that object (like in this solution)?
I have already tried by just storing the function as a string and evaluating it again, but then the state of an object can not be saved.
What you are trying to do is not possible without code introspection and code re-writing which I think is not a good idea. However, what about something like this?
function AnObject() {
var x = 1;
this.x = function () { return x; };
this.addToX = function (num) { x += num; };
this.memento = function () {
return { x: x };
};
this.restoreState = function (memento) {
x = memento.x;
};
}
var o = new AnObject();
o.addToX(2);
o.x(); //3
var serializedState = JSON.stringify(o.memento()),
o = new AnObject();
o.restoreState(JSON.parse(serializedState));
o.x(); //3
However, please note that having priviledged members comes at a great cost because you lose the benefits of using prototypes. For that reason I prefer not enforcing true privacy and rely on naming conventions such as this._myPrivateVariable instead (unless you are hiding members of a module).
Thanks for the responses. While the answer from plalx works perfectly for specific objects, I wanted to have something more general which just works for any object you throw at it.
Another solution one can use is something like this:
function construct(constructor, args, vars) {
function Obj() {
var variables = vars
return constructor.apply(this, args);
}
Obj.prototype = constructor.prototype;
return new Obj();
}
function addFunction(anObject, aFunction, variables) {
var objectSource = anObject.toString();
var functionSource = aFunction.toString();
objectSource = objectSource.substring(0,objectSource.length-1);
var functionName = functionSource.substring(9, functionSource.indexOf('('));
var functionArgs = functionSource.substring(functionSource.indexOf('('), functionSource.indexOf('{')+1);
var functionBody = functionSource.substring(functionSource.indexOf('{')+1, functionSource.length);
return objectSource + "this." + functionName + " = function" +
functionArgs + "var variables = " + variables + ";\n" + functionBody + "}";
}
function makeSerializable(anObject) {
var obj = JSON.stringify(anObject, function(key, val) {
return ((typeof val === "function") ? val+'' : val);
});
var variables = [];
while(obj.indexOf("var") > -1) {
var subString = obj.substring(obj.indexOf("var")+3, obj.length-1);
while (subString[0] == " ")
subString = subString.replace(" ", "");
var varEnd = Math.min(subString.indexOf(" "), subString.indexOf(";"));
var varName = subString.substring(0, varEnd);
variables.push(varName);
obj = obj.replace("var","");
}
var anObjectSource = addFunction(anObject,
function serialize(){
var vars = [];
console.log("hidden variables:" + variables);
variables.forEach(function(variable) {
console.log(variable + ": " + eval(variable));
vars += JSON.stringify([variable, eval(variable)]);
});
var serialized = [];
serialized.push(vars);
for (var func in this){
if (func != "serialize")
serialized.push([func, this[func].toString()]);
}
return JSON.stringify(serialized);
},
JSON.stringify(variables));
anObject = Function("return " + anObjectSource)();
var params = Array.prototype.slice.call(arguments);
params.shift();
return construct(anObject, params, variables);
}
This allows you to serialize all elements of any object, including the hidden variables. The serialize() function can then be replaced by a custom string representation for the hidden variables, which can be used when deserializing the string representation to the object.
usage:
function anObject(){
var x = 1;
var y = [1,2];
var z = {"name": "test"};
this.test = function(){return x;};
this.add = function(a){x+a;};
}
var test = makeSerializable(anObject)
test.serialize()
>>>["[\"x\",1][\"y\",[1,2]][\"z\",{\"name\":\"test\"}]",["test","function (){return x;}"],["add","function (a){x+a;}"]]

JavaScript DRY Object Constructors

I have an object that looks something like this:
var myObj = {
_fooCon: function(f) {
if (typeof f != 'function') throw new TypeError('Bad Foo');
this.fn = f;
},
_barCon: function(f) {
if (typeof f != 'function') throw new TypeError('Bad Bar');
this.fn = f;
},
someFoo: function(v) {
return new this._fooCon(function(x) {
return x + ' Foo ' + v;
});
},
someBar: function(v) {
return new this._barCon(function(x) {
return x + ' Bar ' + v;
});
}
};
The reason for doing this is so I can use instanceof productively (i.e., so I can distinguish between the two objects, which are used in different scenarios, despite being structurally identical). (Ignore the fact that someFoo and someBar are similar!)
Is there a way I can abstract the constructor functions, so if I need to create, say, _bazCon, I don't need to repeat myself; or, if there's a bug, I don't have to fix every constructor definition?
I tried making a factory member, like this:
_factory: function(type, f) {
if (typeof f != 'function') throw new TypeError('Bad ' + type);
this.fn = f;
}
...then:
_fooCon: function(f) { return new this._factory('Foo', f); }
Even without trying this, I can see it's not going to work! Any ideas on how to achieve what I'm looking for?
If your functions really do the same thing, then it's as simple as this:
var myObj = {
_factory: function(err) {
return function(f) {
if (typeof f != 'function') throw new TypeError('Bad ' + err);
this.fn = f;
};
},
someFoo: function(v) {
return new this._fooCon(function(x) {
return x + ' Foo ' + v;
});
},
someBar: function(v) {
return new this._barCon(function(x) {
return x + ' Bar ' + v;
});
}
};
myObj._fooCon = myObj._factory("Foo");
myObj._barCon = myObj._factory("Bar");
If there's other behavior that differentiates them, then you could have _factory receive a function argument that is invoked within the constructor. That function could use .call or .apply to set the this value to the object being constructed.
A different approach would be to use a constructor to create myObj, and take advantage of the variable scope so that you don't need to expose the _xxxCon constructors.
This uses an anonymous function as a constructor, since we don't need it again.
var myObj = new function() {
var _factory = function(err) {
return function(f) {
if (typeof f != 'function') throw new TypeError('Bad ' + err);
this.fn = f;
};
};
var _fooCon = _factory("Foo");
var _barCon = _factory("Bar");
this.someFoo = function(v) {
return new _fooCon(function(x) {
return x + ' Foo ' + v;
});
},
this.someBar = function(v) {
return new _barCon(function(x) {
return x + ' Bar ' + v;
});
}
};
You don't necessarily need the outer function to be used as a constructor, but you do need a function that returns an object to myObj.
If you did want to expose the _xxxCon functions, then change var to this., and put the this. back in someFoo and someBar.

how to reach variables of an object that called a function which called a function

i have the following object. i´m trying to reach the variable b from inside the callback of setTimeout but it doesn't work. i know that the callback of setTimeout only knows the variables of the its surrounding function, so how can i reach the this.b? thank you!
function someFunc() {
this.a = 10;
this.b = 20;
this.func = function() {
this.c = 50;
console.log("a = " + this.a); //works
var time = setTimeout(function() {
console.log("b = " + someFunc.b); //this.b doesn't work
console.log("C = " + this.c); //why this doesn't work also? says undefined
},1000);
}
}
var m = new someFunc();
m.func();
function someFunc() {
this.a = 10;
this.b = 20;
var mySomeFunc = this;
this.func = function() {
console.log("a = " + this.a); //works
var time = setTimeout(function() {
console.log("b = " + mySomeFunc.b);
},1000);
}
}
this does not refer to the function object; it refers to the context in which it was called. (your m variable)
someFunc.b is a propertyo f the function itself (like a static property).
You need to save a reference to the outer this in a variable.
Also you can use something like this to execute your anonymous function within your object scope:
function createDelegate(instance, callback) {
return function () {
callback.apply(instance, arguments);
};
}
function someFunc() {
this.a = 10;
this.func = function() {
this.c = 50;
console.log("a = " + this.a);
var time = setTimeout(createDelegate(this, function() {
console.log("b = " + someFunc.b);
console.log("C = " + this.c);
}),1000);
}
}
someFunc.b = 20;
var m = new someFunc();
m.func();

return statement in a function as class

I am confused about the return statement in a function that serves as a class. See the example code below:
<html>
<body>
<script type="text/javascript">
function test() {
this.abc = 'def';
return 3;
}
var mytest = new test();
document.write(mytest + ', ' + (typeof mytest) + ', ' + mytest.abc);
</script>
</body>
</html>
The code out put: [object Object], object, def.
Here is my question. I wrote 'return 3' in the test() function. Is this statement ignored when 'new test()' is called?
Thanks.
When you call a function with new, you're invoking it as a constructor which automatically returns the new object it constructs.
Your return 3; statement is ignored. What is returned is effectively:
{ abc:'def' }
...with an implicit reference to a prototype object, which in your example doesn't have any enumerable properties because you haven't given it any.
If you did:
mytest instanceof test;
...it would evaluate to true.
If you did:
function test() {
this.abc = 'def';
}
test.prototype.ghi = 'jkl';
var mytest = new test();
...you could then do:
mytest.ghi;
...which would give you the value 'jkl'.
When you use the new operator, you're using the function as a constructor, in that case for the return value:
if it's not an object, it is ignored (like in your example)
if it is an object, the object returned becomes the result of the whole new expression
So if you were to write
Test = function(arg) {
this.a = 1;
return arg;
}
var t1 = new Test(10);
var t2 = new Test({b: 2});
console.log(t1, t2)
// output:
// Test {a:1} Object {b: 2}
The new operator instantiates and returns an object. Here are some examples with its output:
(...)
var mytest = test();
document.write(mytest + ', ' + (typeof mytest) + ', ' + mytest.abc);
// 3, number, undefined
Or:
function test() {
this.abc = 'def';
this.getvalue = function(){
return 3;
}
}
var mytest = new test();
document.write(mytest.getvalue() + ', ' + (typeof mytest) + ', ' + mytest.abc);
// 3, object, def
you can do
function test(){
this.abc = "def"
this.ghi = function(){
return "jkl"
}
}
or
function test(){
this.Class = function(){
this.def = "abc"
this.jkl = "ghi"
}
this.abc = "def"
this.ghi = function(){
return "jkl"
}
}

Categories

Resources