Javascript OOP and jQuery can't touch object properties - javascript

How do i edit property variables from within jquery as shown in the example below:
function Timetable(){
this.timetables=[];
//get timetable data for currentUser
$.get('http://someurl.com/api',function(data){
this.timetables.concat($.parseJSON(data));
});
}
What seems to happen is that the this.timetables seems to be out of the variable scope.

You don't need to use this, you need to create a closure.
function timetable(){
// create a closure
var timetables = Array();
//get timetable data for currentUser
$.get('http://someurl.com/api',function(data){
// this references the Array created above
that.timetables = that.timetables.concat($.parseJSON(data));
});
}
It just occurred to me that you may be using timetable to create objects. As a side note, if that's the case, the convention is to call it Timetable for clarity. If that's the case, use something like this.
function Timetable () {
// store a reference to the scope
var that = this;
// create an instance property of the Timetable object
this.timetables = [];
$.get('http://someurl.com/api',function(data){
// use our scope reference captured above
// to update the timetables property
that.timetables = that.timetables.concat($.parseJSON(data));
});
}
var t = new Timetable();
// once the get call is complete
console.log(t.timetables);

It's because inside your callback function, the scope of this is not the same. It now refers to the object bound to your callback function ($ in this case).
Earlier answers to your question already advised you on a concrete way out of your trouble, so I'm not of much help there.
But if you want a (very) detailed and absolutely worth-reading answer about this topic in a broader sense, you should definitely read this post (see the accepted answer).
This other one about closures (what you seem to need here) could also be of great help.

Force the scope.
var scope = this;
Then you can use scope inside instead of "this" from jQuery

Related

What is difference between function FunctionName(){} and object.FunctionName = function(){}

Today while working my mind was stack at some point in javascript.
I want to know that what is basic difference between
function FunctionName(){
//Code goes here;
}
And
var MyFuncCollection = new Object();
MyFuncCollection.FunctionName = function(){
//Code goes here;
}
Both are working same. Then what is difference between then. Is there any advantage to use function with object name?
I have read Question. But it uses variable and assign function specific variable. I want to create object and assign multiple function in single object.
The first one defines a global function name. If you load two libraries, and they both try to define FunctionName, they'll conflict with each other. You'll only get the one that was defined last.
The second one just has a single global variable, MyFuncCollection. All the functions are defined as properties within that variable. So if you have two collections that try to define the same function name, one will be FuncCollection1.FunctionName, the other will be FuncCollection2.FunctionName, and there won't be any conflict.
The only conflict would be if two collections both tried to use the same name for the collection itself, which is less likely. But this isn't totally unheard of: there are a few libraries that try to use $ as their main identifier. jQuery is the most prominent, and it provides jQuery.noConflict() to remove its $ binding and revert to the previous binding.
The short answer is, the method in object context uses the Parent Objects Context, while the "global" function has its own object context.
The long answer involves the general object-oriented approach of JavaScript, though everything in JavaScript is an object you may also create arrays with this Method.
I can't really tell you why, but in my experience the best function definition is neither of the top mentioned, but:
var myFunction = function(){};
It is possible to assign function to variables, and you may even write a definition like this:
MyObject.myMethod = function(){};
For further reading there are various online Textbooks which can give you more and deeper Information about this topic.
One main advantage I always find is cleaner code with less chance of overwriting functions. However it is much more than that.
Your scope changes completely inside the object. Consider the following code ::
Function:
function FunctionName(){
return this;
}
FunctionName()
Returns:
Window {top: Window, location: Location, document: document, window: Window, external: Object…}
Object:
var MyFuncCollection = new Object();
MyFuncCollection.FunctionName = function(){
return this;
}
MyFuncCollection.FunctionName()
Returns:
Object {}
This leads to some nice ability to daisy chain functions, amongst other things.
The first:
function functionName (){
//Code goes here;
}
Is a function declaration. It defines a function object in the context it's written in.
Notice: this doesn't have to be the global context and it doesn't say anything about the value of this inside it when it's invoked. More about scopes in JavaScript.
Second note: in most style guides functions are declared with a capitalized name only if it's a constructor.
The second:
var myFuncCollection = {};
myFuncCollection.functionName = function () {
//Code goes here;
};
notice: don't use the new Object() syntax, it's considered bad practice to use new with anything other then function constructors. Use the literal form instead (as above).
Is a simple assignment of a function expression to a property of an Object.
Again the same notice should be stated: this says nothing about the value of this when it's invoked.
this in JavaScript is given a value when the function object is invoked, see here for details.
Of course, placing a function on an Object help avoiding naming collisions with other variables/function declarations in the same context, but this could be a local context of a function, and not necessarily the global context.
Other then these differences, from the language point of view, there's no difference whatsoever about using a bunch of function declarations or an Object with bunch of methods on it.
From a design point of view, putting methods on an Object allows you to group and/or encapsulate logic to a specific object that should contain it. This is the part of the meaning of the Object Oriented Programming paradigm.
It's also good to do that when you wish to export or simply pass all these functions to another separate module.
And that's about it (:

