How to access the parent class properties from a subclass? - javascript

I have a question about Javascript objects. How can I access the properties of the parent class?
function randomObj() // for example button obj
{
this.text = "this is obj";
}
function parentClass()
{
this.name = "parent";
this.subObj;
}
parentClass.prototype.generate = function()
{
this.subObj = new randomObj();
this.subObj.changeParentClassName = function() // button obj wants to change name
{
this.name = "not parent";
}
}
var sampleObj = new parentClass();
sampleObj.generate();
sampleObj.subObj.changeParentClassName (); // does not works
It seems 'this' in 'changeParentClassName' is subObj, how can I access parentclass.name?

JavaScript's this will be the object to the left of the . when calling the function. In this case, it is the subObj not the parentObj so you are setting name on subObj. You have 2 options, you can put this in a different variable inside generate so it doesn't get replaced by JavaScript's this logic. Something like:
var parentObj = this;
this.subObj.changeParentClassName = function() // button obj wants to change name
{
parentObj.name = "not parent";
};
Or you can use the bind() to create a new function that will have this bound to a known object (in this case your parent object) Something like:
this.subObj.changeParentClassName = (function() // button obj wants to change name
{
this.name = "not parent";
}).bind(this); // bind the 'this' inside the changeParentClassName to the 'this' inside generate
Check out Function bind() for more info on bind and interactive examples.
Note, if you are targeting a recent version of Javascript (ECMAScript 6 or later), you can use a => function which does not change the value of this compared to the declaring scope. So you could use:
this.subObj.changeParentClassName = () => // button obj wants to change name
{
this.name = "not parent";
};

Related

Difference between object in JavaScript

