a prototype question in javascript - javascript

<script type="text/javascript">
var Person =
{
Create: function(name, age) {
this.name = name;
this.age = age;
},
showMe: function() {
return " Person Name: " + this.name + " Age: " + this.age + " ";
}
};
function New(aClass, aParams) {
function new_() {
aClass.Create.apply(this, aParams);
};
new_.prototype = aClass;
var obj = new new_();
return obj;
}
</script>
I don't quite understand the code above. Could someone tell me the meanings of Person, Create, showMe, New and new_? Thanks a lot.

Person is an object with two functions - Create and showMe. In JavaScript, there are no classes, only objects, and this is how you write up an object - using 'Object Literal Notation' (the curly braces and functions/properties separated by commas).
New is a clever re-implementation of the new keyword. Instead of classes, javascript has prototypes, and instead of creating an instance of a class you create a copy of the prototype. In this case, if you passed Person to New(), it would used as the prototype in new_.prototype = aClass, and the rest of this function will return an object with the Person prototype, which means any changes to Person later on will be inherited into obj as well (unless obj has overridden them).

`Person` -- a variable w/ 'parts' (used loosely) `Person.Create` and `Person.showMe'
`Person.Create` -- function of `Person` that sets `Person.name` and `Person.age` to its arguments
`Person.showMe` -- returns a string explaining values of `Person.name` and `Person.age`
`New` -- a function intended to instantiate new Person's thru prototypal (this is NOT class based) inheritenced
`New._new` -- `New` uses this to get it done
Basically thru prototype inheritence, even though Person is only 'made' once, other 'versions' of it can be constructed in kind. It can be used like this (try it here: http://jsfiddle.net/PBhCs/)
var Person = {
Create: function(name, age)
{
this.name = name;
this.age = age
},
showMe: function()
{
return " Person Name: " + this.name + " Age: " + this.age + " ";
}
};
function New(aClass, aParams)
{
function new_()
{
aClass.Create.apply(this, aParams);
};
new_.prototype = aClass;
var obj = new new_();
return obj;
}
var a = New(Person, ['moo', 5]);
var b = New(Person, ['arf', 10]);
alert(a.showMe() + b.showMe());

Related

How to use constructors as a prototype chain?

Suppose that I have a javascript constructor:
function Person(name) {
this.name = name;
this.hello = function () { return "It's a-me, " + name + "!"; };
}
the Person "type" has a convenient method, hello that I would like to re-use on another type Student. I would like for a Student to have the following structure:
function Student(name) {
this.name = name;
this.hello = function () { return "It's a-me, " + name + "!"; };
this.books = [];
}
One option is to use the code for Student as-is above. This is sub-optimal for the usual reasons, such as that if I want it to mirror the Person type, then I have to manually keep their code in sync. Anyway, this is not good.
A second option (from this answer) is to do something like:
function Student(name) {
Person.call(this, name);
this.books = [];
}
When I mario = new Student("mario") I get the following:
Object { name: "mario", hello: hello(), books: [] }
I've successfully achieved the inheritance that I wanted, but this has the unfortunate property of placing all of the desired properties into my object. Notably, for example, there is a "hello" property on mario. It would be nice if that "hello" property could be looked up in the prototype chain.
How can I neatly create a prototype chain given the relevant object constructors?
When you create an object with new, the this value of your constructor function is set to the object, and that object's prototype is set to the prototype of the constructor Function being called.
That's why your properties are currently being added to the created object.
function Student {
this.name = name
}
const student = new Student('John')
// is (almost) equivalent to the following
const student = {}
student.name = 'John'
But if you want to add properties to the prototype instead, so that you can use inheritance, then in ES5 Javascript you can do so by assigning properties directly to the prototype of your constructor function.
function Person(name) {
this.name = name;
}
// Person is a function
// Its prototype is an instance of Object, and it has no properties
// i.e. something like Person.prototype = new Object()
Person.prototype.hello = function() {
return 'It is I, ' + this.name
}
// Now Person.prototype has one property, "hello", which is a function.
function Student(name) {
Person.call(this, name)
this.books = [];
}
// Student is a function
// Its prototype is also an instance of Object with no properties
// the following is the magic line
Student.prototype = Object.create(Person.prototype)
// We replace the prototype of the Student function with a new object, but
// Object.create() allows us to set the prototype to an existing object, in this case Person.prototype,
// Person.prototype is itself an instance of Object, and we previously
// added the "hello" function to it as a property.
const student = new Student('John')
// So what happens here?
// First a new object is created, and its prototype is set to Student.prototype
// Then we call Person.call(this)
// Which executes the body of the Person function
// So you get the properties on the object itself through the body of the Person and Student functions
// And you get the shared functionality through the prototype chain of instance -> Student.prototype -> Person.prototype -> Object.prototype
Hope that helps!
You can use prototyping method or class sugar method as you want.
Here is a simple example :
function Student(name) {
this.name = name;
this.books = [];
}
Student.prototype.hello = function(){
return "It's a-me, " + this.name + "!";
}
Student.prototype.addBook = function(book){
this.books.push(book);
}
Student.prototype.getBooks = function(){
return this.books;
}
let mario = new Student("Mario");
console.log(mario.hello());
mario.addBook("prototyping");
mario.addBook("chain");
console.log(mario.getBooks());
class Person {
constructor(name) {
this.name = name;
this.books = [];
}
hello(){
return "It's a-me, " + this.name + "!";
}
addBook(book){
this.books.push(book);
}
getBooks(){
return this.books;
}
}
let luigi = new Person("Luigi");
console.log(luigi.hello());
luigi.addBook("classSugar");
luigi.addBook("classType");
console.log(luigi.getBooks());
For longer chains use Object.assign, here is an example of making a GradStudent that is both a Student and a Person and has the personality of a Comedian and also has the properties and methods of a 4th class GameCharacter:
(function() {
//Person
function Person(name) {
this.name = name;
this.helloString = "Hello my name is "
}
Person.prototype.name = "Bob";
Person.prototype.hello = function() {
return this.helloString + this.name;
};
//Student
function Student(name, books) {
Person.call(this, name);
this.books = books;
}
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;
Student.prototype.books = ["math","reading"];
//Comedian
function Comedian(name) {
Person.call(this,name);
};
Comedian.prototype = Object.create(Person.prototype);
Comedian.prototype.constructor = Comedian;
Comedian.prototype.hello = function() {
return "I don't know what my parents where thinking when they name me Squat, just kidding, my name is " + this.name;
};
//GameCharacter
function GameCharacter(power) {
this.power = power;
};
GameCharacter.prototype = new Object();
GameCharacter.prototype.constructor = GameCharacter;
GameCharacter.prototype.gainPower = function(power) {
this.power += ", "+power;
};
GameCharacter.prototype.statePower = function() {
return this.power;
};
//GradStudent
function GradStudent(name, books, degree) {
Comedian.call(this, name);
Student.call(this,name,books);
GameCharacter.call(this, "jumping");
this.degree = degree;
this.gainPower("flying");
}
GradStudent.prototype = Object.create(Student.prototype);
Object.assign(GradStudent.prototype, Comedian.prototype, GameCharacter.prototype);
GradStudent.prototype.constructor = GradStudent;
var gradStudent = new GradStudent("Bill",["C", "C++", "JavaScript"], "B.S.");
console.log(gradStudent.hello() + " I have a " + gradStudent.degree +" I am studying " + gradStudent.books.toString() + ". \n In a game I play my power's are "+ gradStudent.statePower() + ". \n Is gradStudent also a Student? " + (gradStudent instanceof Student) + "" );
var otherStudent = new Student("Jennifer" ,["english", "science"]);
console.log(gradStudent.books.toString() + " " + otherStudent.books.toString());
})();
GradStudent is an instance of Student, it's a type of Student, and can also do all the things Comedian and GameCharacter does. The value of Object.assign is that kind of multiple inheritance.
I can accomplish such a thing with the following:
function Student(name) {
Object.setPrototypeOf(this, new Person(name));
this.books = [];
}
However, I'm not familiar enough with javascript to know what possible problems might arise with this solution. Coming from other OO style languages, it feels weird for the prototype of mario to be an actual instance of a Person, but I suppose everything in js is an instance, in some sense, so this might just be bias on my part.

javascript constructor function not giving correct result

i am a newbie to js.
i am trying to use constructor function to create an object.
here is my code
function player(name,age,rank)
{
this.name=name;
this.age=age;
this.rank=rank;
this.sayEverything=function()
{
return "The name of the player is " + this.name + "the age is " + this.age + "the rank is " + this.rank;
}
Now i am adding a new property like this
player.matchReady=true;
now i create an object like this
var kaka=new player("kaka",22,3,false);
And when i write this
document.write('kaka is match ready-->' + kaka.matchReady);
it gives me this output
kaka is match ready-->undefined
Why is it giving me undefined??
haven't i added a new property correctly??Please tell me.
Thanks.
Instead of player.matchReady=true;
Do, player.prototype.matchReady = true;
This way all players will have match ready default on true;
also you might want to put your function into the prototype.
player.prototype.sayEverything=function()
{
return "The name of the player is " + this.name + "the age is " + this.age + "the rank is " + this.rank;
}
You can regard prototype as the scaffolding on which you outline all properties and functions an object should have when it's instantiated. All these default values will be the same for all objects.
When you add functions within functions all these functions get duplicated in memory when you instantiate a new object.
When possible and when there is no need for scoping, try to add generic functions like your sayEverything()(please rename that to toString() to keep in line with convention) to the prototype.
That way all the player objects can use the same function. Which is more memory efficient.
You cannot add a property to a class. You can always add the property as its prototype.
like this:
function player(name, age, rank) {
this.name = name;
this.age = age;
this.rank = rank;
this.sayEverything = function () {
return "The name of the player is " + this.name + "the age is " + this.age + "the rank is " + this.rank;
}
}
player.prototype.matchReady = true;
var kaka = new player("kaka", 22, 3, false);
alert('kaka is match ready-->' + kaka.matchReady);
working example: jsfiddle
Blog on prototype
If you add it to the prototype, all player will have the field.
player.prototype.matchReady = true;
If you only want a specific player to have the field, add it to that player variable:
var kaka = new player("kaka",22,3,false);
kaka.matchReady = true;// kaka has to come first
In the below example you can see what is private ,public,static and privileged variable or method .When ever you write property on Method itself like static variable,that variable wont be available for the instances.
Also whenever you are writing constructor function you should follow the Naming convention to help you differentiate from other function
/ Constructor
function Player(name) {
// Private
var dob= "17/04/1986";
// Privileged
this.getDOB = function () {
return dob;
};
// Public
this.name = name;
}
// Public
Player.prototype.getName = function () {
return this.name;
};
// Static property
Player.town = "South Park";

How can I make inheritance without third object shim?

I try to understand OOP in JavaScript.
I want to create object Person and Worker. Worker inherits Person. I wrote code:
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.grow = function () {
this.age++;
console.log('Person grows, new age ' + this.age);
};
function Worker(name, age, position) {
// How to call parrent constructor Person?
this.position = position;
}
Worker.prototype = Person.prototype;
Worker.constructor = Worker.prototype.constructor;
Worker.prototype.promote = function () {
console.log('Worker ' + this.name + ' became Senior ' + this.position);
};
Worker.prototype.grow = function () {
this.promote();
// How to call parrent method grow?
};
var workerObj = new Worker('Ben', 39, 'engineer');
workerObj.grow();
But in JS variable assignment works by reference and expression Worker.prototype = Person.prototype; doesn't get result and method grow in Worker overrides method grow in Person and I will not be able to get access to parent method.
I know that I need to use third object. But is there way to inherit without third object?
Setting the functions' .prototype properties to the same object essentially makes them the same class, as you've noticed. What you really need, is for Person.prototype to be an object that inherits from Worker.prototype. But you need to do this without calling the Person constructor, since that leave some side effects back in the prototype chain (they aren't significant in the case you mention, but they could be significant in other cases). So Worker.prototype = new Person(); isn't an ideal solution for you.
Object.create() works for this. Among other things, this function can be used to create an object that inherits from another, without calling any constructors. For the situation you're talking about, it would look like this:
Worker.prototype = Object.create(Person.prototype);
Worker.prototype.constructor = Worker;
Object.create doesn't work in older versions of IE, and a total polyfill isn't available due to engine limitations. But there are polyfills for Object.create which work well enough to enable this kind of subclassing, so browser support need not be an issue.
I typically wrap this up in a function, so that once I've defined my subclass and superclass, I can express the relation without much extra rigamarole. You could do that like this:
Object.subclass = function (sub, sup) {
sub.prototype = Object.create(sup.prototype);
sub.prototype.constructor = sub;
}
Object.subclass(Worker, Person); // "class Worker extends Person"
I make inheritance in javascript like this :
var c_Parent = function () {
};
var c_Child = function () {
c_Parent .call(this);
};
c_Child.prototype = new c_Parent();
c_Child.prototype.constructor = c_Child;
So in you case :
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.grow = function () {
this.age++;
console.log('Person grows, new age ' + this.age);
};
function Worker(name, age, position) {
this.position = position;
Person.call(this, name, age);
}
Worker.prototype = new Person();
Worker.prototype.constructor = Worker;
Worker.prototype.promote = function () {
console.log('Worker ' + this.name + ' became Senior ' + this.position);
};
Worker.prototype.grow = function () {
this.promote();
Person.prototype.grow.call(this);
};
var workerObj = new Worker('Ben', 39, 'engineer');
workerObj.grow();

What am I doing wrong when combining objects with the module pattern

This Possible duplicate did not help me, I failed on an interview because of a similar question.
The idea is to create a person Object that is a father of teacher and grandfather of Manager using module pattern and inheritance.
Something like that Manager->Teacher->Person
My code looks like that(My Plunk):
(function(undef)
{
/**Waiting till document is ready before applying next functions*/
$(document).ready(function(){
var person = new APP.Person('Aria Stark','223232');
document.write(person.getDetails());
})();
var APP = {};
APP.Person =(function() {
function Person(name, ID) {
this.name = name;
this.ID = ID;
}
Person.prototype.getDetails = function() {
return " name: " + this.name + " ID: " + this.ID;
};
return Person;
});
APP.Teacher =(function () {
function Teacher(name, ID, salary, hatColor) {
APP.Person.call(this, name, ID);
this.salary = salary;
this.hatColor = hatColor;
}
Teacher.prototype = new APP.Person();
Teacher.prototype.getDetails = function() {
return APP.Person.call(this) + " Salary: " + this.salary + " Hat: " + this.hatColor;
};
return Teacher;
});
APP.Manager =(function () {
function Manager(name, ID, salary, hatColor, car) {
APP.Teacher.call(this, name, ID, salary, hatColor);
this.car = car;
}
Manager.prototype = new APP.Teacher();
Manager.prototype.getDetails = function() {
return APP.Teacher.call(this) + " Car: " + this.car;
};
return Manager;
});
})();
I get an error on the first line:
var person = new APP.Person('Aria Stark','22323');
The error is: Uncaught TypeError: object is not a function
Can someone help me with with that? I'm also open to hear other improvements to this code.
This is how you create (and call) a self-executing function or IIFE:
(function () {})();
Simply writing (function () {}) does not call the function, it actually has no real effect in this case. With your way APP.Person will be a function, that returns another function (the constructor for Person) when called - it will not operate well with new.
Also, for the documentready, you don't want to execute the result of the .ready call, just pass the function as a parameter, it will be called when the event triggers:
$(document).ready(function(){
}); //removed () from here
Plunk with these changes
All your objects are declared like this:
APP.X=(function() {
function Y() {}
Y.prototype.method= function() {};
return Y;
});
That is not wrong in itself, though it is a bit odd. What you want to have is this:
APP.X=(function() {
function X() {}
X.prototype.method= function() {};
return X;
})(); // actually call the anonymous function you used to encapsulate variables
Then again, why do you bother with an IIFE? You might just as well do this:
APP.X = function () {}
X.prototype.method= function() {};
Encapsulating them brings absolutely nothing, there is nothing private you are hiding from the outer scope.
Also, my post might be better suited for CodeReview than StackOverflow, but your inheritance model has significant issues. Your Teacher.prototype is an instance of Person created with no parameters. Only under highly restrictive circumstances will that be safe.
A better model would be this one:
Teacher = function(){
Person.call(this /*, person parameters*/);
}
Teacher.prototype = Object.create(Person.prototype);
There are many good answers on SO dealing with this specific issue, here is one from me.
There is no need of jQuery to create these things. Well, I have not very good exposer on this, but I tried to show the things you want to know:
// Creating Person Class
var Person = function(name, id){
this.name = name;
this.id = id;
};
Person.prototype.getInfo = function(){
return "name: " + this.name + ", id: " + this.id;
};
// Instance of Person
var x = new Person("Ashish", 1);
x.getInfo();
// Creating Teacher Class
var Teacher = function(name, id, salary, hatColor){
Person.call(this, name, id);
this.salary = salary;
this.hatColor = hatColor;
};
// Inheriting Persons methods
Teacher.prototype = new Person();
// Adding new method to it
Teacher.prototype.getFullDetails = function(){
return this.getInfo() + ", salary: " + this.salary + ", Hatcolor: " + this.hatColor;
}
// Instance of Teacher Class
var teacher = new Teacher("John", 2, 15000, "red");
teacher.getInfo(); //output: "name: John, id: 2"
teacher.getFullDetails(); // output : "name: John, id: 2, salary: 15000, Hatcolor: red"
console.log(teacher.salary); // output : 15000
So, above you can see:
- A Person class is created with 2 properties and one method.
- and then we created a Teacher class and inherited the method from Person class in it.
- and then added another method called getFullDetails() in it which accesses the method coming from Person class.
And this is what you are doing in the DOM.ready:
alert(x.getInfo()); // in my example:
In your example:
var APP = {};
APP.Person = function Person(name, ID) {
this.name = name;
this.ID = ID;
}
APP.Person.prototype.getDetails = function () {
return " name: " + this.name + " ID: " + this.ID;
};
var person = new APP.Person('Aria Stark', '223232');
alert(person.getDetails());

Javascript inheritance question

Why Version 2 in the code below does not produce the same result as Version 1 ?
function person(name) {
this.name = name;
}
function student(id, name) {
this.id = id;
// Version 1
//this.inherit_from_person = person;
//this.inherit_from_person(name);
// Version 2
person(name);
}
s = new student(5, 'Misha');
document.write(s.name); // Version 1 => Misha
// Version 2 => undefined
Live demo here.
When you call person(name) it gets called with this bound to the global object, so that's just setting window.name = "Misha". You want person.call(this, name) to explicitly bind it to the right this.
It looks to me like you are trying to implement prototype inheritance. Below is a classic example, though not much used. Complex inheritance is just not needed in javascript, usually a single instance is all that is required. If multiple instances are required, the module pattern can be used with closures for shared methods and properties and also to provide private and priveliged members.
// Person is the "base class"
function Person(name) {
this.setName(name);
}
// Use setters and getters so properties are
// added appropriately.
Person.prototype.setName = function(name) {
this.name = name;
}
// Add Person methods
Person.prototype.getName = function() {
return this.name;
}
// Student inherits from Person and also has
// its own methods
function Student(name, id) {
this.setId(id);
this.setName(name);
}
// To inherit from Person, Student.prototype should
// be an instance of Person
Student.prototype = new Person();
// Add Student methods
Student.prototype.setId = function(id) {
this.id = id;
}
Student.prototype.getId = function() {
return this.id;
}
var p0 = new Student('Sally', '1234');
var p1 = new Person('James');
alert('p0\'s id is ' + p0.id + ' and name is: ' + p0.name);
alert('p1\'s name is: ' + p1.name);
alert('Is p0 a student? ' + (p0 instanceof Student));
alert('Is p1 a student? ' + (p1 instanceof Student));
Note that the instanceof operator is not very reliable, but it works fine in the above case. Also all methods and properties are public so easily over written.

Categories

Resources