Understanding prototyping and oops implementation in javascript - javascript

var Todo = function(x){
this.data = x;
this.view = function(){
alert("hi")
check()
}
check = function(){
alert("checking")
alert(this.data)
}
}
Todo.prototype.add = function(item){
this.data.push(item)
}
var todo = new Todo([1,2,3])
alert(todo.data)
todo.add(5)
alert(todo.data)
todo.view()
In above code why I am not able to get the value of data in check method. I am little confused.

this in the check function refers to the global object window.
Fix it with:
var Todo = function(x){
this.data = x;
this.view = function(){
alert("hi");
this.check();
};
this.check = function(){
alert("checking");
alert(this.data);
};
};
And if you don't want to expose check method public, then you could do like below.
var Todo = function(x){
this.data = x;
this.view = function(){
alert("hi")
check.apply(this); //here, by using apply method
}
var check = function(){
alert("checking")
alert(this.data)
}
}

you have declared check as a global variable:
var a = 5; local variable
a = 5; global variable (attached to window)
therefore, the function context(this) is bound to Window when calling check(), which does not contain data property.
so you have to attach check function to Todo "class":
this.check = function() {};
a side note, you could get the desired functionality by setting manually the function context to todo when invoking the function:
check.apply(todo);

Related

Copy object functions and properties in new object by value not by reference - javascript

I want to copy the functions and properties of an object into new object. The old object should not effect by changing made in new Object.
Here is the object definition:
var Call = function() {
this.number="123";
}
Call.prototype.function1 = function() {
return this.number;
}
var callobj = new Call();
I can access function1 using callobj.function1().
What I have tried to copy it:
Javascript:
var newcallobj = Object.assign({}, callobj);
In this case, i am not able to access function1 but i can access number property directly.
JQUERY:
var newObj = jQuery.extend(true, {}, callobj); OR
var newObj = jQuery.extend({}, callobj);
In this case, i am able to access function1 and property but when i change number like that newObj.number="222". It also change the value of original object.
I know that there is couple of other posts. But all is not working for me. Please let me know if i am doing any thing wrong?
AFTER #gurvinder372 answer(I am updating question):
After #gurvinder372 answer. It is working for first level of property but if it has another object like i show below and i change the value of property of another object. Then it is effecting on original object also.
var ABC = function(){
this.number = "333";
}
var Call = function() {
this.number="123";
this.anotherobj = new ABC();
}
Call.prototype.function1 = function() {
return this.number;
}
var callobj = new Call();
var newcallobj = Object.create(callobj);
newcallobj.anotherobj.number= "123";
console.log(newcallobj.anotherobj.number);
console.log(callobj.anotherobj.number);
Output of both is 123. #gurvinder372. can you check th above code ?
Object.assign only copies the enumerable properties of an object.
Use Object.create instead of Object.assign
var newcallobj = Object.create(callobj);
var Call = function() {
this.number="123";
}
Call.prototype.function1 = function() {
return this.number;
}
var callobj = new Call();
var newcallobj = Object.create(callobj);
console.log(newcallobj.function1());
Ok. By the help of #gurvinder372. The following solution is working for me.
var ABC = function(){
this.number = "333";
}
var Call = function() {
this.number="123";
this.anotherobj = new ABC();
}
Call.prototype.function1 = function() {
return this.number;
}
var callobj = new Call();
var newcallobj = Object.create(callobj);
newcallobj.anotherobj = Object.create(callobj.anotherobj);
newcallobj.anotherobj.number= "123";
console.log(newcallobj.anotherobj.number);
console.log(callobj.anotherobj.number);
Please let me know if there is any better solution other than this?

private object not setting data

