Calling prototype function with .call() - javascript

I'm watching a course on JS design patters and in one of the examples there is this code:
var Task = function (name) {
this.name = name;
this.completed = false;
}
Task.prototype.save = function () {
console.log('saving Task: ' + this.name);
};
var UrgentTask = function (name, priority) {
Task.call(this, name);
this.priority = priority;
};
UrgentTask.prototype = Object.create(Task.prototype);
UrgentTask.prototype.save = function () {
console.log('do special stuff before saving');
//why use Task.prototype.save and not Task.save directly.
Task.prototype.save.call(this);
};
var ut = new UrgentTask('This is urgent', 1);
ut.save();
My question is why inside the UrgentTask.prototype.save function do i have to use Task.prototype.save and not Task.save directly with the .call() method?
and why if i use Task.save it returns can't read property 'call' of undefined??

Related

Uncaught TypeError: Cannot set property 'getName' of undefined(anonymous function)

<script>
var Employee = new function(name)
{
this.name=name;
}
Employee.prototype.getName = function()
{
return this.name;
}
var PermanenetEmployee = new function(annualsalary)
{
this.annualsalary=annualsalary;
}
var employee = new Employee("rahul");
PermanenetEmployee.prototype = employee;
var pe = new PermanenetEmployee(5001);
document.write(pe.getName());
</script>
i am implementing inheritance in java script. From this code i want to print employee name like "rahul".But i am getting error in this like Uncaught TypeError: Cannot set property 'getName' of undefined(anonymous function).How to resolve this error?
Employee.prototype.getName = function()
{
return this.name;
}
This is the problem:
var Employee = new function(name)
// ------------^^^
{
this.name=name;
}
(And the same for PermanenetEmployee.)
You don't want new there. new calls the function. You want to do that later, as you have when assigning to employee.
Note that the way you're setting up inheritance between them is an anti-pattern. To make PermanenetEmployee correctly "subclass" Employee, do this:
PermanenetEmployee.prototype = Object.create(Employee.prototype);
PermanenetEmployee.prototype.constructor = PermanenetEmployee;
not
var employee = new Employee("rahul");
PermanenetEmployee.prototype = employee;
...and then have PermanenetEmployee accept name and pass it to Employee:
var PermanenetEmployee = function(name, annualsalary) {
Employee.all(this, name); // <====
// ...
};
...or better use, use ES2015 ("ES6") class (transpiling if you need to, for instance with Babel).
Here's a correct setup. I've also fixed the typo in PermanenetEmployee:
var Employee = function(name) {
this.name = name;
};
Employee.prototype.getName = function() {
return this.name;
};
var PermanentEmployee = function(name, annualSalary) {
Employee.call(this, name);
this.annualSalary = annualSalary;
};
// Set up subclass
PermanentEmployee.prototype = Object.create(Employee.prototype);
PermanentEmployee.prototype.constructor = PermanentEmployee.prototype;
PermanentEmployee.prototype.getAnnualSalary = function() {
return this.annualSalary;
};
// Using
var pe = new PermanentEmployee("Rahul", 5001);
console.log(pe.getName());
console.log(pe.getAnnualSalary());
And with ES2015:
class Employee {
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
}
class PermanentEmployee extends Employee {
constructor(name, annualSalary) {
super(name);
this.annualSalary = annualSalary;
}
getAnnualSalary() {
return this.annualSalary;
}
}
// Using
var pe = new PermanentEmployee("Rahul", 5001);
console.log(pe.getName());
console.log(pe.getAnnualSalary());
Again, note that you need to transpile if you want to use that syntax in the wild (for now).
There are a couple ways you can get inheritance to work in JS, I am using this pattern.
First declare the base prototype:
Employee = function () {
};
Employee.prototype = {
getName: function () {}
};
And then the prototype that inherits the base:
PermanentEmployee = function () {
Employee.call(this);
};
PermanentEmployee.prototype = Object.create(Employee.prototype);
PermanentEmployee.constructor = PermanentEmployee;
PermanentEmployee.prototype.foo = function() {}

Create objects inside a module javascript

I am learning design patterns in javascript but I have a problem creating a module. I am creating a Person object inside of module and I have combined it with a constructor pattern, just beacuse I am learning it too, but nothing happens.
Can anybody help me, I don't undertand my mistake here
var myModule = (function () {
function Person(id, name) {
this.id = id;
this.name = name;
}
Person.prototype.toString = function () {
return "\nID: " + this.Id + "\nName: " + this.name;
};
return {
newPerson: function (id, name) {
return new Person(id,name);
console.log(Person.toString());
}
};
})();
var x = myModule;
x.newPerson(1, "John");
You should use
var myModule = (function () {
function Person(id, name) {
this.id = id;
this.name = name;
}
return {
newPerson: function (id, name) {
return new Person(id,name);
}
};
})();
var x = myModule;
console.log(x.newPerson(1, "John"));
Forget the toString(), most consoles can fetch the object, and display it in a much better way.
In your case you want to log the toString() of the Person constructor, which would result a string something like this:
"function Person(id, name) {
this.id = id;
this.name = name;
}"
but it does not run, because you put it after the return statement in the newPerson() function, and the return statement stops execution and returns with the results.

