var Greeter = (function () {
function Greeter(message) {
this.greeting = message;
}
Greeter.prototype.greet = function () {
return "Hello, " + this.greeting;
};
return Greeter;
})();
var Greeting = (function(){
Greeting.prototype = new Greeter();
Greeting.prototype.constructor = Greeter;
function Greeting(greeting){
}
return Greeting;
})();
var greeting = new Greeting("World");
alert(greeting.greet());
I'm trying to manipulate inheritance using javascript prototyping. I have a class structure like above. But when I call the greet method it display some thing like the below image shows. Can anybody guid me on this ?
You are never invoking the "constructor" function Greeter when you are creating the Greeting object. So the this.greeting = message; line never runs, that is why it is undefined.
You have to either insert that line manually:
function Greeting(greeting){
this.greeting = greeting;
}
or invoke the parent constructor:
function Greeting(greeting){
Greeter.call(this, greeting);
}
In your "greet" method of your Greeter you call this.greeting. However, in your Greeting object you haven't defined a "greeting" method...
You call greet method on Greeting context which don't have greeting property.
And there is no reason to wrap code in IIEF in your case, because there is no private vars, so (it works):
var Greeter = function (message) {
this.greeting = message;
};
Greeter.prototype.greet = function () {
return "Hello, " + this.greeting;
};
var Greeting = function (greeting){
Greeter.call(this, greeting)
}
Greeting.prototype = new Greeter();
var greeting = new Greeting("World");
alert(greeting.greet());
When you call greeting.greet(), this.greeting is undefined, thus the problem.
Explanation:
Try this code:
var Greeter = (function () {
function Greeter(message) {
this.greeting = message;
}
Greeter.prototype.greet = function () {
return "Hello, " + this.greeting;
};
return Greeter;
})();
console.log('Log 1: ' + Greeter);
var Greeting = (function(){
console.log('Log 2: ' + Greeting);
Greeting.prototype = new Greeter();
console.log('Log 3: ' + Greeting);
Greeting.prototype.constructor = Greeter;
console.log('Log 4: ' + Greeting);
function Greeting(greeting){
}
console.log('Log 5: ' + Greeting);
return Greeting;
})();
console.log('Log 6: '+Greeting);
var greeting = new Greeting("World");
alert(greeting.greet());
You will see that Greeting is just an empty function, but with Greeter as the prototype. So, new Greeting('World') creates the following function:
function Greeting(greeting){
}
with a prototype containing greeting (undefined), constructor (a function), and greet (a function). Greeting.prototype.greet, in turn, has this definition:
Greeting.prototype.greet = function () {
return "Hello, " + this.greeting;
};
But this.greeting is undefined in this context, because this refers to Greeting.prototype.greet, not Greeter. Thus, these lines:
var greeting = new Greeting("World");
alert(greeting.greet());
fail, because greeting.greet() returns Hello, concatenated with an undefined value.
change the Greeting class like this:
var Greeting = (function(){
function Greeting(greeting){
Greeter.apply(this, arguments);
}
Greeting.prototype = new Greeter();
Greeting.prototype.constructor = Greeter;
Greeting.superClass = Greeter;
return Greeting;
})();
or if you want to create a general solution for all of your inheritance model, do this:
var Greeting = (function(){
var Greeting = function $SubClass(greeting){
$SubClass.prototype.constructor.apply(this, arguments);
}
Greeting.prototype = new Greeter();
Greeting.prototype.constructor = Greeter;
return Greeting;
})();
The important point in this part:
var Greeting = function $SubClass(greeting){};
is when you directly assign the function to a variable, you would have access to your function based on its label ($SubClass) only in the function context.
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 am stuck with a design pattern in JavaScript where I would like to create a private static member variable for keeping object count. Something along these lines:
var person = function(name){
//How to persist this value across multiple calls avoiding Globals
var _personCount = _personCount || 0;
_personCount++;
var _name = name;
getPerson = function(){
return "Person is: " + _name;
}
};
person("foo");//_personCount should be 1 after this call
person("bar");//_personCount should be 2 after this call
The idea is something to similar to private static variables, accessible only to the class's internal variables
You can use the revealing module pattern:
var something = (function() {
var myThing = 0;
return {
doSomething: function() {
myThing++;
}
};
})();
something.doSomething(); // myThing is now 1
The variable is within what's called an IIFE (immediately invoked function expression) will remain throughout the lifecycle of the program.
If you're going to instantiate the module more than once in different places, you'll need to also create a singleton.
If you want the variable to be global to all the persons, you need to define them within the scope of a containing function. This can be an IIFE, since it only need to run once.
var person = (function() {
var _personCount = _perconCount || 0;
return function(name) {
_personCount++;
var _name = name;
getPerson = function() {
return "Person is: " + _name;
};
};
})();
You must create the private static variable in the closure context.
var person = (function() {
//private variable
var _personCount = 1;
return function(name) {
this.name = name;
this.id = _personCount++;
}
}());
var foo = new person('foo');
console.log(foo.id + ' ' + foo.name);//1 foo
var boo = new person('boo');
console.log(boo.id + ' ' + boo.name);//2 boo
Here the enclosing anonymous function can never be called again. It gets executed while JS engine parses your code, and creates _personCount variable which can be accessed only by inner function function(name) making it like private static.
I think that this could help you!
note: the prototype property for having instance method!
note: count, instead, is static!
var Person = (function() {
var counter = 0;
function Person(name) {
this.name = name;
}
Person.prototype.getName = function() {
counter += 1;
return this.name;
};
Person.count = function() { return counter; };
return Person;
})();
var superman = new Person('SuperMan');
var batman = new Person('BatMan');
var el = function() { return window.document.getElementById('counter'); }
function p1() {
var name = superman.getName();
el().innerText = name + ' - ' + Person.count();
}
function p2() {
var name = batman.getName();
el().innerText = name + ' - ' + Person.count();
}
<h1 id="counter">0</h1>
<button onclick="p1()">Person1</button>
<button onclick="p2()">Person2</button>
I have tried to create an instance of object internally like the following:
var oo = function(){
return new func();
}
var func = function(){
this.name;
this.age;
};
func.prototype = {
setData: function(name, age){
this.name = name;
this.age = age;
},
getData: function (){
return this.name + " " + this.age;
}
}
When usage, I got an error oo.setData is not a function.
oo.setData("jack", 15);
console.log(oo.getData());
What's wrong in my code?
This happens because oo is not a "func", oo returns a new func. You could set the data using
oo().setData('jack',15);
But then you have no way of accessing it.
You could also use
var newfunc = oo();
newfunc.setData('jack',15);
newfunc.getData();
oo is a function to create a object.
var oo = function(){ //the oo variable is used to create func() objects
return new func();
}
var func = function(){ //function
this.name;
this.age;
};
func.prototype = { //define properties to func
setData: function(name, age){
this.name = name;
this.age = age;
},
getData: function (){
return this.name + " " + this.age;
}
}
//create instance
var myObject = oo();
//or
var myObject = new func();
//Use
myObject.setData("jack", 12);
//Get a property
console.log(myObject.getData())
I think I finally wrapped my head around understanding how methods, constructor functions, and objects work. Could someone please review my code, and let me know if I using the correct names and syntax? Thanks a ton!
function objectConstructor (arg1, arg2) {
this.property1 = arg1;
this.property2 = arg2;
this.methodName = functionName;
}
function functionName() {
console.log(this.property1 + ' ' + this.property2);
}
var object1 = new objectConstructor('value1','value2');
console.log(object1.property1);
console.log(object1.methodName());
Methods of Javascript classes should be defined as prototype:
var CustomObject = function (arg1, arg2) {
this.property1 = arg1;
this.property2 = arg2;
};
CustomObject.prototype.functionName = function() {
console.log(this.property1 + ' ' + this.property2);
};
var object1 = new CustomObject("value1","value2");
Everything else seems fine to me though.
Use prototype functions. Else your inner functions get copied with every instance.
function Person(firstName, lastName)
{
this.firstName = firstName;
this.lastName = lastName;
}
Person.prototype.getFullName = function()
{
return this.firstName+' '+this.lastName;
}
var person1 = new Person('foo', 'bar');
console.log(person1.getFullName());
There are many other patterns which for example prevent the pollution of the global scope or allow a more class like approach. (Object literal, Module Pattern, Self-Executing Anonymous Functions)
The same example with the module pattern:
var Person = (function()
{
var Person = function(firstName, lastName)
{
this.firstName = firstName;
this.lastName = lastName;
}
Person.prototype.getFullName = function()
{
return this.firstName+' '+this.lastName;
}
return Person;
})();
var person1 = new Person('foo', 'bar');
console.log(person1.getFullName());
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/