Hi I'm trying to implement a LinkedList in Javascript. When i assign a value to my node it doesn't seem to store it when I use my getter. For example:
var Node =function() {
var _data;
var _next ={};
var that = this;
that.getData = function() {
return _data;
};
that.setData = function(data) {
that._data = data;
};
that.getNext = function() {
return _next;
};
that.setNext = function(next) {
that._next = next;
};
return that;
};
Will not work with:
var nodeObj = new Node();
nodeObj.setData("hello");
console.log(nodeObj.getData());
_data is not the same as that._data, you must do this:
that.getData = function() {
return that._data;
};
OR you could do this instead:
that.setData = function(data) {
_data = data;
};
the benefit of the second approach being that you're simulating a private variable (because you cannot do nodeObj._data in the second case but you can in the first)
also var that = this; is unnecessary, you can simply do this._data in this case.
For your case here, you can assume that if you're calling a function like yourObject.someFunction(), then within someFunction the value of this equals yourObject. (And this isn't always true in javascript but since you're starting off you should think about it this way for now. If you pass a function to another function as a variable and then call it then this wouldn't be the case).

Javascript scope issue with objects (this)

I have the following code:
var tradingInterface = function() {
this.json = '';
this.init = function() {
$.get( '/whatever',{}, function(data) {
this.json = data;
// Rebuilds Everything
this.rebuildAll();
});
};
this.rebuildAll = function() {
//whatever here
};
};
Why am I getting in init function the following error?
ReferenceError: this.rebuildAll is not defined
this.rebuildAll();
Why can I access to this.json without scoping problems but not to this.rebuildAll?
I wrote a similar previous thread but i was redirected to How to access the correct `this` / context inside a callback? but i am not able to make it work properly.
As thw thread suggets, I tried with:
var tradingInterface = function() {
this.json = '';
var self = this;
this.init = function() {
$.get( '/whatever',{}, function(data) {
this.json = data;
// Rebuilds Everything
self.rebuildAll();
});
};
this.rebuildAll = function() {
//whatever here
};
};
The error disappears but rebuildAll function is not doing what it should...
I need some help...
Regards,
The error disappears but rebuildAll function is not doing what it should...
You are not explaining what the rebuildAll is supposed to do, so I can only assume that the issue is that you didn't replace
this.json = data;
with
self.json = data;
Inside the the $.get callback, this refers to a different object than self. This is all explained in the question/answer you linked to.
Why can I access to this.json without scoping problems but not to this.rebuildAll?
You are assigning to this.json. You can (almost) always assign a property to an object. However, you are reading this.rebuildAll and try to call it as a function. Since this.rebuildAll is undefined, you cannot call it.
Simplified example:
var obj = {};
obj.foo = 42; // works, foo didn't exist before
obj.bar = function() {}; // works, bar didn't exist before
obj.bar(); // works because bar exists
obj.baz(); // doesn't work, because baz doesn't exist

Is it possible to append functions to a JS class that have access to the class's private variables?