Im doing a course in frontend Dev in uni and the teacher insists on us using a old book so to learn the history and basics of JavaScript before we move on to more advanced and recent implementations.
Now in this book we are instructed to code a webpage for a food truck and it is supposed to take orders.
Now in some scripts the objects are defined like this :
function DataStore() {
this.data = {};
}
Here the data object is defined using the keyword "this" as in saying it belongs to the function object DataStore.
however in some scripts the data object is defined as:
FormHandler.prototype.addSubmitHandler = function() {
console.log('Setting submit handler for form');
this.$formElement.on('submit', function(event){
event.preventDefault();
var data = {};
My question is what is the difference in the two data objects?
Short answer is at the bottom
Long and boring introduction to how things work
When you write this :
function SomeThing() { }
You can always do
let a = new SomeThing();
even when it doesn't make sense like in :
function lel() { console.log('lelelel'); }
let g = new lel();
console.log(g);
console.log(g.constructor.name);
What this means is that classes are actually the same as functions. And a function in which you use the keyword this usually means you will want to create instances of it.
now if I want all instances of my lel() function class to have a property called foo and a method called bar here's how you do :
lel.prototype.foo = "Some initial value";
lel.prototype.bar = function() {
console.log(this.foo);
}
now I can do
let g = new lel();
lel.bar();
lel.foo = "Hell yeah !";
lel.bar();
In conclusion, this :
function SomeThing() {
this.data = {};
}
SomeThing.prototype.setData = function(key, value) {
this.data[key] = value;
}
SomeThing.prototype.getDataKeys = function() {
return Object.keys(this.data);
}
SomeThing.prototype.getDataValues = function() {
return Object.values(this.data);
}
is the same thing as this
class SomeThing {
constructor() {
this.data = {};
}
setData(key, value) {
this.data[key] = value;
}
getDataKeys() {
return Object.keys(this.data);
}
getDataValues() {
return Object.values(this.data);
}
}
Clarifications about your question
If somewhere in your code you have :
FormHandler.prototype.addSubmitHandler = function() {
console.log('Setting submit handler for form');
this.$formElement.on('submit', function(event){
event.preventDefault();
var data = {};
if necessarily means that somewhere else in your code you have
function FormHandler(...) { ... }
Short answer
This :
function DataStore() {
this.data = {};
}
is how you define a class named DataStore with a property called data initialized to the value {}
And this :
FormHandler.prototype.addSubmitHandler = function() {
...
var data = {};
}
is how you add a method called addSubmitHandler to the already defined class FormHandler. That method uses a local variable called data, could have been any other name
In the first case, data is a property of the object that is created like this: new DataStore.
You can access this property like this:
var obj = new DataStore();
obj.data // => {}
/* or */
obj['data'] // => {}
In the second case, data is just a global variable, inside of an event handler, that is added executing the function.
var obj = new FormHandler();
obj.addSubmitHandler();
You access this variable like this:
data // => {}
I don't think it's a good idea to learn old JS. You would be out of date. You wouldn't be able to use latest technologies, and it would be harder to get a job.

Is it possible to run object method using Object's ID?

Object with method created by Object Constructor:
function objectexample(name) {
this.name = name;
this.create = function(){
var obj = document.createElement('div');
obj.id = this.name;
parent = document.getElementsByTagName("body")[0];
parent.appendChild(obj);
}
this.showalert = function(){
alert("alert");
}
}
And now I create object:
var obj1 = new objectexample("new1");
How to run method .create for this object, but not using variable obj1, I want to get Object using ID, for example:
document.getElementById("new1").showalert();
Is it possible?
Basically, yes, it is possible
However, you'll need the element to contain a reference to the object that created it.
In the demo below:
When constructing the new obj1, we define 3 properties:
Its name.
A create() method that when called creates an element.
A showAlert() method that when called outputs some data.
When calling showAlert() before calling create(), we get whatever data is available about the object, but nothing about the as yet uncreated element.
When calling create() we create the element, and define creation as a property of the object, with the element as its value.
We then define creator as a property of the element, with the value of this (the object that created the element).
Now the object (creator) has a child element called creation, and the element has a creator and all the properties it has, including its methods.
In other words, if the new object gives birth to an element, the element adopts its creator's properties, and the creator keeps a tight hold of its child's hand.
function ObjectExample( name ) {
this.name = name;
this.create = function() {
this.creation = document.createElement( "div" );
this.creation.id = name;
this.creation.creator = this;
document.body.appendChild( this.creation );
}
this.showAlert = function() {
// alert( "Alert!" ); // simpler for demo to use console
console.log( this.name );
console.log( this.creation );
return this.creation;
}
}
let obj1 = new ObjectExample( "new1" );
if ( !obj1.showAlert() ) {
obj1.create();
}
document.getElementById( "new1" ).creator.showAlert();
What you're talking about is a variable name, not an object id.
document.getElementById has nothing to do with Javascript variable names, but rather is used for selecting elements from an HTML document by their id. However, it is possible to do this in several different ways depending on your use case.
One way could be to use a global/neatly scoped object in which you would modify every time the constructor is called.
let objects = {}; // create your global object
function objectexample(name) {
this.name = name;
// append this to global object
objects[name] = this;
this.create = function(){
var obj = document.createElement('div');
obj.id = this.name;
parent = document.getElementsByTagName("body")[0];
parent.appendChild(obj);
}
this.showalert = function(){
alert("alert");
}
}
new objectexample("new1");
console.log(objects.new1)
console.log(objects["new1"]) // alternatively method

Does anyone know why the output is "Obama" not "Clinton"?

function setName(obj){
obj.name = "Obama";
obj = {name:"Clinton"};
}
var president = {name:"Bush"};
setName(president);
console.log(president.name);
When I change “obj.name = "Obama";” to “this.name = "Obama";”
function setName(obj){
this.name = "Obama";
obj = {name:"Clinton"};
}
var president = {name:"Bush"};
setName(president);
console.log(president.name);
The output becomes "Bush".
this is not the obj.
You can try this to understand:
function setName(obj){
console.log(this.name);
}
It will not give you obj.
Well if you really think bad about using the obj word try this:
function setName(obj){
setName.arguments[0].name = "Obama";
obj = {name:"Clinton"}; // I don't touch this.
}
I added some comments to help understand what is happening.
function setName(obj){
// change obj's name property to Obama
obj.name = "Obama";
// change the reference to obj to a new object inside setName.
// this does not affect the original object being passed in.
obj = {name:"Clinton"};
}
var president = {name:"Bush"};
setName(president);
console.log(president.name);
function setName2(obj){
// change this's name property to Obama. this is set to window/global, not obj.
this.name = "Obama";
// change the reference to obj to a new object inside setName.
// this does not affect the original object being passed in.
obj = {name:"Clinton"};
}
var president2 = {name:"Bush"};
setName2(president2);
console.log(president2.name);
You are replacing the local variable obj, the scope of which is inside the function. It is no more than a reference to the object. Thus the update obj = { name: "Clinton" }; does not affect any state outside the function.
But changing the object's name affects its contents. This is why you are getting "Obama".
this.name = "Obama" has no relevant effect on president, since this is not the president.
You are modifying an object reference and not the object itself.
This line is modifying the initial object. Obj is currently pointing to the initial object which is the same as the Object that president is pointing to.
obj.name = "Obama";
The next line assigns the variable to a new object reference. It no longer refers to the initial object. The variable president is still pointing at the initial object and thus you get "Obama" and not "Bush"
obj = {name:"Clinton"};
In the first case:
When invoking setName with the president object, it first sets the name of the object to Obama. Since you passed an object as a parameter, all properties that change, will be changed to the initial object as well. When overriding the entire object obj = {name:"Clinton"};, you lose the reference and you don't return the object, so nothing happens with it. The name is set to Obama in the first step and it will stay Obama.
In the second case:
Same as above and the this-context is related to the setName scope. You're not using setName as an Object or it's not part of an Object, so there's not really a usable this-context here. You could attach one by using call:
setName.call(president, null);
The first argument is the this-context and the other arguments are the parameters of the method. However, I would not recommend doing that for this scenario.
setName used on an Object:
To use a method setName on an object, you could do this for example:
function President(name) {
this.name = name;
}
President.prototype.setName = function(name) {
this.name = name;
}
var president = new President('Clinton');
president.setName('Obama');
Since you're using new, you create a new this-context and set the name property to Clinton while creating the Object.
Also, this could work:
function President(name) {
var presidentName = name;
return {
getName: function() {
return presidentName;
},
setName: function(name) {
presidentName = name;
}
};
}

Accessing properties in parent class

I am trying to make a parent data access layer class that is inherited by multiple classes.
parent class:
var DataAccess = function() {
this.Save = function(){
alert(this.ListName); //works
SaveLogic(this.Id); //doesnt work
}
}
Child Class:
var Job = function(){
Job.prototype.ListName = 'MyList'; //works
this.Save = function(){
Job.prototype.Save().call(this);
//specific Job Save logic
}
}
Job.prototype = new DataAccess();
Now in my main class:
var aJob = new Job();
aJob.Id = 1;
aJob.Save(); //Does not work. Prototype can not see aJob.Id..
As you can see, I need to create a parent function with shared variables such as ID, so when I inherit the parent class, I can assign values to these variables so the shared logic of hte parents class work, then my extended class's can have specific logic
You can start with construction like this:
var DataAccess = function() {
this.Save = function(){
console.log('DataAccess Save call', this.ListName, this.Id);
}
}
var Job = function(){
this.ListName = 'MyList';
}
Job.prototype = new DataAccess();
/**
* Delete me to use parent's Save method.
*/
Job.prototype.Save = function(){
console.log('Job Save call', this.ListName, this.Id);
}
var aJob = new Job();
aJob.Id = 1;
aJob.Save();
#stivlo described how it works in his answer here: https://stackoverflow.com/a/4778408/1127848
The problem I had was I wanted to reuse the same code. I think I have worked it out this way, im still not 100% its the right way to go with prototype programming :
function DataAccess() {
//setup common variables
}
DataAccess._Save_(listname, id){
commonSaveLogic(id);
doStuff(listname);
}
function Job() {
this.ListName = 'Jobs';
DataAccess.call(this); //call DataAccess Constructor
}
Job.prototype = DataAccess;
Job.prototype.constructor = Job;
Job.ProtoType.Save = function(){
this._Save_(this.ListName, this.Id);
}
function AotherList() {
this.ListName = 'AnotherList';
DataAccess.call(this);
}
//same as above. Job and Another list both inherit off DataAccess.
Dont use .prototype inside the constructor. We define .prototype for sharing same copy to all objects.
You are missing here many things. I'm explaining one by one:
First : SaveLogic(this.Id); //doesnt work
Because You don't use this with the function so it's a global function not a constructor function. And you don't have defined it any where so there will be an error like function SaveLogic not defined
To prevent this error, define the function somewhere.
Second : You have passed this.Id as a parameter. Id using the line aJob.Id = 1; will not be accessible within the SaveLogic(this.Id); because Id is a property of aJob not of ajob.prototype. this.ListName will be available here because it's a property of prototype.
So it you want to get Id inside SaveLogic() function, define it as prototype property.
Third : when this line aJob.Save(); will be invoke it will call
this.Save = function(){
Job.prototype.Save().call(this);
//specific Job Save logic
}
Job.prototype.Save() will search for a function named as Save(). Which is not defined in Job's prototype so function not defined error will occur.
Fourth : call() can not be called anyhow excepts either DataAccess.call() or Job.call();
call() is just like the constructor call excepts it's first parameter get assigned to the constructor's this object.
Here i have improved your code. Just copy and paste it in your editor and see what is going here.
Try this :
function SaveLogic(Id)
{
alert(Id);
}
var DataAccess = function() {
this.Save = function(){
alert(this.ListName); //works
SaveLogic(this.Id);
return this; //doesnt work
}
this.call = function() {
alert('call is called here');
}
}
var Job = function(){
Job.prototype.ListName = 'MyList'; //works
this.Save = function(){
//console.log(Job.prototype.Save());
Job.prototype.Save().call(this);
//specific Job Save logic
}
}
Job.prototype = new DataAccess();
var aJob = new Job();
Job.prototype.Id = 1;
aJob.Save(); //Does not work. Prototype can not see aJob.Id..

What does 'var that = this;' mean in JavaScript?

In a JavaScript file I saw:
function Somefunction(){
var that = this;
...
}
What is the purpose of declaring that and assigning this this to it?
I'm going to begin this answer with an illustration:
var colours = ['red', 'green', 'blue'];
document.getElementById('element').addEventListener('click', function() {
// this is a reference to the element clicked on
var that = this;
colours.forEach(function() {
// this is undefined
// that is a reference to the element clicked on
});
});
My answer originally demonstrated this with jQuery, which is only very slightly different:
$('#element').click(function(){
// this is a reference to the element clicked on
var that = this;
$('.elements').each(function(){
// this is a reference to the current element in the loop
// that is still a reference to the element clicked on
});
});
Because this frequently changes when you change the scope by calling a new function, you can't access the original value by using it. Aliasing it to that allows you still to access the original value of this.
Personally, I dislike the use of that as the alias. It is rarely obvious what it is referring to, especially if the functions are longer than a couple of lines. I always use a more descriptive alias. In my examples above, I'd probably use clickedEl.
From Crockford
By convention, we make a private that
variable. This is used to make the
object available to the private
methods. This is a workaround for an
error in the ECMAScript Language
Specification which causes this to be
set incorrectly for inner functions.
JS Fiddle
function usesThis(name) {
this.myName = name;
function returnMe() {
return this; //scope is lost because of the inner function
}
return {
returnMe : returnMe
}
}
function usesThat(name) {
var that = this;
this.myName = name;
function returnMe() {
return that; //scope is baked in with 'that' to the "class"
}
return {
returnMe : returnMe
}
}
var usesthat = new usesThat('Dave');
var usesthis = new usesThis('John');
alert("UsesThat thinks it's called " + usesthat.returnMe().myName + '\r\n' +
"UsesThis thinks it's called " + usesthis.returnMe().myName);
This alerts...
UsesThat thinks it's called Dave
UsesThis thinks it's called undefined
This is a hack to make inner functions (functions defined inside other functions) work more like they should. In javascript when you define one function inside another this automatically gets set to the global scope. This can be confusing because you expect this to have the same value as in the outer function.
var car = {};
car.starter = {};
car.start = function(){
var that = this;
// you can access car.starter inside this method with 'this'
this.starter.active = false;
var activateStarter = function(){
// 'this' now points to the global scope
// 'this.starter' is undefined, so we use 'that' instead.
that.starter.active = true;
// you could also use car.starter, but using 'that' gives
// us more consistency and flexibility
};
activateStarter();
};
This is specifically a problem when you create a function as a method of an object (like car.start in the example) then create a function inside that method (like activateStarter). In the top level method this points to the object it is a method of (in this case, car) but in the inner function this now points to the global scope. This is a pain.
Creating a variable to use by convention in both scopes is a solution for this very general problem with javascript (though it's useful in jquery functions, too). This is why the very general sounding name that is used. It's an easily recognizable convention for overcoming a shortcoming in the language.
Like El Ronnoco hints at Douglas Crockford thinks this is a good idea.
The use of that is not really necessary if you make a workaround with the use of call() or apply():
var car = {};
car.starter = {};
car.start = function(){
this.starter.active = false;
var activateStarter = function(){
// 'this' now points to our main object
this.starter.active = true;
};
activateStarter.apply(this);
};
Sometimes this can refer to another scope and refer to something else, for example suppose you want to call a constructor method inside a DOM event, in this case this will refer to the DOM element not the created object.
HTML
<button id="button">Alert Name</button>
JS
var Person = function(name) {
this.name = name;
var that = this;
this.sayHi = function() {
alert(that.name);
};
};
var ahmad = new Person('Ahmad');
var element = document.getElementById('button');
element.addEventListener('click', ahmad.sayHi); // => Ahmad
Demo
The solution above will assing this to that then we can and access the name property inside the sayHi method from that, so this can be called without issues inside the DOM call.
Another solution is to assign an empty that object and add properties and methods to it and then return it. But with this solution you lost the prototype of the constructor.
var Person = function(name) {
var that = {};
that.name = name;
that.sayHi = function() {
alert(that.name);
};
return that;
};
Here is an example
`
$(document).ready(function() {
var lastItem = null;
$(".our-work-group > p > a").click(function(e) {
e.preventDefault();
var item = $(this).html(); //Here value of "this" is ".our-work-group > p > a"
if (item == lastItem) {
lastItem = null;
$('.our-work-single-page').show();
} else {
lastItem = item;
$('.our-work-single-page').each(function() {
var imgAlt = $(this).find('img').attr('alt'); //Here value of "this" is '.our-work-single-page'.
if (imgAlt != item) {
$(this).hide();
} else {
$(this).show();
}
});
}
});
});`
So you can see that value of this is two different values depending on the DOM element you target but when you add "that" to the code above you change the value of "this" you are targeting.
`$(document).ready(function() {
var lastItem = null;
$(".our-work-group > p > a").click(function(e) {
e.preventDefault();
var item = $(this).html(); //Here value of "this" is ".our-work-group > p > a"
if (item == lastItem) {
lastItem = null;
var that = this;
$('.our-work-single-page').show();
} else {
lastItem = item;
$('.our-work-single-page').each(function() {
***$(that).css("background-color", "#ffe700");*** //Here value of "that" is ".our-work-group > p > a"....
var imgAlt = $(this).find('img').attr('alt');
if (imgAlt != item) {
$(this).hide();
} else {
$(this).show();
}
});
}
});
});`
.....$(that).css("background-color", "#ffe700"); //Here value of "that" is ".our-work-group > p > a" because the value of var that = this; so even though we are at "this"= '.our-work-single-page', still we can use "that" to manipulate previous DOM element.

Categories