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
Related
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;
}
};
}
I'm making my own jQuery-like library for a very specific task. (dont want to use jquery, to be closer to native js).
I need a solution to call class with and without agruments, in my case - certain selector.
What I've ment - class has to work in both ways:
myclass.function();
and:
myclass(selector).function();
Initialization of class looks like this
(function(window){
var myclass = function( selector ){
return new myclass.model.build( selector );
};
myclass.model = myclass.prototype = {
constructor: myclass,
myfunction: function(){
alert("some function's alert");
}
};
myclass.model.build = function( selector ){
if( !selector )
return this;
/* Picking objects by selector */
};
window.myclass = myclass;
return myclass;
})(window);
jsFiddle Demo
There are a few ways to accomplish this. Here is a common way, which is to setup an instance of a local function ("class") that has its prototype configured as an object for extensibility and has properties attached to it as an object as well.
//use window and document shortcut
(function(win,doc){
//setup local function in order to extend
var jakeWeary = function(selector){
//force an instance to be returned when referenced
return new jakeWeary.fun.start(selector);
};
//allow prototype to be extended by referencing fun
jakeWeary.fun = jakeWeary.prototype = {
constructor : jakeWeary,
//use passed values to query
start : function(selector){
//query against present document
var nodes = doc.querySelectorAll(selector);
//mimic an array of matched elements
for(var i = 0; i < nodes.length;i++){
this[i] = nodes[i];
}
//return self for chaining
return this;
}
};
//extend function object in order to be used without calling instance
jakeWeary.div = function(content){
var div = document.createElement("div");
div.innerHTML = content;
return div;
};
//expose
win.jakeWeary = win.jk = jakeWeary;
})(window,document)
//call instance to match the selector `.d`
var $ = jakeWeary('.d');//lets use a fun variable like $ for this
//reference the third matched element, and then append a div created from a function on the
//jakeWeary function object
$[2].appendChild(jk.div("<p>Reinventing the wheel</p>"));
<div id="i">i</div>
<div class="d">d</div>
<div class="d">d</div>
<div class="d">d</div>
You mean you want the non-instance call to generate a default instance and then be applied to it?
var Foo = (function () {
// set up constructor
var Foo = function () {
this.fizz = 'buzz';
};
Foo.prototype = Object.create(null);
// instance version
Foo.prototype.bar = function () {return 'this.fizz is ' + this.fizz;};
// non-instance version
Foo.bar = function () {return Foo.prototype.bar.apply(new Foo(), arguments);};
return Foo;
}());
Foo.bar(); // "this.fizz is buzz"
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..
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";
};
Here is an example:
var Box = function() {
this.id = generateUniqueId();
};
Box.prototype = {
add:function(parent) {
parent.appendChild(this.elm);
}
};
var NewBox = function() {
this.newThing = true;
};
NewBox.prototype = new Box();
NewBox.prototype.remove = function() {
this.elm.parentNode.removeChild(this.elm);
};
var a = new NewBox();
var b = new NewBox();
alert(a.id); // alerts 0
alert(b.id); // also alerts 0! :#
I would like to have a and b (basically each time I create a NewBox) have their own id. I understand that NewBox is using prototypal inheritance and is thus inheriting from a single instance of the generated id that it gets from Box, but I would like it so that each NewBox gets its own id without having to explicitly say that inside the NewBox constructor.
Maybe it's impossible or I'm doing something really wrong, so please help!
Thanks a lot!
In your example, the Box constructor gets executed only when you set the NewBox.prototype object.
You could workaround this by calling the Box constructor function inside NewBox with the Function.prototype.apply method, to set the this value and forward all the argument values, for example:
//..
var NewBox = function() {
Box.apply(this, arguments);
this.newThing = true;
};
//..
var a = new NewBox();
var b = new NewBox();
// assuming your `generateUniqueId` function
// increments a number
alert(a.id); // will alert 1
alert(b.id); // will alert 2
Now, each time the NewBox constructor is called to create a new object instance (new NewBox();), it will call the Box function to apply all its logic on it. This will help you to avoid repeating the logic of the parent constructor over and over.
The apply, is used call the "parent" constructor function setting the this value to the object instance that is being created by the NewBox constructor and we pass all arguments provided to this function.
Your example also shows a common problem, when you express inheritance relationship through NewBox.prototype = new Box(); the Box constructor gets called and it has side effects, this new object will be initialized and your generateUniqueId function will be executed for the first time, if you want to avoid that, you need to either use a temp constructor, just to make a new object that inherits from Box.prototype, or use the new ECMAScript 5 Object.create method for the same purpose, for example:
function inherit(o) {
function Tmp() {}
Tmp.prototype = o;
return new Tmp();
}
//.....
NewBox.prototype = inherit(Box.prototype);
Or:
NewBox.prototype = Object.create(Box.prototype);
In that way, you express the same inheritance hierarchy without running your Box constructor that first time, avoiding any side effect that it might cause.
At last but not least, whenever you replace a function's prototype property is always recommended to restore the constructor property of this new prototype object, otherwise it will point to the wrong function.
In your example, since you replace the NewBox.prototype with a new instance of Box, the NewBox.prototype.constructor property will point to Box, (your instances are affected, e.g. a.constructor === Box; // true) instead of to NewBox as you would expect, we need to set it back, e.g.:
NewBox.prototype = someObject; // as any of the examples above
NewBox.prototype.constructor = NewBox;
You could abstract those details into a function, as I did in the inherit function above:
function inherits(child, parent) {
var obj, Tmp = function () {};
Tmp.prototype = parent.prototype;
obj = new Tmp();
child.prototype = obj;
child.prototype.constructor = child;
}
//...
// instead of setting the `NewBox.prototype` manually
inherits(NewBox, Box); // "NewBox inherits from Box"
//...
Maybe it's impossible or I'm doing something really wrong, so please help!
You're doing something wrong.
If you want instance-specific values, initialize them in the constructor, not the prototype.
Matt Ball has the right idea. Instead try:
var Box = (function(){
var numberOfBoxes = 0;
function() {
this.id = numberOfBoxes++;
}
})();
Or in the case you want all your (different) classes to have unique ids:
var generateUniqueID = (function(){
var runningCount = 0;
return function (){
return runningCount++;
}
})();
var Box = function() {
this.id = generateUniqueId();
};
var NewBox = function() {
this.id = generateUniqueId();
this.newThing = true;
};