I have 2 JS files - one with the functions I would like to access and the other that I'd like to call the function with.
(function($) {
var Place = function() {
var Location = function(id, duration, check) {
//Should access this function
}
}
})(jQuery);
I'm trying to access it with:
Place.Location(markerId, 600);
But all I'm getting is that it's not defined. Simple issue but can't quite figure this one out.
As it's a jQuery plugin, maybe there's a way I can access it via another method?
$.fn.place = function(params) {
var len = this.length;
return this.each(function(index) {
var me = $(this),
key = 'place' + (len > 1 ? '-' + ++index : ''),
instance = (new Place).init(me, params);
});
};
The way you are defining Location, it is a private variable inside the function Place. If you want to access it as an attribute of Place, you should replace var Location = ... with this.Location = ...
It's going out of scope. Because you wrapped your Place object in function($) {}, now anything outside that wrapper will no longer have access to variables inside the wrapper. If $ stands for jQuery, it should be a global anyways and you can take the wrapper out.
The solution is a combination of the other two answers.
You define Place as a variable in the (anonymous) function. It can't be used outside the scope of that function. (This function doesn't use jQuery, either, so the wrapper is unnecessary).
Place is a function. It executes code that sets local variable Location to a function, but doesn't export that function, so Location() is inaccessible outside the Place function.
You probably mean to make Place an object (instead of a function), and give it a Location method. Here's one way to write it:
var Place = {
Location: function(id, duration, check) {
// do something with id, duration, & check
}
};
// execute
Place.Location(someId, someDuration, someCheck);
(It doesn't look like you've posted all your code, like the Place.init() method, but there are plenty of ways to write this so that it works correctly; this should solve your immediate problem.)
Related
The question may not be clear, so I will clear that here. I am using require.js to import a script in script. Here is a piece of code :
var vr = {};
vr.example = function(func) {
return require(["https://example.com"], func);
};
So, now I am able to call it by :
vr.example( function() { .... });
But, I am thinking about not writing the function everytime I have to call it. I would like to write something like this :
vr.example({ ... });
And the result should be same. But I can't understand how to do it. So please help
Thanks in advance.
The thing you want can't be done in JavaScript ! But there is a way to do, by making an interpreter. Here is a basic example. I don't really recommend it, well I am showing you just a possibility ;)
window.InterpretData = function() {
var el = document.querySelectorAll("script[type='text/test']") // You can change it anyway !
for(var i = 0; i < el.length; ++i) { // You can use i++ instead of ++i, but ++i is much optimised for this function, watch out their differences in the internet.
var val = el[i].innerHTML
var crt = document.createElement("script")
crt.id = "InterpretedScript"
document.getElementsByTagName("body")[0].appendChild(crt) // Creating a new script element
val = val.replace(/\.example\(\{([\S\s]*?)\}\)/gm, function(_, a) { // Wish you are familiar with regular expressions
a = ".example( function() {" + a + "})"
document.getElementById("InterpretedScript").innerHTML += a;
}
}
}
Now you can do :
<!DOCTYPE html>
<body>
<script type="text/test">
// Defining
var vr = {};
vr.example = function(func) {
return require(["https://example.com"], func);
};
// Calling
var.example({ ... })
<script>
<script>
new InterpretData()
</script>
</body>
</html>
Output :
vr.example({ ... }) converts to vr.example( function() { ... })
Well, remember this example is just to give you an idea about a possibility to solve your problem. It's not the perfect solution though you can't again declare the "example()" to any other constant / variables, that contain different parameters ! So, the only way lies to either use ES6's fat arrows (=>) or just declare the function earlier and go on reusing it ! If you have to support old browsers than go with reusing technique shown by #mbojko, or just go with ES6's fat arrows, said earlier by #deceze. So, want do you think ?
So, you want to pass a block of code not wrapped with a function? Short answer: you can't do that in JavaScript. And require.js does expect a callback function at any rate.
If the callback function is reusable, you can declare it once and reuse it like:
function myReusableCallback(args) {
//...
}
vr.example(myReusableCallback);
And that's pretty much it.
Because the require() function returned from the vr.example() takes a callback function and since this callback function is usually provided by the invocation of vr.example, it, therefore, means you can't necessarily call it with and object as you want to. So you can only use an object if there is no callback expected by the require() an or if you have a static function that you want to be executed all the time then you can implement the function inside of the vr.example and then just pass the object which you need to use inside the function.
It's not possible because {} is not a function, it's an object.
You can try it out yourself using typeof({}) and compare it to typeof(() => {}) or typeof(function() {})
I'm trying to call a js function within another one, but use the argument to specify the function. ie depending on the argument passed, it will call a different function
function toggle(n){
if (sessionStorage['toggle'+n]== 0){
check+n();
}
else
}
So, for example, if the argument 'Balloons' was passed as n, then it will call the function checkBalloons(). "check+n();" is not currently working here. Sorry for my lack of simple js syntax!
If the function is defined in the global scope (browser) you can do:
window["check"+n]();
or some tenants like Node.js you would access it from global object.
global["check"+n]();
if it is a part of some other object then you would do the same.
obj["check"+n]();
Functions and properties defined on an object can be accessed using [] convention as well. i.e obj["propFuncName"] will give you reference to it, so in case of methods you add () to invoke it.
If the function is global, you would do this:
window["check" + n]();
or, you could put your function in an object like so:
myNamespace = {};
myNamespace.checkSomething = function(){ /* ... */ }
// call it like this:
myNamespace["check" + n]();
The answers thus far are correct, but lack explanation.
In JavaScript, you cannot call a function by name when that name is a string. What you can do is retrieve a value from an object by name, and if that value happens to be a function, you can then call it. For example:
var myObject = {};
myObject.myFunction = function() { alert('test!'); };
// Get the property on `myObject` called `myFunction`
var theFunctionLookup = myObject['myFunction'];
// Since that property was a function, you can call it!
theFunctionLookup();
In the browser, functions that are defined in the global scope are attached to the window object. For example, this works:
function myFunction() { alert('test'); }
var theFunctionLookup = window['myFunction'];
theFunctionLookup();
You can shorten the last two lines into one:
function myFunction() { alert('test'); }
// Look up and call the function in one line.
window['myFunction']();
For the same reasons, you can use a dynamically-calculated string to look up functions.
function checkBalloon() {
alert('checking balloon');
}
function toggle(n){
if (sessionStorage['toggle'+n]== 0){
window['check' + n]();
check+n();
}
}
toggle('Balloon');
if you do this way:
if (sessionStorage['toggle'+n]== 0){
window["check" + n]();
}
will work
Let's start from the code:
function say(name) {
var ghost=function () {
function ghost() {
alert('!');
};
return body;
};
eval("var body=''+"+name+';');
eval(name+('=('+ghost).replace('body', body)+')();');
eval(name+'();');
}
function Baal() {
if ('undefined'===typeof ghost) {
say('Baal');
return;
}
ghost();
}
say('Baal'); // or just Baal();
Looks like that saying the devil's name invoke his presence (well, maybe he needs somebody for spiritual possession) ..
As you can see the ghost doesn't exist along with Baal, but we can invoke it since there're evals in say(name).
say(name) reassigns Baal to its code body as a closure and makes it captured a ghost method, that's how things work. But I'm trying to avoid eval ..
So .. let me reword the question:
How do I make a nonexistent(and not a member or global) method invocable without using eval?
Let me rephrase your question, just to make sure I’ve got it. Given a function, you want to put a new variable in its scope, without that scope being the global scope or a scope shared between the caller and the subject, without using eval (or the equivalent new Function and other hacks depending on the environment).
You can’t.
In the case you just mentioned, you could define one function, base(), that uses arguments.callee.caller.
Don’t do that.
The short answer: You don't.
That scope is not available. If you were to attach the scope then it would be available inside of the scope used. You could then access the method handles. I assume this is not what you were looking for, but here is what that would look like. demo
function say(name){
var methods = {};
methods.Baal = function(){
alert("!");
};
return methods[name];//this could invoke as well: methods[name]()
}
var handle = say('Baal');
handle();
What your evals break down to is something along these lines (although with dynamic content from string building - this is the end result)
function say(name) {
var Baal = (function () {
function ghost() {
alert('!');
};
return function(){
if ('undefined'===typeof ghost) {
say('Baal');
return;
}
ghost();
}
})();
Baal();
}
say('Baal'); // or just Baal();
Note that the meat of what happens here is from the function Baal, namely that it calls a hardcoded ghost() which in turn calls a hardcoded alert. Why go through all of this trouble to access a hardcoded function?
A better way would be to inject this function as a callback which expects some parameters to be injected.
jsFiddle Demo
function say(callback){
var params = "!";
if( typeof callback == "function" ){
callback(params);
}
}
say(function(params){
alert(params);
});
It's very difficult for me to read through your code and figure out what you are trying to accomplish with it, but it appears that you are trying to introduce a variable into the current scope so that you can call it. You cannot do this in javascript with the method that you demonstrated. Scoping only ever "flows down". By that I mean that a variable or function defined within a function will only be available to that function and any other functions defined therein. Your function named ghost will only ever be available within the function where it is defined, regardless of when that function is evaluated.
What you can do, however, is write a function that returns a function. You can then call that function and assign the result to a variable in the scope where you want to expose functionality. Doing that would look something like this.
function defineSpecialAlert() {
return function(name) {
alert(name + "!");
};
}
var newlyDefinedMethod = defineSpecialAlert();
newlyDefinedMethod("Baal");
So if I understand, it seems like you want to create an alias of eval: Something like
#Note this code is not intended as a solution, but demonstrates
#an attempt that is guaranteed to fail.
#
function myAlias(ctx) {
eval.call(ctx, 'var ghost = 42');
}
myAlias(this);
alert(ghost);
Javascript allows many funky sleight-of-hand tricks especially with closures, but this is maybe the one impossible thing that javascript cannot do. I've tried at length to do this exact same thing, and I can tell you that you'll run into nothing but complaints from the browser, saying that eval cannot be re-contexted or aliased in any way.
I'm looking to encapsulate my javascript inside a namespace like this:
MySpace = {
SomeGlobal : 1,
A: function () { ... },
B: function () { ....; MySpace.A(); .... },
C: function () { MySpace.SomeGlobal = 2;.... }
}
Now imagine that instead of a few lines of code, I have about 12K lines of javascript with hundreds of functions and about 60 globals. I already know how to convert my code into a namespace but I'm wondering if there's a quicker way of doing it than going down 12K lines of code and adding MySpace. all over the place.
Please let me know if there's a faster way of doing this.
Thanks for your suggestions.
I like to wrap up the namespace like so. The flexibility is huge, and we can even separate different modules of the MySpace namespace in separate wrappers if we wanted too. You will still have to add some sort of _self. reference infront of everything, but at least this way you can change the entire name of the namespace very quickly if need be.
You can see how with this method you can even call _self.anotherFunc() from the 1st module, and you'll get to the second one.
(function (MySpace, $, undefined) {
var _self = MySpace; // create a self-reference
_self.test = function () {
alert('we got here!');
_self.anotherFunc(); // testing to see if we can get the 2nd module
};
_self = MySpace; // reassign everything just incase
}(window.MySpace = window.MySpace || {}, jQuery));
$(function () {
MySpace.test(); // call module 1
MySpace.callOtherModule(); // call module 2
});
// Here we will create a seperate Module to the MySpace namespace
(function (MySpace, $, undefined) {
var _self = MySpace; // create a self-reference
_self.callOtherModule = function () {
alert('we called the 2nd module!');
};
_self.anotherFunc = function () {
alert('We got to anotherFunc from the first module, even by using _self.anotherFunc()!');
};
_self = MySpace; // reassign everything just incase
}(window.MySpace = window.MySpace || {}, jQuery));
jsFiddle DEMO
Wrap a function body around your existing code to use as scope, hiding everything from global - this will allow you to do internal calls without pasting Namespace. prefix everywhere, neatly hide things you don't want everyone else to see, and will require minimal changes as well.
After that, decide what functions you want to "export" for everyone and assign them to properties of object you want to use as "namespace".
I plan on using JSONP to call an external web service to get around the fact that I don't want to create a global function that could potentially conflict with the calling page. I thought that creating a random function name and passing it up would work. Something like this:
<script src="www.foo.com/b?cb=d357534">
where cb is the callback function name, the server would return
d357534({my json data});
What I want to know is how to create the random function name, I'm sure I could use eval but is this the best way to go about it?
Essentially, what I am trying to do is this:
var d + Math.floor(Math.random()*1000001) = function(){...
This should do what you want. You need to save the function name somewhere so that you can pass it to the server, but you can do that inside of a local scope to avoid polluting your global namespace.
var functionName = 'd' + Math.floor(Math.random()*1000001);
window[functionName] = function() { ... }
To make a randomly-named global variable you could do this:
window['randomvar' + Math.floor(Math.random()*1000001)] = function() { ... };
now of course you've got the problem of remembering the random name somewhere. You could make up a random name for that variable too. Then you'd have to remember the name of that variable, so that you could look at its value and then know how to find your function. After a while, things are going to start getting weird.
Why don't just use a counter and increment it each time you need a new function:
var name = "callback" + window.COUNTER++;
window[name] = function() { ... };
If you want to avoid littering the global namespace with too many references you could (and should) attach the counter and callbacks to a single global object:
var JSONP = window.JSONP;
var name = "callback" + JSONP.COUNTER++;
JSONP[name] = function() { ... };
In this case you could call the method like this:
JSONP.callback_12(json);
Of coarse you have to initialize the JSONPobject and the COUNTER variable first.