Get name of instance of a class within the class

Here is what I want:
var Validator = function () {
this.do = function () {
alert(INTANCENAME); /// SHOULD BE 'FOO'
}
}
var FOO = new Validator().do();
Is it possibe to implement in Javascript?
The truth is there is no point of doing that, the only way I can hardly think is to loop all window or scope objects and check some kind of equality with the current object, something like
this.do = function () {
for(var key in window) {
if(this === window[key]) {
alert(key);
}
}
};
In order to work call it after you assign it.
var FOO = new Validator();
FOO.do();
Another issue that can come up is that an instance (a reference) can be stored in various variables so maybe will not get what you expect.
The literal answer to your question would be:
Use (new Error()).stack to get information on the line and the function where the do() method was called.
Use JS parser (e.g. Esprima) to find out what variable it was called on (if any, the method itself might be assigned to a variable).
I do not recommend doing this though.
There's no way to directly do what you're asking for here. Objects themselves are not in any defined by their matching variable name - in fact it's possible to have objects that exist that are not directly assigned to a variable, and multiple variables assigned to the same object.
The javascript interpreter uses our variable names as identifiers to help with the code execution, but once it's running the variable name makes no difference to the running javascript program, as it's probably been reduced to a memory reference by the time it's executing, completely separated from the original code that you wrote.
Edit: Answer by yannis does kind of simulate this, but it relies on working with variables available in a specific scope - what I ment was that there's no direct way to do this from within the object itself as per your example in the question.

Correct use of the this pointer in javascript for callbacks in knockout.js

