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"
}
}
Related
I'd like to know if it is possible to achieve this in javascript:
function Hello() { }
Hello.prototype.echo = function echo() {
return 'Hello ' + this.firstname + '!';
};
// execute the curryed new function
console.log(new Hello()('firstname').echo())
Is it possible to curry var o = new Class()(param1)(param2)(...) ?
Thank you in advance for your help.
Using the answer of georg with an array of the properties and a counter for assigning an arbitrary count of properties.
function Hello() {
var args = ['firstname', 'lastname'],
counter = 0,
self = function (val) {
self[args[counter++]] = val;
return self;
};
Object.setPrototypeOf(self, Hello.prototype);
return self;
}
Hello.prototype.echo = function echo() {
return 'Hello ' + this.firstname + ' ' + (this.lastname || '') + '!';
};
console.log(new Hello()('Bob').echo());
console.log(new Hello()('Marie')('Curie').echo());
For example:
function Hello() {
let self = function (key, val) {
self[key] = val;
return self;
};
Object.setPrototypeOf(self, Hello.prototype);
return self;
}
Hello.prototype.echo = function echo() {
return 'Hello ' + this.firstname + this.punct;
};
console.log(new Hello()('firstname', 'Bob')('punct', '...').echo())
In your code new Hello('Bob') does not return a function, but an object that has an .echo() method.
function Hello(firstname) {} is a contructor function that returns an object when instantiated with new.
// constructor function expecting 1 argument
function Hello(firstname) {
this.firstname = firstname;
}
// attach a method to the constructor prototype
Hello.prototype.echo = function() {
return 'Hello ' + this.firstname + '!'; // the method can use the contructor's properties
};
// new Hello('Bob') returns the object, and you can call the .echo() method of that object
console.log(new Hello('Bob').echo())
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;
I need more clarification for this problem.I have an object and it has two functions as like this.
<script type="text/javascript">
obj =
{
f1 : function ()
{
var k = this. f2(param1 , param2 , param3);// I don't know whether it is correct
},
f2 : function (par1 , par2 , par3)
{
return param1 + param2 + param3;
}
}
</script>
How can I call function f2 from f1? Can I declare f1 in f2? If yes, how is it? Which is the best method?
Not to replace the above answers, but to provide an alternative: when I write definitions of objects that have methods I prefer to use function constructor so that I can hide "private" closure variables and have some resemblance to OOP.
var myClass = function() {
/******** PRIVATE **********/
var _s = "foo"; // Private member
var _f = function() {}; // Private method
/******** PUBLIC **********/
this.s = "bar"; // Public member
this.f1 = function() { // Public method
console.log(_s + " " + this.s); // Concat private and public
}
this.f2 = function() {
this.f1();
}
}
var myObject = new myClass();
myObject.f2(); // prints "foo bar"
You can use it by the code you have given,but be care of the scope.
Please consider the output of following two part of code.
obj =
{
f1 : function () {
var k = this. f2(1 , 2 , 3);
},
f2 : function (par1 , par2 , par3){
console.log(this);
return par1 + par2 + par3;
}
}
obj.f1();
and
obj =
{
f1 : function () {
var k = this. f2(1 , 2 , 3);
},
f2 : function (par1 , par2 , par3){
console.log(this);
return par1 + par2 + par3;
}
}
function MyClass () {
return this;
}
MyClass.prototype = obj;
var tmp = new MyClass();
tmp.f1();
You also can declare f1 in f2,but if you want to use f1 at the other place,you must write f1 agian.
To share this, the functions would be better to be added to obj.prototype.
obj = {};
obj.prototype = {
f1: function(){
},
f2: function(params){
}
};
Something like this may give you a better idea. I have tested it it runs fine.
obj =
{
f1 : function ()
{
console.log("in F1");
obj.f2();
},
f2 : function ()
{
console.log("in F2");
}
};
console.log(obj.f1());
Here is the fiddle to it => http://jsfiddle.net/CJ7Uz/
calling f2 like this:
<pre>
<script type="text/javascript">
obj =
{
f1 : function ()
{
var k = this.f2(1 , 2 , 3);// it is correct :)
alert(k);
},
f2 : function (par1 , par2 , par3)
{
return par1 + par2 + par3;
}
}
obj.f1();
</script>
</pre>
and check the link below to find the answer of your second question
http://www.phpied.com/3-ways-to-define-a-javascript-class/
Going off of Barmar's suggestion, here's what the code would look like:
<script type="text/javascript">
var obj = {
f1: function () {
var k = this.f2(param1 , param2 , param3);
},
f2: function (par1 , par2 , par3) {
return par1 + par2 + par3;
}
};
</script>
Also, bad idea to stick a space after this. in your code. :)
your problem is resolved:
Click
obj =
{
f1 : function ()
{
alert('f1');
var param1=param2=param3=0;
var k = this.f2(param1 , param2 , param3);
},
f2 : function (param1 , param2 , param3)
{
alert('f2')
return param1 + param2 + param3;
}
}
For demo visit this link DEMO
function condition(){
this.expression = "";
this.toString = function(){
return this.expression;
}
};
function and(first, second){
this.expression = first + " and " + second;
}
function nop(){};
nop.prototype = condition.prototype;
and.prototype = new nop();
var a =new and(1,2);
console.log(a.toString());
it is expected to see "1 and 2" as output but this is what happened:
"[object Object]"
You are transfering the prototype of condition to nop's prototype. The problem is that your condition.toString is not declared in the prototype... Here:
function condition(){
this.expression = "";
};
condition.prototype.toString = function(){
return this.expression;
}
function and(first, second){
this.expression = first + " and " + second;
}
function nop(){};
nop.prototype = condition.prototype;
and.prototype = new nop();
var a =new and(1,2);
console.log(a.toString());
OR
function condition(){
this.expression = "";
this.toString = function(){
return this.expression;
}
};
function and(first, second){
this.expression = first + " and " + second;
}
function nop(){};
nop = condition;
and.prototype = new nop();
var a =new and(1,2);
console.log(a.toString());
you aren't overriding the toString method, because the constructer of condition is never called! try doing this;
condition.prototype.toString=function(){
return this.expression;
}
try passing strings into your and function, as at the moment you are trying to concatenate integers to a string var a =new and("1","2");
it should be like this
function condition(){
this.expression = "";
};
condition.prototype.toString = function(){
return this.expression;
}
Ok, so the problem here is you are mixing two inheritance patterns (http://davidshariff.com/blog/javascript-inheritance-patterns/) the pseudo-classical with the functional patterns.
You can create an object by adding methods on the constructor function:
function MyClass() {
var privateProperty = 1;
this.publicProperty = 2;
function pivateMethod() {
// some code ...
}
this.publicMethod = function() {
// some code ...
};
}
// inheritance
function SubClass() {
MyClass.call(this);
this.newMethod = function() { };
}
Here when you create a instance of this class you are creating every method again.
Then you have the prototype pattern:
function MyClass() {
this._protectedProperty = 1;
this.publicProperty = 2;
}
MyClass.prototype._protectedMethod = function() {
// some code ...
};
MyClass.prototype.publicMethod = function() {
// some code ...
};
// inheritance
function SubClass() {
MyClass.call(this);
}
SubClass.prototype = new MyClass();
SubClass.prototype.newMethod = function() { };
// OR
function SubClass() {
MyClass.call(this);
}
function dummy() { }
dummy.prototype = MyClass.prototype;
SubClass.prototype = new dummy();
SubClass.prototype.newMethod = function() { };
Yhen you must choose one of those two patterns, not both·
I've fixed your code on this fiddle: http://jsfiddle.net/dz6Ch/
How do I access 'a' below?
var test = function () {
return {
'a' : 1,
'b' : this.a + 1 //doesn't work
};
};
You can't do it this way. When you are in the process of constructing an object (that's what you actually do using the curly braces), there is no way to access it's properties before it is constructed.
var test = function () {
var o = {};
o['a'] = 1;
o['b'] = o['a'] + 1;
return o;
};
var t = function ()
{
return new x();
};
var x = function ()
{
this.a = 1;
this.b = this.a + 1; //works
}
abstract a layer
edited for formatting, and noting that this is shifting from OLN
You can't Object Literal Notion does not support this access
var test = function () {
//private members
var a = 1;
var b = a + 1;
//public interface
return {
geta : function () {
return a;
},
getb : function () {
return b;
}
}
}();