I have an existing class I need to convert so I can append functions like my_class.prototype.my_funcs.afucntion = function(){ alert(private_var);} after the main object definition. What's the best/easiest method for converting an existing class to use this method? Currently I have a JavaScript object constructed like this:
var my_class = function (){
var private_var = '';
var private_int = 0
var private_var2 = '';
[...]
var private_func1 = function(id) {
return document.getElementById(id);
};
var private_func2 = function(id) {
alert(id);
};
return{
public_func1: function(){
},
my_funcs: {
do_this: function{
},
do_that: function(){
}
}
}
}();
Unfortunately, currently, I need to dynamically add functions and methods to this object with PHP based on user selected settings, there could be no functions added or 50. This is making adding features very complicated because to add a my_class.my_funcs.afunction(); function, I have to add a PHP call inside the JS file so it can access the private variables, and it just makes everything so messy.
I want to be able to use the prototype method so I can clean out all of the PHP calls inside the main JS file.
Try declaring your "Class" like this:
var MyClass = function () {
// Private variables and functions
var privateVar = '',
privateNum = 0,
privateVar2 = '',
privateFn = function (arg) {
return arg + privateNum;
};
// Public variables and functions
this.publicVar = '';
this.publicNum = 0;
this.publicVar2 = '';
this.publicFn = function () {
return 'foo';
};
this.publicObject = {
'property': 'value',
'fn': function () {
return 'bar';
}
};
};
You can augment this object by adding properties to its prototype (but they won't be accessible unless you create an instance of this class)
MyClass.prototype.aFunction = function (arg1, arg2) {
return arg1 + arg2 + this.publicNum;
// Has access to public members of the current instance
};
Helpful?
Edit: Make sure you create an instance of MyClass or nothing will work properly.
// Correct
var instance = new MyClass();
instance.publicFn(); //-> 'foo'
// Incorrect
MyClass.publicFn(); //-> TypeError
Okay, so the way you're constructing a class is different than what I usually do, but I was able to get the below working:
var my_class = function() {
var fn = function() {
this.do_this = function() { alert("do this"); }
this.do_that = function() { alert("do that"); }
}
return {
public_func1: function() { alert("public func1"); },
fn: fn,
my_funcs: new fn()
}
}
var instance = new my_class();
instance.fn.prototype.do_something_else = function() {
alert("doing something else");
}
instance.my_funcs.do_something_else();
As to what's happening [Edited]:
I changed your my_funcs object to a private method 'fn'
I passed a reference to it to a similar name 'fn' in the return object instance so that you can prototype it.
I made my_funcs an instance of the private member fn so that it will be able to execute all of the fn methods
Hope it helps, - Kevin
Maybe I'm missing what it is you're trying to do, but can't you just assign the prototype to the instance once you create it? So, first create your prototype object:
proto = function(){
var proto_func = function() {
return 'new proto func';
};
return {proto_func: proto_func};
}();
Then use it:
instance = new my_class();
instance.prototype = proto;
alert(instance.prototype.proto_func());

In jQuery, how do you resolve the scope of "this", when you are in the scope of each()?

I've created an Object, and have a method setup() in the object.
this.debug = function (){...}
this.setup = function(){
var fieldsets = form.children("fieldset");
fieldsets.each(function(){
this.debug($(this).attr("class")));
});
}
I'm trying to call this.debug which is in the scope of the Object but not in the scope of each, since THIS is a different this...
How do I access this.debug?
Say var that = this after this.debug, then do that.debug.
This is basically Skilldrik's answer, but showing you where it works best
this.setup = function(){
// save it in a scoped var... some people use "self" for this purpose, i prefer
// naming it whatever the outer object actually is...
var containingObject = this;
var fieldsets = form.children("fieldset");
fieldsets.each(function(){
// use that scoped var later!
containingObject.debug($(this).attr("class")));
});
}
In jQuery 1.4 you can do:
this.debug = function (){...}
this.setup = function(){
var fieldsets = form.children("fieldset");
fieldsets.each(jQuery.proxy(function(){
this.debug($(this).attr("class")));
},this);
}
The jQuery.proxy(function, object) function will take 2 arguments:
The function will be the function used in the loop.
The object argument will be the this object inside the function.
In this way, you can transfer the this from the outer scope inside the each function.
I tried this in my Greasemonkey-Console:
this.debug = function() {
console.log("foo");
};
this.setup = function() {
var fieldsets = form.children("fieldset");
fieldsets.each(function(){
debug($(this).attr("class"));
});
};
Which will search the scope for any debug .. which that is hopefully the function above. This will fail, if you assign a variable with the very same name :)
I normally do it this way: (note:example below is from memory but looks sound):
function CustomObject()
{
var _instance = this;
this.debug = function(){...};
this.setup =
function()
{
var fieldsets = form.children("fieldset");
fieldsets.each(
function()
{
_instance.debug($(this).attr("class"));
});
};
}
this.debug = function (){...}
this.setup = function(){
var that = this;
var fieldsets = form.children("fieldset");
fieldsets.each(function(){
that.debug($(this).attr("class")));
});
}

Categories

Resources