Error for JS OOP beginner training

I'm new in programming and I'm learning JavaScript OOP, trying to make a game with tanks. I have some code but it doesn't work properly and I need some help to understand how it works. Please check it and tell me how to solve the problem because I want to add a few more kinds of tanks but before that I need to fix the code.
var Tank = (function () {
function Tank(name) {
this._name = name;
}
Tank.prototype.getWeight = function () { return this._weight; }
Tank.prototype.getName = function () { return this._name; }
return Tank;
}());
var SmallTank = (function () {
this.prototype = Object.create(Tank.prototype);
function SmallTank(name) {
Tank.apply(this._name);
}
SmallTank.prototype._weight = 2;
return SmallTank;
}());
var myTank = new SmallTank("Aleks Tank");
console.log(myTank.getWeight());
It seems that you're just trying to do some kind of inheritance; typically you do this by assigning a parent instance to the prototype of the child.
I think you will want something like this:
var SmallTank = (function () {
function SmallTank(name) {
Tank.call(this, name);
this._weight = 2;
}
SmallTank.prototype = new Tank();
return SmallTank;
}());
Alternatively you can assign Object.create(Tank.prototype).
Here is another way of doing what it looks like you are attempting to do, following the Mozilla guide:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript
var Tank = function (name) {
this.name = name;
};
Tank.prototype.getName = function () { return this.name; };
var SmallTank = function (name) {
Tank.call(this, name);
this.weight = 2;
};
SmallTank.prototype = Object.create(Tank.prototype);
SmallTank.prototype.constructor = SmallTank;
SmallTank.prototype.getWeight = function () { return this.weight; };
var myTank = new SmallTank("Aleks Tank");
console.log(myTank.getName());
console.log(myTank.getWeight());

how to set a passed function in javascript

I am creating a new object variable and passing an object as an argument:
var obj = new test({
first : $('#fname').val(),
last : $('#lname').val(),
fn : function() {
alert(this.first + " " + this.last);
}
});
This is the called function when creating the above variable:
var test = function(obj) {
this.fn = function() {
alert("No custom function was made.");
}
this.first = obj.first;
this.last = obj.last;
if(obj.fn)
this.fn = obj.fn(); //I also tried it without the '()' after 'obj.fn'
};
The first and last variables are fine, but I cannot figure out how to get the custom function that is passed to be set.
You mentioned that you tried removing the '()' after 'obj.fn'... seems to work when I do that. Here's the link to verify: http://jsfiddle.net/TD93x/3/
it worked for me
var test = function(obj) {
this.fn = function() {
alert("No custom function was made.");
}
this.first = obj.first;
this.last = obj.last;
if(obj.fn)
this.fn = obj.fn;
};

Calling method using JavaScript prototype

