var People = function()
{
this.FirstName = "John";
this.LastName = "Doer";
}
var Employee = function(o)
{
this.DateHired = "June 30";
this.prototype = o;
}
var obj = new People();
var employee1 = new Employee(obj);
print(employee1.DateHired);
print(employee1.FirstName);
Output:
June 30
I expected the output should be:
June 30
Jonh
but it is not what I expected. So could someone explain me what is wrong with the above code?
You've set a property called prototype on the instance created by new Employee, which doesn't do anything to hook up a prototype chain. The prototype property goes on the function Employee. That property is then used to set the [[Prototype]] internal property of objects created via new Employee.
So assuming you want Employee to be a subclass of People, you'd do it like this:
// The singular is "Person", so I'll use that instead of People
var Person = function() {
this.FirstName = "John";
this.LastName = "Doer";
};
var Employee = function() {
// Give `Person` a chance to do its initialization of the instance
Person.call(this/*, possible, arguments, here*/);
// Now carry on with the `Employee` initialization
this.DateHired = "June 30";
};
// Make Employee a subclass of Person by
// 1. Giving `Employee.prototype` a new object whose [[Prototype]] is
// `Person.prototype`
// 2. Ensuring that `Employee.prototype`'s `constructor` property points
// back to Employee.
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
// Usage
var employee1 = new Employee();
console.log(employee1.DateHired);
console.log(employee1.FirstName);
However, here at the end of 2016, we don't need to play those games anymore: We can use the class syntax of ES2015 (transpiling if we need to deploy the code to older browsers), which handles the plumbing for us:
class Person {
constructor() {
this.FirstName = "John";
this.LastName = "Doer";
}
}
class Employee extends Person {
constructor() {
// Give `Person` its chance to initialize the instance
super();
// Now carry on with the `Employee` initialization
this.DateHired = "June 30";
}
}
// Usage
const employee1 = new Employee();
console.log(employee1.DateHired);
console.log(employee1.FirstName);
Inheritance works as below
var People = function()
{
this.FirstName = "John";
this.LastName = "Doer";
}
var Employee = function()
{
this.DateHired = "June 30";
//this.prototype = o;
People.call(this);
}
Employee.prototype=Object.create(People.prototype);
var employee1 = new Employee();
console.log(employee1.DateHired);
console.log(employee1.FirstName);
When you say:
this.prototype = o;
You are essentially creating a property named "prototype" and giving it a value.
Javascript assumes that you are trying to store values in a variable named "prototype".
If you typed:
print(employee1.prototype.FirstName);
You would get
Output: John
Related
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.
I recently read that using private method is bad because they are very memory inefficient because a new copy of the method would be created for each instance. In the example given, how is dispalyIncreasedSalary more efficient than increaseSalary?
var Employee = function (name, company, salary) {
this.name = name || ""; //Public attribute default value is null
this.company = company || ""; //Public attribute default value is null
this.salary = salary || 5000; //Public attribute default value is null
// Private method
var increaseSalary = function () {
this.salary = this.salary + 1000;
};
// Public method
this.dispalyIncreasedSalary = function() {
increaseSalary();
console.log(this.salary);
};
};
// Create Employee class object
var emp1 = new Employee("John","Pluto",3000);
// Create Employee class object
var emp2 = new Employee("Merry","Pluto",2000);
// Create Employee class object
var emp3 = new Employee("Ren","Pluto",2500);
In the following example is this.dispalyIncreasedSalary reused for all objects?
No. You are binding it to this. So each gets it's own copy of that. That is what an instance member means. They bind to instance and not to Class/Object.
What about this.name etc. properties?
Same.
Aren't the this.propName not copied for all the instances?
If that happens all instance see the same value and that's a big NO.
You are correct that it is wasteful/inefficient to duplicate what could be a shared function for each instance.
You should investigate how JavaScript prototypes work: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes
So shared methods would be placed onto every object and shared like this:
Employee.prototype.dispalyIncreasedSalary = function() {
increaseSalary();
console.log(this.salary);
}
I'd like to get _firstName and _birthDate from : I tried https://jsfiddle.net/0xLqhufd/
var Person = (function () {
function Person(firstName, birthDate) {
this._firstName = firstName;
this._birthDate = birthDate;
}
return Person;
}());
alert(Object.keys(Person.Prototype));
You cannot get an object's properties before creating a new instance.
Object.keys(new Person)
Also for your understanding, you have properties with your current instance not in prototype. At this moment your prototype will be empty and it inherits the Object's, The core one, that holds toString etc. And those are non enumerable, so you cannot get those by using Object.keys().
DEMO
This is factory function. You need to create instances of the class using new.
var Person = (function () {
function Person(firstName, birthDate) {
this._firstName = firstName;
this._birthDate = birthDate;
}
return Person;
}());
var tushar = new Person('Tushar', '15464');
console.log(tushar); // { _firstName: 'Tushar', _birthDate: '15464' }
You need to create a new person:
var newPerson = new Person('Lars', 'Svensson');
console.log(newPerson.firstname);
console.log(newPerson.birthDate);
This will allow you to access it's properties.
So I am designing a grade book interface and I have a course defined as:
<script>
course = new Object();
var name;
var gradingareas;
var finalgrade;
</script>
then later I want to create a new instance:
var gradingareas = new Array("Homework", "Classwork", "Exams");
course1 = new course("CS1500", gradingareas, 85);
I have also tried without the var in front to no avail. I get an "Uncaught TypeError: Object is not a function" I am very new to javascript so I don't even know if Im going about this the correct way. Any help is appreciated Thanks.
Your existing code:
// Creates a new, empty object, as a global
course = new Object();
// Creates three new variables in the global scope.
var name;
var gradingareas;
var finalgrade;
There is no connection between the variables and the object.
It looks like you want something more like:
function Course(name, gradingareas, finalgrade) {
this.name = name;
this.gradingareas = gradingareas;
this.finalgrade = finalgrade;
}
Then:
var course1 = new Course("CS1500", gradingareas, 85);
Note the use of a capital letter for naming the constructor function. This is a convention in the JS community.
JS is prototypical, rather than class based and if you are new to it there are advantages to learning this immediately rather than trying to mush classical inheritance models from it, however, classical inheritance is alive and well in JS.
Anyhow, to answer how you would access your variables:
course1.name works fine with the example above.
If you wanted to privatise your data you could take this approach using closure:
var Course = function(name, grade) {
// Private data
var private = {
name: name,
grade: grade
}
// Expose public API
return {
get: function( prop ) {
if ( private.hasOwnProperty( prop ) ) {
return private[ prop ];
}
}
}
};
Then instantiate a new object:
var course = new Course('Programming with JavaScript', 'A');
and start using all that private data:
course.get('name');
Of course, you'd probably want setters to manipulate that data too ;)
The code that you described does the following:
// Declares a memory variable called course and stores and object in it
var course = new Object();
// Declares three variables
var name;
var gradingareas;
var finalgrade;
These declared variables aren't automatically connected to the object. If you want these properties declared on the object you have 2 options:
Declare them as properties of the object
Declare them on the prototype of of the object
Example1: declare them as properties of the object:
// Declares a memory variable called course and stores and object in it
var course = new Object();
// Access or create new properties with . or [] operator
course.name = 'math';
course.gradingareas = 'muliple';
course['finalgrade'] = 'A'
console.log(course);
Example2: Declare them on the prototype:
// Create a constructor function
function Course (name, grade) {
this.name = name;
this.grade = grade;
}
// course is added on the prototype
Course.prototype.gradingareas = 'some gradingareas';
// the name and the grade are added on the object itself
var course = new Course ('willem', 10);
console.log(course);
To create a very simple object with constructor and default values, you can do :
//My object with constructor
var myObjectWithConstrutorFunction = {
//construtor function with default values in constructor
myConstrutor: function(Name = 'bob', Age = 18){
this.Name = name;
this.Age = age;
}
};
// instance
var myInstance = new myObjectWithConstrutorFunction.myConstrutor();
// show on console
console.log('object with constructor function: ', myInstance);
// show properties
console.log(myInstace.Name, myInstance.Age);
PS : It's a good practice create a constructor's name with the same name of the class, if you are creating a external class.
I've seen a Javascript project where a prototype property is defined like this:
myFunc.prototype.a = new myObject()
I'm wondering what happens when I call new myFunc() to the a property:
Does it return the result of new myObject() or everytime I call myFunc.a it calls new myObject()?
And on different myFunc instances the a property is the same one as it happens for normal prototype properties or every instance's a is different myObject() instance?
See this http://backbonejs.org/docs/todos.html: every TodoList instance will share the same localStorage, so the same Backbone.LocalStorage() instance?
No, all your instances of myObject will have the same __proto__.
If you access a from an object, you'll access the one of the prototype but if you set a on one object, then this object will have whatever a you gave him while the others will keep the old one.
Hopefully, this will help you out:
var Person = function (name, age) {
this.getName = function () { return name; };
this.getAge = function () { return age; };
};
var Employee = function (employee_id) {
this.printBadge = function () {
console.log("#" + employee_id + " | " + this.record.getName());
};
};
Employee.prototype.record = new Person("Bob", 32);
var jim = new Employee(1),
doug = new Employee(2);
jim.printBadge(); // #1 | Bob
doug.printBadge(); // #2 | Bob
The "prefer composition to inheritance" mantra goes quadruple for JavaScript.
You can quite happily override a particular object on a person:
jim.record = { getName : function () { return "Jim"; } };
jim.printBadge(); // #1 | Jim
doug.printBadge(); // #2 | Bob
Just be careful when modifying properties of the prototype object (the object which instances refer to).
var jeff = new Employee(3);
jeff.record.getName = function () { return "OMG! Yuse guys is scr00d!" };
jim.printBadge(); // #1 | Jim
doug.printBadge(); // #2 | OMG! Yuse guys is scr00d!
jeff.printBadge(); // #3 | OMG! Yuse guys is scr00d!
Reason being that you changed a property of the shared, prototype object (static, in other languages), rather than replacing the WHOLE prototype object (referencing a new object, instead of the static object) like in Jim's case.
But the X.prototype.y = new Z(); can be seen like this, simply:
var bob = new Person("Bob", 32);
Employee.prototype.record = bob;
var jim = new Employee(1),
doug = new Employee(2),
jeff = new Employee(3);