I am a relatively experienced c# (and before that c++ Win32) developer, I am new to javascript and have a question regarding the this pointer.
I am using knockout.js, and one function called subscribe accepts a this variable, that will be set inside the callback function.
From my way of thinking from the Win32 days and C#, on any callback function i want a scope object which contains my state.
In this case I have use the this javascript thing to set my callback scope.
My questions are:
Now everything works (full fiddle here if you are
interested), but have I done something terrible?
Is there any reason this is used instead of passing in an explicit
scope variable as a parameter (that would make things easier to understand as
for me, this makes the workings kind of hidden).
What is the intended use for this?
From http://knockoutjs.com/documentation/observables.html it says:
The subscribe function accepts three parameters: callback is the function that is called whenever the notification happens, target (optional) defines the value of this in the callback function, and event (optional; default is "change") is the name of the event to receive notification for. Example below
myViewModel.personName.subscribe(function(oldValue) {
alert("The person's previous name is " + oldValue);
}, null, "beforeChange");
My code snippet below:
var computedOptions = createComputedDepdency(viewModel[option.requires.target],option.data);
viewModel[option.optionsName] = computedOptions;
console.log("making callback scope object for: " + option.optionsName );
var callbackScope = {
callbackName: option.optionsName,
options: computedOptions,
selectedValue: viewModel[option.selectedName]
};
// when the list of available options changes, set the selected property to the first option
computedOptions.subscribe(function () {
var scope = this;
console.log("my object: %o", scope);
scope.selectedValue(scope.options()[0].sku);
console.log("in subscribe function for..." + scope.callbackName);
},callbackScope);
First a semantic note:
The scope of a function is not related to this word. The context is related to this. The scope is related to the accessibility of variables and functions inside another function.
When you try to read a variable outside the function where it's declared, then you trying to access to a var outside its scope. So you cannot do it because the var is inside a scope not accessible from current position.
Now everything works (full fiddle here if you are interested), but have I done something terrible?
If it works, it's not so terrible :-)
Is there any reason this is used instead of passing in an explicit scope variable as a parameter (that would make things easier to understand as for me, this makes the workings kind of hidden).
a fast read: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
In javascript the value of this is determined by how a function is called.
In one way this approach could save annoying passage of context as argument: in a well documented library, the this use is very intituitive.
In other cases, I agree when you change continually context in your app without a rigorous logic, it could be confused.
What is the intended use for this?
We should always remember how and when the javascript is born. It was born for browser in order to interact with the DOM.
For this purpose, the context has sense that change based of which element call the function.
For example:
var divs = document.getElementsByTagName('DIV');
for(var i = 0; i < divs.length; i++) {
divs[i].addEventListener('click',_clickHandler);
}
function _clickHandler() {
this.innerHTML = "clicked";
}
DEMO http://jsfiddle.net/AYBsL/1/
This is an example to how is useful the implicit change of context in javascript.
You could do this also for user-defined function: when you call a function you could change the context:
_clickHandler.call(divs[0]); // simulate click of first div
In javascript 'this' refers to the object that called your function. Only in a situation when you use 'new' keyword you can expect it to point to the current object (function).
var MyObject = function () {
this.hello = function () { console.log(this); }
}
var instance = new MyObject();
There is a way to make sure that this is always what you expect and that is creating a variable to store the correct reference for you and use that instead of this... in your example it would be similar to this...
computedOptions = function () {
var that = this;
}
computedOptions.subscribe(function () {
console.log("my object: %o", scope);
scope.selectedValue(that.options()[0].sku);
console.log("in subscribe function for..." + that.callbackName);
},callbackScope);
MDN JavaScript reference would inevitably explaing it more better then myself, have a look at it.
You shouldn't mix scope and this. this is supposed to mimic classical-oop languages like java or++, that is to keep the reference to an instance object. But it can be used just to execute arbitrary function on a given context using .apply() or .call.
What about scope, you don't have to do anything to pass the scope to a function, since the outer scope becomes automatically accessible inside function. You should read about closures - it's the best part of javascript.

function used from within javascript dojo closure using "this"-notation is undefined

I have a Problem accessing an Object function using "this".
In case of the below example (which is simplified, because I cannot supply actual code due to various reasons) the function call this._getEntry() is "undefined" when calling
createList().
I would hope for some opinions on wether this is due to a misunderstanding of
javascript closures or rather a syntax error.
In the latter case I will have to find the error in the actual code myself.
If it is a misunderstanding of javascript or dojo concepts I would really appreciate
some help on how to correctly scope and access the below mentioned function (_getEntry()).
var OBJECT = {
_getEntry : function(entry){
var li = document.createElement('LI');
li.appendChild(document.createTextNode(entry));
return li;
},
createList : function(entryArray){
var list = document.createElement('UL');
dojo.forEach(entryArray,function(entry){
list.appendChild(this._getEntry(entry));
});
dojo.body().appendChild(list);
}
};
OBJECT.createList(["entry1","entry2"]);
thanks!
Firstly, I think your pasted code is missing ); to complete the forEach.
Secondly, forEach takes an optional third parameter which determines the context in which the passed function runs. If not given, it defaults to the global scope, so yes this is your problem. Assuming this already refers to what you need it to immediately outside the forEach, you should be able to just pass this in as the third argument to forEach and it should work, e.g.:
dojo.forEach(entryArray, function(entry){
list.appendChild(this._getEntry(entry));
}, this);
For more information: http://dojotoolkit.org/api/dojo/forEach - which is based on the API in JS 1.6 https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach
This is a common problem and you are right, its all about scoping and closure. What is happening here is once you get into the forEach the context changes to the global context (window). Handily, Dojo provides a way to set this context:
createList : function(entryArray){
var list = document.createElement('UL');
dojo.forEach(entryArray,function(entry){
list.appendChild(this._getEntry(entry));
}, this);
dojo.body().appendChild(list);
}
An alternate approach is to use closure to get at this
createList : function(entryArray){
var list = document.createElement('UL');
var _this = this; // closure allowing the forEach callback access to this
// some popular variable names used for this include:
// $this, _this, me and that
dojo.forEach(entryArray,function(entry){
list.appendChild(_this._getEntry(entry));
});
dojo.body().appendChild(list);
}