Is it possible to call the base method from a prototype method in JavaScript if it's been overridden?
MyClass = function(name){
this.name = name;
this.do = function() {
//do somthing
}
};
MyClass.prototype.do = function() {
if (this.name === 'something') {
//do something new
} else {
//CALL BASE METHOD
}
};
I did not understand what exactly you're trying to do, but normally implementing object-specific behaviour is done along these lines:
function MyClass(name) {
this.name = name;
}
MyClass.prototype.doStuff = function() {
// generic behaviour
}
var myObj = new MyClass('foo');
var myObjSpecial = new MyClass('bar');
myObjSpecial.doStuff = function() {
// do specialised stuff
// how to call the generic implementation:
MyClass.prototype.doStuff.call(this /*, args...*/);
}
Well one way to do it would be saving the base method and then calling it from the overriden method, like so
MyClass.prototype._do_base = MyClass.prototype.do;
MyClass.prototype.do = function(){
if (this.name === 'something'){
//do something new
}else{
return this._do_base();
}
};
I'm afraid your example does not work the way you think. This part:
this.do = function(){ /*do something*/ };
overwrites the definition of
MyClass.prototype.do = function(){ /*do something else*/ };
Since the newly created object already has a "do" property, it does not look up the prototypal chain.
The classical form of inheritance in Javascript is awkard, and hard to grasp. I would suggest using Douglas Crockfords simple inheritance pattern instead. Like this:
function my_class(name) {
return {
name: name,
do: function () { /* do something */ }
};
}
function my_child(name) {
var me = my_class(name);
var base_do = me.do;
me.do = function () {
if (this.name === 'something'){
//do something new
} else {
base_do.call(me);
}
}
return me;
}
var o = my_child("something");
o.do(); // does something new
var u = my_child("something else");
u.do(); // uses base function
In my opinion a much clearer way of handling objects, constructors and inheritance in javascript. You can read more in Crockfords Javascript: The good parts.
I know this post is from 4 years ago, but because of my C# background I was looking for a way to call the base class without having to specify the class name but rather obtain it by a property on the subclass. So my only change to Christoph's answer would be
From this:
MyClass.prototype.doStuff.call(this /*, args...*/);
To this:
this.constructor.prototype.doStuff.call(this /*, args...*/);
if you define a function like this (using OOP)
function Person(){};
Person.prototype.say = function(message){
console.log(message);
}
there is two ways to call a prototype function: 1) make an instance and call the object function:
var person = new Person();
person.say('hello!');
and the other way is... 2) is calling the function directly from the prototype:
Person.prototype.say('hello there!');
This solution uses Object.getPrototypeOf
TestA is super that has getName
TestB is a child that overrides getName but, also has
getBothNames that calls the super version of getName as well as the child version
function TestA() {
this.count = 1;
}
TestA.prototype.constructor = TestA;
TestA.prototype.getName = function ta_gn() {
this.count = 2;
return ' TestA.prototype.getName is called **';
};
function TestB() {
this.idx = 30;
this.count = 10;
}
TestB.prototype = new TestA();
TestB.prototype.constructor = TestB;
TestB.prototype.getName = function tb_gn() {
return ' TestB.prototype.getName is called ** ';
};
TestB.prototype.getBothNames = function tb_gbn() {
return Object.getPrototypeOf(TestB.prototype).getName.call(this) + this.getName() + ' this object is : ' + JSON.stringify(this);
};
var tb = new TestB();
console.log(tb.getBothNames());
function NewClass() {
var self = this;
BaseClass.call(self); // Set base class
var baseModify = self.modify; // Get base function
self.modify = function () {
// Override code here
baseModify();
};
}
An alternative :
// shape
var shape = function(type){
this.type = type;
}
shape.prototype.display = function(){
console.log(this.type);
}
// circle
var circle = new shape('circle');
// override
circle.display = function(a,b){
// call implementation of the super class
this.__proto__.display.apply(this,arguments);
}
If I understand correctly, you want Base functionality to always be performed, while a piece of it should be left to implementations.
You might get helped by the 'template method' design pattern.
Base = function() {}
Base.prototype.do = function() {
// .. prologue code
this.impldo();
// epilogue code
}
// note: no impldo implementation for Base!
derived = new Base();
derived.impldo = function() { /* do derived things here safely */ }
If you know your super class by name, you can do something like this:
function Base() {
}
Base.prototype.foo = function() {
console.log('called foo in Base');
}
function Sub() {
}
Sub.prototype = new Base();
Sub.prototype.foo = function() {
console.log('called foo in Sub');
Base.prototype.foo.call(this);
}
var base = new Base();
base.foo();
var sub = new Sub();
sub.foo();
This will print
called foo in Base
called foo in Sub
called foo in Base
as expected.
Another way with ES5 is to explicitely traverse the prototype chain using Object.getPrototypeOf(this)
const speaker = {
speak: () => console.log('the speaker has spoken')
}
const announcingSpeaker = Object.create(speaker, {
speak: {
value: function() {
console.log('Attention please!')
Object.getPrototypeOf(this).speak()
}
}
})
announcingSpeaker.speak()
No, you would need to give the do function in the constructor and the do function in the prototype different names.
In addition, if you want to override all instances and not just that one special instance, this one might help.
function MyClass() {}
MyClass.prototype.myMethod = function() {
alert( "doing original");
};
MyClass.prototype.myMethod_original = MyClass.prototype.myMethod;
MyClass.prototype.myMethod = function() {
MyClass.prototype.myMethod_original.call( this );
alert( "doing override");
};
myObj = new MyClass();
myObj.myMethod();
result:
doing original
doing override
function MyClass() {}
MyClass.prototype.myMethod = function() {
alert( "doing original");
};
MyClass.prototype.myMethod_original = MyClass.prototype.myMethod;
MyClass.prototype.myMethod = function() {
MyClass.prototype.myMethod_original.call( this );
alert( "doing override");
};
myObj = new MyClass();
myObj.myMethod();

Categories

Resources