widget , call function from option error? - javascript

In the widget I'm trying to call a function from a property in the options
getThing: this._runFunc()
but I get an error saying _runFunc() is not an instance of an object? can you please help?
$.widget('my.testW', {
options:{
buttons:buttons,
getThing: this._runFunc() // why wont _runFunc work?
},
_create: function () {
//do things
var s = this.options.getThing;
},
_runFunc: function (){
return 'hello world'
}
});

In the $.widget call, the options object and the anonymous object literal within which it is contained are just parameters to $.widget, so this refers to whatever this was outside the $.widget call, and not the newly defined widget.
AFAIK, there's no way to refer to some other element of the same anonymous object literal from within values of that literal.
If you wish to hide your function, you could define your widget thus:
(function() {
function _runFunc() {
return 'hello world';
};
$.widget(..., {
options: {
getThing: _runFunc()
},
_runFunc: _runFunc; // if you want to expose this method
});
})();
where the IIFE encloses the utility function within that scope.

Related

Function as a Parameter that Returns an Anonymous Object

I see a lot of javascript code that passes a function as a parameter that returns an anonymous object.
myFunction(function() {
return {
foo: 'bar'
};
});
What is the advantage or the purpose of using this instead of simply passing directly an anonymous object?
myFunction({
foo: 'bar'
});
The difference is that if you alter the argument passed in your second code snippet, there is no way to get the original argument again.
If you pass an function instead you can call the function more than once and get always the same argument back. (if the function is implemented this way)
Furthermore if you use a function you can do additional stuff like logging how often your function / argument was called or so on. So using a function adds more flexibility for the user of the function.
For the developer of the function on the other hand accepting a function as argument can cause the tiny problem that a function doesn´t have to return the same value every time you call it - myFunc() == myFunc() COULD return false, therefore i would not recommend handing over a function if it is supposed to JUST return an argument.
Backbone uses have a lot of places where they will initialize the function if passed to get the value, eg.
Backbone.Model.extend({
url: function() { return 'myurl.aspx'; }
});
// VS
Backbone.Model.extend({
url: 'myurl.aspx'
});
This is clever if you will have to make some calculation / run some conditions before you'ill know that the url is.
Backbone.Model.extend({
url: function() {
if ( this.get('name') ) {
return 'service1.aspx';
}
else {
return 'service2.aspx';
}
}
});
Your first example sends an anonymous function as the first argument to myFunction while the second example sends an object as the first argument.
myFunction(function() {
return {
foo: 'bar'
};
}); // function() {...}
myFunction({
foo: 'bar'
}); // {foo: 'bar'}
function myFunction(what) {
console.log(what);
}
If you are talking about closures, the main difference is that you can have private variables inside closures:
var setGet = (function() {
var v = null;
return {
get: function() { return v; },
get: function(val) { v=val; },
};
});
// VS:
var setGet = {
v: null,
get: function() { return this.v; },
get: function(val) { this.v; },
};
In the first example you can't access the variable v without using .get/.set on setGet while in the 2. example i can simple change it by setting setGet.v = 'new_val';
In the first example You are passing a callback function.
When we pass a callback function as an argument to another function,
we are only passing the function definition. We are not executing the function
in the parameter.
And since the containing function has the callback function in its parameter as a function definition, it can execute the callback anytime. This allows us to execute the callback functions at any point in the containing function.
A simple example for this is jQuery click binding :
/The anonymous function is not being executed there in the parameter.
//The anonymous function is a callback function
$("#btn_1").click(function() {
alert("Btn 1 Clicked");
});
But in the second example you are simply passing an object to the called function.
Use this link to get more details about Callback functions. Enjoy :)
I think, it really depends where you saw the code being used.
In this case, myFunction seems to require you to pass a function rather than an Object.
But in general, Consider this
myFunction(function() {
var a = "bar";
return {
foo: a
};
});
and this:
var a = "bar"
myFunction({
foo: a
});
In the second case, anyone outside is able to access a. But in first case, a becomes similar to a private variable which is exposed as public by the function. So you might observe this in places where people wish to follow OOP concepts in the otherwise classless JS.
Another case is where you require a callback function or some function that is to be called later. So if the data is to be preserved until a certain something is over you can make it available as the return value of a function, rather than storing it globally...

Issue with calling javascript objects