How is data passed to anonymous functions in JavaScript?

When I pass 'this' to an anonymous function like so:
MyClass.prototype.trigger = function(){
window.setTimeout(function(){this.onTimeout();},1000);
}
I get a "this.onTimeout is not a function"-error. I guess that 'this' is no longer available at the time the anonymous function is executing? So I've been doing this:
MyClass.prototype.trigger = function(){
var me = this
window.setTimeout(function(){me.onTimeout();},1000);
}
Is this really how you're supposed to do things? It kinda works, but it feels weird.
Then we have this example:
$(function(){
function MyClass(){
this.queue = new Array();
}
MyClass.prototype.gotAnswer = function(count){
$('body').append("count:"+count+"<br/>");
}
MyClass.prototype.loadAll = function(){
var count = 0;
var item;
while(item = this.queue.pop()){
count++;
var me = this;
$.getJSON("answer.html",{},function(data){me.gotAnswer(count);});
}
}
var o = new MyClass();
o.queue.push(1);
o.queue.push(2);
o.loadAll();
});
This outputs:
2
2
Shouldn't it output:
1
2
instead? Then I discovered that putting the $.getJSON-statement in another function makes it all work:
MyClass.prototype.loadAll = function(){
var count = 0;
var item;
while(item = this.queue.pop()){
count++;
this.newRequest(count);
}
}
MyClass.prototype.newRequest = function(count){
var me = this;
$.getJSON("answer.html",null,function(data){ me.gotAnswer(count); });
}
This outputs:
1
2
(Or the other way around.) What's happening here? What is the right way to pass variables to an anonnymous function?
Sorry for the confusing and lengthy post.
What you are experiencing is the correct behavior - it's not a good behavior, but it's part of the language. The value of "this" is reset inside every function definition. There are four ways to call a function that have different ways of setting "this".
The regular function invocation myFunc(param1, param2); This way of calling a function will always reset "this" to the global object. That's what's happening in your case.
Calling it as a method myObj.myFunc(param1, param2); This unsurprisingly sets "this" to whatever object the method is being called on. Here, "this" == "myObj".
Apply method invocation myFunc.apply(myObj, [param1, param2]) This is an interesting one - here "this" is set to the object you pass as the first parameter to the apply method - it's like calling a method on an object that does not have that method (be careful that the function is written to be called this way). All functions by default have the apply method.
As a constructor (with "new") myNewObj = new MyConstructor(param1, param2); When you call a function this way, "this" is initialized to a new object that inherits methods and properties from your function's prototype property. In this case, the new object would inherit from MyConstructor.prototype. In addition, if you don't return a value explicitly, "this" will be returned.
The solution you used is the recommended solution - assign the outside value of "this" to another variable that will still be visible inside your function. The only thing I would change is to call the variable "that" as Török Gábor says - that's sort of the de-facto standard and might make your code easier to read for other programmers.
You are confused about the closures.
For the first problem, yes, you are right, that is the way it can be done. The only difference that there is a convention to name the variable that that holds this.
MyClass.prototype.trigger = function(){
var that = this;
window.setTimeout(function(){that.onTimeout();},1000);
}
There is already a nice thread about this on StackOverflow. Check answers for question
How does a javascript closure work?.
Your second problem is an exact duplicate of Javascript closure inside loops - simple practical example.
you will have the same problem if inside your new method: newRequest you have to use a "for" or a "while" statement.
Another solution could be creating a closure:
like that:
$.getJSON("answer.html",{},(function(me){return function(data){me.gotAnswer(count);}})(this));

Categories