excuse the pseudo code, my actual file is much larger:/
I want to call a function (with parameters) from inside a class. However, that function should be passed to the class as a variable.
someObject = {
itWorked:function(answer){
alert(answer);
},
plugins:{
somePlugin:function(){
var callback;
this.doSomething = doSomething;
function setCallback(c){
callback = c;
}
function doSomething(){
var answer = "hello";
[callback](answer); // how do I call this?
}
}
},
widgets:{
something:function(){
var doIt = new someObject();
doIt.setCallback(someObject.itWorked()); // how do I send this?
doIt.doSomething();
}
}
}
So how would I pass itWorked() to the class?
And how would I call that itWorked(answer) function within the class as well as passing a variable to if?
You will need to change
setCallback = function (c) {callback = c;}
to
this.setCallback = function (c) {callback = c;}
so the setCallback function will be public.
If you also want to scope the callback, you can call it like this
callback.call(scope, param1, param2);
If you don't know how many parameters, you can call it like this
callback.apply(scope, parameters);
Scope could be any object, even an empty one {} if you want.
By the way, I really like your use of private variables in this example, great work with the javascript. Here is a good way to write your javascript object to help with the initialization and readability
var mynamespace = {};
(function () {
function MyObject(param1, param2) {
this.initialize(param1, param2);
}
MyObject.prototype = {
initialize: function (param1, param2) {
var privateScope = {
param1: param1,
param2: param2,
callback: null
};
this.setCallback = function (c) {
privateScope.callback = c;
}
this.doSomething = function () {
if (privateScope.callback) {
privateScope.callback.call();
}
}
}
}
mynamespace.MyObject = MyObject;
}());
Then to use it
var obj = new mynamespace.MyObject("value1", "value2");
Remove the parentheses to pass the function as a variable.
doIt.setCallback( someObject.itWorked );
You can then use the callback as you would any other function.
callback( answer );
Related
I have read this answer and IIFE but I can't seem to find the correct solution to my problem.
I have a simple class here:
define(['jquery'], function($) {
// Need 'self' because someCallback() is being called with .call() and 'this' changes
var self;
function Foo(number) {
self = this;
this.someNumber = number;
}
Foo.prototype = {
someCallback: function () {
//Use self because 'this' changes to a DOM element
var num = self.someNumber;
//Do something with the num
return num * 2;
}
};
return Foo;
});
and someCallBack() is being called by a jQuery plugin using .call(). Because of this, the context changed, hence the use of the self variable.
However, this is wrong because:
define(['foo'], function(Foo) {
describe('context question', function () {
var foo1 = new Foo(1);
var foo2 = new Foo(2);
it('"this" should work', function () {
var call1 = foo1.someCallback.call(this); // 4
var call2 = foo2.someCallback.call(this); // 4
expect(call2).toBe(4); // Only works because it is 'new' last
expect(call1).toBe(2); // Fails because 'self' is taken from foo2
});
});
});
How exactly should I wrap the self variable to make this code work?
You could probably just use the revealing module pattern and declare it as a "global" variable (local to the module):
define(['jquery'], function($) {
var someNumber;
function Foo(number) {
someNumber = number;
}
Foo.prototype = {
someCallback: function () {
return someNumber * 2;
}
};
return Foo;
});
Two ways of calling an object method which stores its own this value include
Define the method as a nested function which references its this value in a closure which stores this value in a variable. The function defined could be anonymous or declared with a name but must be evaluated each time a class instance is created, so as to create a new Function object capturing different values of self in function scope.
Take a statically defined function object and bind its this value using bind. Bind creates a new wrapper function object each time it is called.
The first method looks like (without Jquery or Jasmine):
function Foo(number)
{ var self = this;
this.num = number;
this.someCallback = function() // method with new Foo object stored as self in function scope
{ // something with num:
return self.num * 2;
}
}
and the second method could look like
function Foo(number)
{ this.num = number
this.someCallback = this.someCallback.bind(this); // bind prototypical method as local method.
}
Foo.prototype = {
someCallback: function () {
// this value is bound by constructor;
//Do something with the num
return this.num * 2;
}
};
I have been creating several classes but I never had any that needed parameters on the class itself.
The following code works perfectly.
$(function()
{
search.anotherFunction('a', 'b');
});
search = function()
{
this.anotherFunction = function(param1, param2)
{
// do whatever
};
var public = { anotherFunction: anotherFunction }
return public;
}();
But now I would like to pass parameters inside search in order to avoid passing the same parameters to all the functions.
$(function()
{
search('front/file.php').anotherFunction('a', 'b');
});
search = function(url)
{
this.anotherFunction = function(param1, param2)
{
// use here the 'url' parameter
};
this.anotherFunctionB = function(param1, param2)
{
// use here the 'url' parameter
};
var public = { anotherFunction: anotherFunction,
anotherFunctionB: anotherFunctionB }
return public;
}();
This doesn't work and the console outputs the error.
Uncaught TypeError: object is not a function
It means that search isn't a function but yes a class name and therefore can't receive params?
To start with, the way you're creating your "classes" is incorrect, and ends up creating global variables: Inside the call to your anonymous function, because of the way you call it, this will refer to the global object*, so this.anotherFunction = ... will create a global variable called anotherFunction, because properties on the global object are global variables.
If you want to keep using your current pattern with minimal changes, then don't use this.xyz = ... with your functions, use var instead:
var search = function()
{
var anotherFunction = function(param1, param2)
{
// do whatever
};
var public = { anotherFunction: anotherFunction }
return public;
}();
Also note that you were falling prey to The Horror of Implicit Globals by not declaring search; I've added a var to declare it.
Your second example, with the changes above, would work if you didn't call the outermost function and just assigned the function to the search variable, then called it later:
var search = function(url)
{
var anotherFunction = function(param1, param2)
{
// use here the 'url' parameter
};
var anotherFunctionB = function(param1, param2)
{
// use here the 'url' parameter
};
var public = { anotherFunction: anotherFunction,
anotherFunctionB: anotherFunctionB }
return public;
}; // <== Note, no () here
Now search refers to a function, which we can call like this:
var x = search("http://example.com");
x.anotherFunction(...); // Will have access to the URL
* Why does this refer to the global object when you call your anonymous function? Because you call it without doing anything to set this to something else, and you're using loose mode. (I know you're using loose mode because if you were using strict mode, this would be undefined and so this.anotherFunction = ... would fail.)
Side note: I would recommend you stop using public as a variable name, as it's a future reserved word and has been since at least ES3.
You can use JavaScript closures here. Check out the below approach:
search = function()
{
return function (url) {
this.anotherFunction = function(param1, param2)
{
// use here the 'url' parameter
};
this.anotherFunctionB = function(param1, param2)
{
// use here the 'url' parameter
};
var public = { anotherFunction: anotherFunction,
anotherFunctionB: anotherFunctionB }
return public;
}
}();
search('front/file.php').anotherFunction('a', 'b');
Consider following class and calling foo method: (jsFiddle: http://jsfiddle.net/dpvbd9LL/2/)
function MyClass() {
this.Prop = "Hello";
}
MyClass.prototype.foo = function () {
var self = this;
$("<p>" + self.Prop + "</p>").appendTo("#result");
}
function sampleMethod(callback) {
// do magic stuff
callback();
}
function executeMethod() {
var myClass = new MyClass();
sampleMethod(function() {
myClass.foo();
});
sampleMethod(myClass.foo);
}
(function() {
executeMethod();
})();
The output:
Hello
undefined
As you can see, there is a big difference between calls:
sampleMethod(function() {
myClass.foo();
});
sampleMethod(myClass.foo);
Why that happens? How to write a class to prevent such a situation?
This is caused by the fact that sampleMethod(myClass.foo); pass function of myClass but not in class context, if you test the current object this, you will see that is window, the global one.
If you declare sampleMethod in the object context, you could do something like that.
You can solve this by passing the parent scope to the anonymous function executioner, like this:
function sampleMethod(callback, scope) {
if(scope) scope[callback]();
else callback();
}
function executeMethod() {
var myClass = new MyClass();
sampleMethod(function() {
myClass.foo();
});
sampleMethod("foo", myClass);
}
The problem is that you are trying to pass a function of a -for the sampleMethod- unexisting scope. So if you pass both you can call them as you need to.
I have the following piece of code:
function initValidation()
{
// irrelevant code here
function validate(_block){
// code here
}
}
Is there any way I can call the validate() function outside the initValidation() function? I've tried calling validate() but I think it's only visible inside the parent function.
function initValidation()
{
// irrelevant code here
function validate(_block){
console.log( "test", _block );
}
initValidation.validate = validate;
}
initValidation();
initValidation.validate( "hello" );
//test hello
Hope that you are looking for something like this
function initValidation()
{
// irrelevant code here
this.validate = function(_block){
// code here
}
}
var fCall = new initValidation()
fCall.validate(param);
This will work.
Hope this addresses your problem.
You can call validate from within initValidation. Like this.
function initValidation()
{
// irrelevant code here
function validate(_block){
// code here
}
return validate(someVar);
}
validate is not visible to anything outside of initValidation because of its scope.
Edit: Here's my suggestion of a solution.
(function() {
function validate(_block){
// code here
}
function initValidation()
{
// irrelevant code here
return validate(someVar);
}
function otherFunctions() {
// ...
}
// initValidation = function
}());
// initValidation = undefined
All of your functions will be hidden to anything outside the function wrapper but can all see each other.
This invocation will return function statement, which is function validate.
So you can invoke directly after the first invocation.
function initValidation() {
// irrelevant code here
return function validate(_block) {
// code here
}
}
initValidation()();
I know this is an old post but if you wish to create a set of instances that you wish to work with that reuse the code you could do something like this:
"use strict";
// this is derived from several posts here on SO and ultimately John Resig
function makeClassStrict() {
var isInternal, instance;
var constructor = function(args) {
if (this instanceof constructor) {
if (typeof this.init == "function") {
this.init.apply(this, isInternal ? args : arguments);
}
} else {
isInternal = true;
instance = new constructor(arguments);
isInternal = false;
return instance;
}
};
return constructor;
}
var MyClass = makeClassStrict();// create "class"
MyClass.prototype.init = function(employeeName, isWorking) {
var defaultName = 'notbob';
this.name = employeeName ? employeeName : defaultName;
this.working = !!isWorking;
this.internalValidate = function() {
return {
"check": this.working,
"who": this.name
};
};
};
MyClass.prototype.getName = function() {
return this.name
};
MyClass.prototype.protoValidate = function() {
return {
"check": this.working,
"who": this.name
};
};
var instanceBob = MyClass("Bob", true);// create instance
var instanceFred = MyClass("Fred", false);// create instance
var mything = instanceFred.internalValidate();// call instance function
console.log(mything.check + ":" + mything.who);
var myBobthing = instanceBob.protoValidate();
console.log(myBobthing.check + ":" + myBobthing.who);
I know this thread's been here for quite some time but I thought I'd also leave my 0.02$ on how to call inner functions from outside their scope (might benefit somebody).
Note that in any place, a better design decision should be taken into consideration rather than some hackish workaround which will bite you back later.
How about using function expressions instead of function statements and making use of the global scope.
var innerFn;
function outerFn() {
innerFn = function(number) {
return number ** 2;
}
}
outerFn();
console.log(innerFn(5));
// if there's more complex code around and you could write this defensively
if (typeof innerFn !== 'undefined') {
console.log(`we are squaring the number 5 and the result is: ${innerFn(5)}`);
} else {
console.log('function is undefined');
}
Or, you can make use of closures:
function outer() {
// initialize some parameters, do a bunch of stuff
let x = 5, y = 10;
function inner() {
// keeps references alive to all arguments and parameters in all scopes it references
return `The arithmetic mean of the 2 numbers is: ${(x + y) / 2}`;
}
return inner;
}
innerFn = outer(); // get a reference to the inner function which you can call from outside
console.log(innerFn());
Create a variable outside the parent function, then in the parent function store your required function in the variable.
Var Store;
Function blah() {
Function needed() {
#
}
Store = needed;
}
As a minor variation of Esailija's answer, I did this:
function createTree(somearg) {
function validate(_block) {
console.log( "test", _block );
}
if (somearg==="validate") { return validate; } // for addNodes
// normal invocation code here
validate(somearg);
}
function addNodes() {
const validate = createTree("validate");
//...
validate( "hello" );
}
createTree("create");
addNodes();
//validate("illegal");
so validate() is now perfectly shared between createTree() and addNodes(), and perfectly invisible to the outside world.
Should work.
function initValudation() {
validate();
function validate() {
}
}
Function definition:
function initValidation() {
// code here
function validate(_block){
// code here
console.log(_block);
}
return validate;
}
Call it as below:
initValidation()("hello");
function initValidation()
{
function validate(_block){
console.log(_block)
// code here
}
// you have to call nested function
validate("Its Work")
}
// call initValidation function
initValidation()
I have JS code roughly like this:
function myObject()
{
this.a = 13;
this.fetchData = function()
{
alert(this.a);
getData(this.processData);
}
this.processData = function(data)
{
// do stuff with data
alert(this.a);
}
this.fetchData();
}
function getData(callback)
{
// do async request for data and call callback with the result
}
My problem is: The function fetchData has access to my a variable via the this keyword, but the other function processData does not when called by getData. I understand why this happens, but don't know how to work around it.
How would you approach this problem preferably in OOP style? (The function getData has to be available to multiple classes)
Two options:
1) Have getData accept a context parameter (usually called context or thisArg) and use callback.apply(context, ...) or callback.call(context, ...) to call it. So:
function getData(callback, context) {
// ...when it's time to call it:
callback.call(context, arg1, arg2);
// or
callback.apply(context, [arg1, arg2]);
}
2) Create a function that, when called, will turn around and call the original callback with this set to the correct value. (This is sometimes called "binding".)
For example, using an explicit closure:
this.fetchData = function()
{
var self = this;
alert(this.a);
getData(getDataCallback);
function getDataCallback(arg1, arg2) {
self.processData(arg1, arg2);
}
}
Or have a generic bind function to do it (which will also involve a closure, but in a nice controlled context so it's not closing over stuff you don't need). See link below for an example of a simple bind function.
More: You must remember this
I think that you only need to define "a" as a local variable so that it is in the cope of both fetchData and getData, something like this:
function myObject() {
var a = 13;
this.fetchData = function() {
alert(a);
getData(this.processData);
}
this.processData = function(data) {
// do stuff with data
alert(a);
}
this.fetchData();
}
You could also do,
function myObject() {
this.a = 13;
var that = this;
this.fetchData = function() {
alert(that.a);
getData(this.processData);
}
this.processData = function(data) {
// do stuff with data
alert(that.a);
}
this.fetchData();
}