New to programming...I'm trying to learn about object inheritance in JavaScript.
I'm getting an error for the following code. It says:
TypeError: Cannot find function getName in object [object Object]
Does __proto__ (aka "dunder proto") not work in App Script? How can I set an inheritance to something other than the default "Object" without it?
function onPlay(){
//create an employee constructor
function Emp(last, first){
this.first = first;
this.last = last;
this.getName = function() {return(this.first+this.last);}
}
//create an employee
var emp1 = new Emp("Halpert", "Jim");
//log the employee's name
Logger.log(emp1.getName());
//create a manager constructor
function Mgr(){
this.salary = 100,000;
}
//managers are also employees
Mgr.__proto__ = Emp.prototype;
//create a manager
var mgr1 = new Mgr("Scott", "Michael");
//log the manager's name
Logger.log(mgr1.getName());
}
Rather than:
Mgr.__proto__ = Emp.prototype;
You probably want:
Mgr.prototype = Object.create(Emp);
The __proto__ property is for mutating prototypes, and isn't necessarily available in all JavaScript engines. To set a prototype for your custom object constructor, you want to set the prototype object on the constructor function to an instance of the base class (with Object.create not calling the parent constructor unnecessarily).
Related
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);
}
function Plant() {
this.country = "Mexico"
this.isOrganic = true;
}
function Fruit(fName, fColor) {
this.name = fName;
this.color = fColor;
}
Fruit.prototype = new Plant();
var abanana = new Fruit("Banana", "Yellow")
console.log(abanana.constructor)
So in my code, I was trying to play around with prototype inheritance. Each time I created a new instance of Fruit (var aFruit = new Fruit ()), the new instance’s prototype is assigned the prototype from the Fruit constructor, which is Fruit.prototype.
So why is abanana.constructor
not
[function: Fruit]
but
[function: Plant]?
I thought this was what the constructor method does:
Moreover, all objects that inherit from another object also inherit a constructor property. And this constructor property is simply a property (like any variable) that holds or points to the constructor of the object.
Two problems with that code:
Using new Plant() to create the Fruit.prototype is a sadly-common anti-pattern; instead, use Object.create and call Plant from within Fruit. It doesn't matter a lot in your specific code, but it would matter if you wanted to derive something from Fruit, or if you wanted to make country an argument to Plant.
You need to set constructor on Fruit.prototype if you want it to point to Fruit.
So:
function Plant() {
this.country = "Mexico"
this.isOrganic = true;
}
function Fruit(fName, fColor) {
Plant.call(this); // **
this.name = fName;
this.color = fColor;
}
Fruit.prototype = Object.create(Plant.prototype); // **
Fruit.prototype.constructor = Fruit; // **
Of course, as of ES2015, we have class syntax, which you can use today with a transpiler (or if you only need to support current versions of Chrome and Firefox):
class Plant {
constructor() {
this.country = "Mexico";
this.isOrganic = true;
}
class Fruit extends Plant {
constructor(fName, fColor) {
super();
this.name = fName;
this.color = fColor;
}
}
I thought this was what the constructor method does:
Moreover, all objects that inherit from another object also inherit a constructor property. And this constructor property is simply a property (like any variable) that holds or points to the constructor of the object.
constructor isn't a method, it's a property that refers to the function that the prototype object is related to. JavaScript itself doesn't use constructor for anything at all, but does define that for all functions that have a prototype property, when the function is first created, the object that prototype property points to will have a constructor property pointing back at the function. But since you replace the value of prototype with a reference to a different object, you have to update the constructor property so it points back to the correct function again (if you want to be thorough, which is for the best — even though JavaScript doesn't use it, it doesn't mean that libraries don't use it).
On really old browsers, you may have to shim Object.create. It can't be completely shimmed, but it can be sufficient for the above:
if (!Object.create) {
Object.create = function(p, props) {
if (typeof props !== "undefined") {
throw new Error("The second argument of Object.create cannot be shimmed.");
}
function ctor() { }
ctor.prototype = p;
return new ctor;
};
}
I am learning prototype in JavaScript and this is the code I am trying -
<script>
function employee(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
var trialcoder = new employee('trialcoder', 26, 'M');
//employee.prototype.salary = null;
trialcoder.salary = 19000;
document.write("salary is "+ trialcoder.salary);
</script>
My thoughts- To add another property we need to use prototype like - employee.prototype.salary = null; so on un commenting this line, I was expecting an error but it was not..let me know where I am wrong in the prototype concept.
Code Source - http://www.w3schools.com/jsref/jsref_prototype_math.asp
Your code is correct, because when you called
var trialcoder = new employee('trialcoder', 26, 'M');
You got an object instance of employee and just like any other object you can add properties to your trialcoder object like
trialcoder.salary = 19000;
In this case, the salary property is only available to your trialcoder object and if you make another instance of employee like var another = new employee() you have no salary property in another object, but, if you do something like
function employee(name, age, sex) { //... }
employee.prototype.salary = 19000;
and then make instances like
var anEmp = new employee();
console.log(anEmp.salary); // 19000
Make another instance
var newEmp = new employee();
console.log(newEmp.salary); // 19000
if you want, you can
newEmp.salary = 10000;
console.log(anEmp.salary); // 10000
Which means, when you add a property in the prototype of a constructor (employee) then every object instance can share the same property and after making an instance from the constructor, you can change the property of an instance but this won't effect other instances. Hope it's clear enough now.
Your code is right and you will not receive error because using prototype your setting property salary of class employee and after creating an object of your class ur are setting the property for that specific object,if you create another object you can set its property salary too
If you set property using prototype then all objects of that class will share that (salary) property .
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.
Quite recently I read about JavaScript call usage in MDC
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/call
one linke of the example shown below, I still don't understand.
Why are they using inheritance here like this
Prod_dept.prototype = new Product();
is this necessary? Because there is a call to the super-constructor in
Prod_dept()
anyway, like this
Product.call
is this just out of common behaviour? When is it better to use call for the super-constructor or use the prototype chain?
function Product(name, value){
this.name = name;
if(value >= 1000)
this.value = 999;
else
this.value = value;
}
function Prod_dept(name, value, dept){
this.dept = dept;
Product.call(this, name, value);
}
Prod_dept.prototype = new Product();
// since 5 is less than 1000, value is set
cheese = new Prod_dept("feta", 5, "food");
// since 5000 is above 1000, value will be 999
car = new Prod_dept("honda", 5000, "auto");
Thanks for making things clearer
The answer to the real question is that you need to do both:
Setting the prototype to an instance of the parent initializes the prototype chain (inheritance), this is done only once (since the prototype object is shared).
Calling the parent's constructor initializes the object itself, this is done with every instantiation (you can pass different parameters each time you construct it).
Therefore, you should not call the parent's constructor when setting up inheritance. Only when instantiating an object that inherits from another.
Chris Morgan's answer is almost complete, missing a small detail (constructor property). Let me suggest a method to setup inheritance.
function extend(base, sub) {
// Avoid instantiating the base class just to setup inheritance
// Also, do a recursive merge of two prototypes, so we don't overwrite
// the existing prototype, but still maintain the inheritance chain
// Thanks to #ccnokes
var origProto = sub.prototype;
sub.prototype = Object.create(base.prototype);
for (var key in origProto) {
sub.prototype[key] = origProto[key];
}
// The constructor property was set wrong, let's fix it
Object.defineProperty(sub.prototype, 'constructor', {
enumerable: false,
value: sub
});
}
// Let's try this
function Animal(name) {
this.name = name;
}
Animal.prototype = {
sayMyName: function() {
console.log(this.getWordsToSay() + " " + this.name);
},
getWordsToSay: function() {
// Abstract
}
}
function Dog(name) {
// Call the parent's constructor
Animal.call(this, name);
}
Dog.prototype = {
getWordsToSay: function(){
return "Ruff Ruff";
}
}
// Setup the prototype chain the right way
extend(Animal, Dog);
// Here is where the Dog (and Animal) constructors are called
var dog = new Dog("Lassie");
dog.sayMyName(); // Outputs Ruff Ruff Lassie
console.log(dog instanceof Animal); // true
console.log(dog.constructor); // Dog
See my blog post for even further syntactic sugar when creating classes. http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html
Technique copied from Ext-JS and http://www.uselesspickles.com/class_library/ and a comment from https://stackoverflow.com/users/1397311/ccnokes
The ideal way to do it is to not do Prod_dept.prototype = new Product();, because this calls the Product constructor. So the ideal way is to clone it except for the constructor, something like this:
function Product(...) {
...
}
var tmp = function(){};
tmp.prototype = Product.prototype;
function Prod_dept(...) {
Product.call(this, ...);
}
Prod_dept.prototype = new tmp();
Prod_dept.prototype.constructor = Prod_dept;
Then the super constructor is called at construction time, which is what you want, because then you can pass the parameters, too.
If you look at things like the Google Closure Library you'll see that's how they do it.
If you have done Object Oriented Programming in JavaScript, you will know that you can create a class as follows:
Person = function(id, name, age){
this.id = id;
this.name = name;
this.age = age;
alert('A new person has been accepted');
}
So far our class person only has two properties and we are going to give it some methods. A clean way of doing this is
to use its 'prototype' object.
Starting from JavaScript 1.1, the prototype object was introduced in JavaScript. This is a built in object that
simplifies the process of adding custom properties and methods to all instances of an object.
Let's add 2 methods to our class using its 'prototype' object as follows:
Person.prototype = {
/** wake person up */
wake_up: function() {
alert('I am awake');
},
/** retrieve person's age */
get_age: function() {
return this.age;
}
}
Now we have defined our class Person. What if we wanted to define another class called Manager which inherits some properties from Person. There is no point redefining all this properties again when we define our Manager class, we can just set it to inherit from the class Person.
JavaScript doesn't have built in inheritance but we can use a technique to implement inheritance as follows:
Inheritance_Manager = {};//We create an inheritance manager class (the name is arbitrary)
Now let's give our inheritance class a method called extend which takes the baseClass and subClassas arguments.
Within the extend method, we will create an inner class called inheritance function inheritance() { }. The reason why we are using this inner
class is to avoid confusion between the baseClass and subClass prototypes.
Next we make the prototype of our inheritance class point to the baseClass prototype as with the following code:
inheritance.prototype = baseClass. prototype;
Then we copy the inheritance prototype into the subClass prototype as follows: subClass.prototype = new inheritance();
The next thing is to specify the constructor for our subClass as follows: subClass.prototype.constructor = subClass;
Once finished with our subClass prototyping, we can specify the next two lines of code to set some base class pointers.
subClass.baseConstructor = baseClass;
subClass.superClass = baseClass.prototype;
Here is the full code for our extend function:
Inheritance_Manager.extend = function(subClass, baseClass) {
function inheritance() { }
inheritance.prototype = baseClass.prototype;
subClass.prototype = new inheritance();
subClass.prototype.constructor = subClass;
subClass.baseConstructor = baseClass;
subClass.superClass = baseClass.prototype;
}
Now that we have implemented our inheritance, we can start using it to extend our classes. In this case we are going to
extend our Person class into a Manager class as follows:
We define the Manager class
Manager = function(id, name, age, salary) {
Person.baseConstructor.call(this, id, name, age);
this.salary = salary;
alert('A manager has been registered.');
}
we make it inherit form Person
Inheritance_Manager.extend(Manager, Person);
If you noticed, we have just called the extend method of our Inheritance_Manager class and passed the subClass Manager in our case and then the baseClass Person. Note that the order is very important here. If you swap them, the inheritance
will not work as you intended if at all.
Also note that you will need to specify this inheritance before you can actually define our subClass.
Now let us define our subClass:
We can add more methods as the one below. Our Manager class will always have the methods and properties defined in the Person class because it inherits from it.
Manager.prototype.lead = function(){
alert('I am a good leader');
}
Now to test it let us create two objects, one from the class Person and one from the inherited class Manager:
var p = new Person(1, 'Joe Tester', 26);
var pm = new Manager(1, 'Joe Tester', 26, '20.000');
Feel free to get full code and more comments at:
http://www.cyberminds.co.uk/blog/articles/how-to-implement-javascript-inheritance.aspx