I'm fairly new to javascript objects and I could use some clarification on calling variables. I'm trying to call the test variable in the bar function. Is this possible? If so how would I do it correctly?
var foo = {
bar: function()
{
var test = 'Hello World';
},
speak: function()
{
// Log the Variable from above ^^
console.log(foo.bar.test);
}
};
Thanks
No; local variables are not visible outside their declaring functions.
Instead, you need to add a property to the object:
foo.test = ...;
You could also set foo.bar.test; that would add a property to the function object.
When you declare a local variable inside the function, you add it to the VariableEnvironment of the functions (which essentially has no difference from the outer LexicalEnvironment, but the ECMA distinguishes them). The function has a reference to the LexicalEnvironment of the scope in which it was declared (in our case, the global object or window). When you try to reference the variable from inside the function, the engine first searches for it the the native VariableEnvironment of the function, and then, if not found, in the outer LexicalEnvironment. In your case, you try to reference a variable from outside of the function, so the engine searches for it in the scope of global object at the very start.
So, to accomplish your task, you should either declare the variable in the outer scrope, and then assign it inside the function, or you should add a new property to the object and then reference it:
var foo = {
test: 'Hello world',
speak: function()
{
console.log(this.test);
}
};
You can access test by return it on call of bar method.
var foo = {
bar: function()
{
var test = 'Hello World';
return test;
},
speak: function()
{
// Log the Variable from above ^^
console.log(foo.bar());
}
};
In order to access the variable test in that manner, you need to define it as a property of the object like so:
var foo = {
test: 'Hello World, before calling bar()',
bar: function()
{
this.test = 'Hello World';
},
speak: function()
{
// Log the Variable from above ^^
console.log(this.test);
}
};
console.log(foo.test);
I also changed the functions to access the object foo using the keyword this. It will usually work but keeping track of your scope in javascript can be tricky sometimes, so just try to be aware of that.

Running a custom function - settings.func is not a function

I have written a jQuery plugin which I want to call a custom function on like so...
(function($) {
$.fn.testPlugin= function(options) {
var settings = {
func: null
};
if (options) {
$.extend(settings, options);
}
settings.func();
};
})(jQuery);
In this case I want to run the doSomething function.
$(document).ready(function(){
$('div').testPlugin({
func: 'doSomething'
});
});
function doSomething() {
alert('hello');
}
I always get the error settings.func is not a function so I am having to use:
eval(settings.func+"()");
Intead of:
settings.func();
Which is not ideal! Any ideas why I am getting this?
Because you're assigning a string to settings.func, not a function. Strings are never functions, even if they contain the name of a function.
Functions are first-class citizens, however, which means you can use them as you would any other variable, assigning them to variables or passing them as arguments to other functions. Change:
$('div').testPlugin({
func: 'doSomething'
});
to
$('div').testPlugin({
func: doSomething
});
and it should work.

Calling nested function when function name is passed as a string

I'm trying to access a nested function by passing the function name in as a string and then calling it. Eg, see this post
function outer(action){
window["outer"][action]();
function inner(){
alert("hello");
}
}
outer("inner");
However it doesn't work. Error:
window.outer[action] is not a function
How to make this work, or an alternative way of calling a nested function.
The reason for this is that I am trying to hide a bunch of functions that are called by an iframe inside a functions scope.
function outer(action){
var inner = {
func1: function() {},
func2: function() {},
func3: function() {},
// ...
}
inner[action]();
}
outer("func1");
In that way you are trying to access the "inner" property of the "outer" function (outer.inner) that is not defined. The only way to do that is by using eval:
function outer(action){
eval(action+"()");
function inner(){
alert("hello");
}
}
outer("inner");
But remember eval is evil is some situations so be careful.

Prototypes Object.extend with multiple objects that contain there own functions

How would I achieve something along the lines of this..
var Persistence = new Lawnchair('name');
Object.extend(Lawnchair.prototype, {
UserDefaults: {
setup: function(callback) {
// "save" is a native Lawnchair function that doesnt
//work because
// "this" does not reference "Lawnchair"
// but if I am one level up it does. Say if I defined
// a function called UserDefaults_setup() it would work
// but UserDefaults.setup does not work.
this.save({key: 'key', value: 'value'});
// What is this functions scope?
// How do I access Lawnchairs "this"
}
},
Schedule: {
refresh: function(callback) {
}
}
});
//this get called but doesnt work.
Persistence.UserDefaults.setup();
UserDefaults is it's own object, so "this" refers to UserDefaults there. In other languages the result would be the same...accessing "this" within a function in an object that's a property of another object won't give you the parent.
The simplest solution is to use a version of dependency injection and just pass "this" in to the lower-level class:
var Persistence = new Lawnchair('name');
Object.extend(Lawnchair.prototype, {
initialize: function(){
// since initialize is the constructor when using prototype,
// this will always run
this.UserDefaults.setParent(this);
},
UserDefaults: {
setParent: function(parent){
this.parent = parent;
},
setup: function(callback) {
// "save" is a native Lawnchair function that doesnt
//work because
// "this" does not reference "Lawnchair"
// but if I am one level up it does. Say if I defined
// a function called UserDefaults_setup() it would work
// but UserDefaults.setup does not work.
this.parent.save({key: 'key', value: 'value'});
// What is this functions scope?
// How do I access Lawnchairs "this"
}
},
Schedule: {
refresh: function(callback) {
}
}
});
//this get called but doesnt work.
Persistence.UserDefaults.setup();
Use bind(this)
setup: function(callback) {
// "save" is a native Lawnchair function that doesnt
//work because
// "this" does not reference "Lawnchair"
// but if I am one level up it does. Say if I defined
// a function called UserDefaults_setup() it would work
// but UserDefaults.setup does not work.
this.save({key: 'key', value: 'value'});
// What is this functions scope?
// How do I access Lawnchairs "this"
}.bind(this)
is the same of passing this in a global variable of by parameter but in an elegant form.

Categories