this must be some JavaScript concept that I am not grasping yet..
For some odd reason the id of thisSound returns undefined! why??
console.log("o: "+o.id+" - "+decodeURI(soundURL));
// create sound
thisSound = soundManager.createSound({
id:o.id,
url:decodeURI(soundURL)
});
console.log("thisSound: "+thisSound.id+" - "+thisSound.url);
the console :
o: Sound0 - http://api.soundcloud.com/tracks/76673175/stream?client_id=e992d357c0914e9b65ba17f459720fc0
thisSound: undefined - http://api.soundcloud.com/tracks/76673175/stream?client_id=e992d357c0914e9c65ba17f459720fc0
The code you provided doesn't “obviously” define the id of the returned object.
// create sound
thisSound = soundManager.createSound({
id:o.id,
url:decodeURI(soundURL)
});
Let's say I write the function createSound for you:
var soundManager = {
createSound: function (options) {
// do internal magic here
createSound(options);
// return public API here
return {
getId: function () {}
}
}
};
So, my point here is that if there is a third-party function, you should follow the docs of whoever created that function, and SoundManager apparently doesn't return an object with id property defined on it. It “returns a SMSound object instance” – and what is that object, please find out in the docs.
I know nothing about the soundcloud library, although the function createSoundseems asyncronous... (It's like I/O Stuff, the most of the I/O operations in javascript -and the other languages- are async ).. Is it possible when you have called the console.log thisSound hasn't been fully created yet? Maybe you could emulate a setInterval() behaviour with a lot of time and this code works... (although I believe you should use a callback function for this).
Related
In Ruby I think you can call a method that hasn't been defined and yet capture the name of the method called and do processing of this method at runtime.
Can Javascript do the same kind of thing ?
method_missing does not fit well with JavaScript for the same reason it does not exist in Python: in both languages, methods are just attributes that happen to be functions; and objects often have public attributes that are not callable. Contrast with Ruby, where the public interface of an object is 100% methods.
What is needed in JavaScript is a hook to catch access to missing attributes, whether they are methods or not. Python has it: see the __getattr__ special method.
The __noSuchMethod__ proposal by Mozilla introduced yet another inconsistency in a language riddled with them.
The way forward for JavaScript is the Proxy mechanism (also in ECMAscript Harmony), which is closer to the Python protocol for customizing attribute access than to Ruby's method_missing.
The ruby feature that you are explaining is called "method_missing" http://rubylearning.com/satishtalim/ruby_method_missing.htm.
It's a brand new feature that is present only in some browsers like Firefox (in the spider monkey Javascript engine). In SpiderMonkey it's called "__noSuchMethod__" https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/NoSuchMethod
Please read this article from Yehuda Katz http://yehudakatz.com/2008/08/18/method_missing-in-javascript/ for more details about the upcoming implementation.
Not at the moment, no. There is a proposal for ECMAScript Harmony, called proxies, which implements a similar (actually, much more powerful) feature, but ECMAScript Harmony isn't out yet and probably won't be for a couple of years.
You can use the Proxy class.
var myObj = {
someAttr: 'foo'
};
var p = new Proxy(myObj, {
get: function (target, methodOrAttributeName) {
// target is the first argument passed into new Proxy, aka. target is myObj
// First give the target a chance to handle it
if (Object.keys(target).indexOf(methodOrAttributeName) !== -1) {
return target[methodOrAttributeName];
}
// If the target did not have the method/attribute return whatever we want
// Explicitly handle certain cases
if (methodOrAttributeName === 'specialPants') {
return 'trousers';
}
// return our generic method_missing function
return function () {
// Use the special "arguments" object to access a variable number arguments
return 'For show, myObj.someAttr="' + target.someAttr + '" and "'
+ methodOrAttributeName + '" called with: ['
+ Array.prototype.slice.call(arguments).join(',') + ']';
}
}
});
console.log(p.specialPants);
// outputs: trousers
console.log(p.unknownMethod('hi', 'bye', 'ok'));
// outputs:
// For show, myObj.someAttr="foo" and "unknownMethod" called with: [hi,bye,ok]
About
You would use p in place of myObj.
You should be careful with get because it intercepts all attribute requests of p. So, p.specialPants() would result in an error because specialPants returns a string and not a function.
What's really going on with unknownMethod is equivalent to the following:
var unk = p.unkownMethod;
unk('hi', 'bye', 'ok');
This works because functions are objects in javascript.
Bonus
If you know the number of arguments you expect, you can declare them as normal in the returned function.
eg:
...
get: function (target, name) {
return function(expectedArg1, expectedArg2) {
...
I've created a library for javascript that let you use method_missing in javascript: https://github.com/ramadis/unmiss
It uses ES6 Proxies to work. Here is an example using ES6 Class inheritance. However you can also use decorators to achieve the same results.
import { MethodMissingClass } from 'unmiss'
class Example extends MethodMissingClass {
methodMissing(name, ...args) {
console.log(`Method ${name} was called with arguments: ${args.join(' ')}`);
}
}
const instance = new Example;
instance.what('is', 'this');
> Method what was called with arguments: is this
No, there is no metaprogramming capability in javascript directly analogous to ruby's method_missing hook. The interpreter simply raises an Error which the calling code can catch but cannot be detected by the object being accessed. There are some answers here about defining functions at run time, but that's not the same thing. You can do lots of metaprogramming, changing specific instances of objects, defining functions, doing functional things like memoizing and decorators. But there's no dynamic metaprogramming of missing functions as there is in ruby or python.
I came to this question because I was looking for a way to fall through to another object if the method wasn't present on the first object. It's not quite as flexible as what your asking - for instance if a method is missing from both then it will fail.
I was thinking of doing this for a little library I've got that helps configure extjs objects in a way that also makes them more testable. I had seperate calls to actually get hold of the objects for interaction and thought this might be a nice way of sticking those calls together by effectively returning an augmented type
I can think of two ways of doing this:
Prototypes
You can do this using prototypes - as stuff falls through to the prototype if it isn't on the actual object. It seems like this wouldn't work if the set of functions you want drop through to use the this keyword - obviously your object wont know or care about stuff that the other one knows about.
If its all your own code and you aren't using this and constructors ... which is a good idea for lots of reasons then you can do it like this:
var makeHorse = function () {
var neigh = "neigh";
return {
doTheNoise: function () {
return neigh + " is all im saying"
},
setNeigh: function (newNoise) {
neigh = newNoise;
}
}
};
var createSomething = function (fallThrough) {
var constructor = function () {};
constructor.prototype = fallThrough;
var instance = new constructor();
instance.someMethod = function () {
console.log("aaaaa");
};
instance.callTheOther = function () {
var theNoise = instance.doTheNoise();
console.log(theNoise);
};
return instance;
};
var firstHorse = makeHorse();
var secondHorse = makeHorse();
secondHorse.setNeigh("mooo");
var firstWrapper = createSomething(firstHorse);
var secondWrapper = createSomething(secondHorse);
var nothingWrapper = createSomething();
firstWrapper.someMethod();
firstWrapper.callTheOther();
console.log(firstWrapper.doTheNoise());
secondWrapper.someMethod();
secondWrapper.callTheOther();
console.log(secondWrapper.doTheNoise());
nothingWrapper.someMethod();
//this call fails as we dont have this method on the fall through object (which is undefined)
console.log(nothingWrapper.doTheNoise());
This doesn't work for my use case as the extjs guys have not only mistakenly used 'this' they've also built a whole crazy classical inheritance type system on the principal of using prototypes and 'this'.
This is actually the first time I've used prototypes/constructors and I was slightly baffled that you can't just set the prototype - you also have to use a constructor. There is a magic field in objects (at least in firefox) call __proto which is basically the real prototype. it seems the actual prototype field is only used at construction time... how confusing!
Copying methods
This method is probably more expensive but seems more elegant to me and will also work on code that is using this (eg so you can use it to wrap library objects). It will also work on stuff written using the functional/closure style aswell - I've just illustrated it with this/constructors to show it works with stuff like that.
Here's the mods:
//this is now a constructor
var MakeHorse = function () {
this.neigh = "neigh";
};
MakeHorse.prototype.doTheNoise = function () {
return this.neigh + " is all im saying"
};
MakeHorse.prototype.setNeigh = function (newNoise) {
this.neigh = newNoise;
};
var createSomething = function (fallThrough) {
var instance = {
someMethod : function () {
console.log("aaaaa");
},
callTheOther : function () {
//note this has had to change to directly call the fallThrough object
var theNoise = fallThrough.doTheNoise();
console.log(theNoise);
}
};
//copy stuff over but not if it already exists
for (var propertyName in fallThrough)
if (!instance.hasOwnProperty(propertyName))
instance[propertyName] = fallThrough[propertyName];
return instance;
};
var firstHorse = new MakeHorse();
var secondHorse = new MakeHorse();
secondHorse.setNeigh("mooo");
var firstWrapper = createSomething(firstHorse);
var secondWrapper = createSomething(secondHorse);
var nothingWrapper = createSomething();
firstWrapper.someMethod();
firstWrapper.callTheOther();
console.log(firstWrapper.doTheNoise());
secondWrapper.someMethod();
secondWrapper.callTheOther();
console.log(secondWrapper.doTheNoise());
nothingWrapper.someMethod();
//this call fails as we dont have this method on the fall through object (which is undefined)
console.log(nothingWrapper.doTheNoise());
I was actually anticipating having to use bind in there somewhere but it appears not to be necessary.
Not to my knowledge, but you can simulate it by initializing the function to null at first and then replacing the implementation later.
var foo = null;
var bar = function() { alert(foo()); } // Appear to use foo before definition
// ...
foo = function() { return "ABC"; } /* Define the function */
bar(); /* Alert box pops up with "ABC" */
This trick is similar to a C# trick for implementing recursive lambdas, as described here.
The only downside is that if you do use foo before it's defined, you'll get an error for trying to call null as though it were a function, rather than a more descriptive error message. But you would expect to get some error message for using a function before it's defined.
I have tried searching through a lot of S.O. pages but nothing has touched EXACTLY on this top while also NOT USING JQUERY.... I am trying to stick to pure JavaScript as I want to learn it 115% before advancing my current knowledge of JQuery.
I have an object called ScreenResizeTool like this...
function ScreenResizeTool(currImg) {
window.addEventHandler('resize', function() {
listen(currImg);
}, true);
}
and a method like this...
ScreenResizeTool.prototype.listen = function(currImg) {
//Random Code For Resizing
};
My trouble is probably obvious to an experienced JavaScript user but I am having trouble not making this into a messy dirty awful OOP set. I have done various tests to show and prove to myself that the this inside the addEventHandler changes when it becomes bound to the window. This much I assumed before testing but I was able to see that once window.resize event happens the listen method is gone and not a part of the global window variable....
I have also tried adding a this capture such as this.me = this inside the object constructor however it also couldn't see the me variable once it ran. Once the window took the function over it no longer knew anything about the me variable or any reference to my class methods....
I am aware that I could separate this differently but my goal here is to learn how to fully encapsulate and use as many clean OOP structures as possible as I just came from the .NET world and I need it in my life.
I am also aware that I could make messy calls and or store this object or access to the methods inside the window variable but that seems outright wrong to me. I should be able to fully encapsulate this object and have its events and methods all implemented in this class structure.
I also know that the currImg variable is not going to be seen either but lets start small here. I assume once I figure out my incorrect train of thought on scope for JavaScript I should be fine to figure out the currImg problem.
I know there's 1000 JavaScript programmers out there waiting to rip me a new one over asking this simple question but I gotta know...
Thoughts anyone?
this inside a function bound to a DOM Object (like window) will always refer to that object.
this inside a constructor function will always refer to the prototype.
A common practice to circumvent the this issue, as you mentioned, is to cache it in a variable, often called self. Now you want the variables and properties of your object available after instantiation, so what you need is the return keyword, more specifically to return the parent object itself. Let's put that together:
function ScreenResizeTool() {
var self = this;
// method to instantiate the code is often stored in init property
this.init = function() {
window.addEventListener('resize', function() {
self.listen(); // self will refer to the prototype, not the window!
}, true);
};
return this;
}
ScreenResizeTool.prototype.listen = function() { // Dummy function
var h = window.innerHeight, w = window.innerWidth;
console.log('Resized to ' + w + ' x ' + h + '!');
};
Pretty easy huh? So we have our prototype now, but prototypes can't do anything if there's not an instance. So we create an instance of ScreenResizeTool and instantiate it with its init method:
var tool = new ScreenResizeTool();
tool.init();
// every time you resize the window now, a result will be logged!
You could also simply store the listen & init methods as private functions inside your constructor, and return them in an anonymous object:
function ScreenResizeTool() {
var listen = function() { ... };
var init = function() { ... };
// in this.init you can now simply call listen() instead of this.listen()
return {
listen: listen,
init: init
}
}
Check out the fiddle and make sure to open your console. Note that in this case I'd rather use the first function than the second (it does exactly the same) because prototypes are only useful if you have multiple instances or subclasses
The whole concept of this in JavaScript is a nightmare for beginners and in my code I usually try to avoid it as it gets confusing fast and makes code unreadable (IMHO). Also, many people new to JavaScript but experienced in object-oriented programming languages try to get into the whole this and prototype stuff directly though the don't actually need to (google JS patterns like IIFE for example as alternatives).
So looking at your original code:
function ScreenResizeTool(currImg) {
window.addEventHandler('resize', function() {
listen(currImg); // global function listen?
}, true);
}
ScreenResizeTool.prototype.listen = function(currImg) {
//Random Code For Resizing
};
First off, you probably mean addEventListener instead. In its callback you refer to listen but as a global variable which would look for it as window.listen - which doesn't exit. So you could think to do this:
function ScreenResizeTool(currImg) {
window.addEventHandler('resize', function() {
this.listen(currImg); // what's this?
}, true);
}
As you want to use the prototype.listen function of ScreenResizeTool. But this won't work either as the event listener's callback function is called with a different this and not the this that is your function scope.
This is where something comes in which makes most programmers cringe, you have to cache this, examples from code I've seen:
var _this = this;
var that = this;
var _self = this;
Let's just use the latter to be able to refer to the function within the event callback:
function ScreenResizeTool(currImg) {
var _self = this;
window.addEventListener('resize', function() {
_self.listen();
}, true);
}
Now this will actually work and do what you want to achieve: invoke the prototype.listen function of ScreenResizeTool.
See this JSFiddle for a working example: http://jsfiddle.net/KNw6R/ (check the console for output)
As a last word, this problem did not have anything to do with using jQuery or not. It's a general problem of JS. And especially when having to deal with different browser implementations you should be using jQuery (or another such library) to make your own code clean and neat and not fiddle around with multiple if statements to find out what feature is supported in what way.
I'm very inexperienced with javascript so forgive me if this is really obvious...
I'm using the TodoMVC example found here (http://todomvc.com/architecture-examples/backbone/) as a foundation for a Cordova project. The trouble that I'm having is combining this with the Camera and Geolocation plugins, I get errors calling any functions in js/views/app-view.js from within the Camera/Geolocation callback functions. I'm assuming it's a problem of context but I don't know enough about javascript to fix it.
For example, the TodoMVC project adds new items using this line of code, in js\views\app-view.js:
app.todos.create(this.newAttributes());
I'm trying to combine this with the camera function to take a picture with a phone's camera, then add a new todo item with the picture stored in it. Everything works fine except when I try to have that above line of code in the camera callback function, at the bottom like this:
onCameraSuccess: function(imageData) {
// Stores image data in a hidden field to be used later. Not best method but it works
document.getElementById('imageData').value = "data:image/jpeg;base64," + imageData;
// This line should create a new item
app.todos.create(this.newAttributes());
},
It gives the error "Undefined is not a function", seemingly referring to "this.newAttributes()". Again it seems like this is a matter of context, because that very same line works almost anywhere else in the same script.
OnCameraSuccess is a callback function from the Camera's getPicture function:
Camera: function() {
navigator.camera.getPicture(this.onCameraSuccess, this.onCameraFail, { quality: 50,
destinationType: Camera.DestinationType.DATA_URL,
targetWidth: 250,
targetHeight: 250,
correctOrientation: true
});
},
Likewise, a function for Geolocation requires two callback functions, for success and errors, but I can't find an acceptable way to refer to the other functions that doesn't give a TYPE_MISMATCH_ERR that says those aren't functions.
onDeviceReady: function() {
//This line calls the geolocation function and specifies the two callback functions, but it thinks they don't exist
navigator.geolocation.watchPosition(this.onLocationSuccess, this.onLocationError, {enableHighAccuracy : true});
},
onLocationSuccess: function(position) {
// map logic
},
onLocationError: function(error) {
alert('code: ' +error.code+ '\n' + 'message: ' +error.message + '\n');
},
They're right below the onDeviceReady function, but for some reason it can't find them. this.onLocationSuccess doesn't work (even though that's how it refers to all of its other functions), self.onLocationSuccess doesn't work... Again, it seems like a matter of context, but I can't figure it out.
Any ideas? I don't even know enough about javascript to know if I'm explaining this adequately, so feel free to yell at me about that too.
The value of this in JavaScript depends on how a function is called. For example, this:
var obj = {
f: function() { console.log(this) }
};
obj.f();
will put obj in the console but this:
var obj = {
f: function() { console.log(this) }
};
var f = obj.f;
f();
will (usually) dump window into the console even though the same function is being called. This this behavior confuses almost everyone when they start using JavaScript. In your case, the documentation doesn't say anything about what this will be in the getPicture callbacks so this is probably going to be window instead of your object.
If you need a particular this with a callback function in JavaScript, you usually have to arrange it yourself. One way to do that is to stash the desired this in a variable and use an anonymous function:
var _this = this;
navigator.camera.getPicture(
function(imageData) { _this.onCameraSuccess(imageData) },
...
);
A cleaner way (especially when there are arguments to your functions) is to bind the function to the desired this using $.proxy, _.bind, Function.prototype.bind, or similar utilities that come with pretty much every JavaScript toolkit. For example, given this:
var obj = {
f: function() { console.log(this) }
};
var f1 = $.proxy(obj.f, obj);
var f2 = _(obj.f).bind(obj);
var f3 = obj.f.bind(obj);
Calling f1(), f2(), or f3() will all dump obj into the console. Underscore is the typical toolkit with Backbone so this would be common:
navigator.camera.getPicture(
_(this.onCameraSuccess).bind(this),
_(this.onCameraFail).bind(this),
{ ... }
);
Underscore also provides _.bindAll, this is commonly used within initialize to bind several functions in-place:
initialize: function() {
_.bindAll(this, 'onCameraSuccess', 'onCameraFail');
//...
}
and then you can use this.onCameraSuccess without worry about the binding:
navigator.camera.getPicture(
this.onCameraSuccess,
this.onCameraFail,
{ ... }
);
Using _.bindAll in initialize would probably be the most common approach in Backbone.
Since you are passing this as a reference to the camera function it is being overridden by camera's context with the current context of the application.
Make a clone of the current context like
var currentContext = this;
currentContext.onCameraSuccess,
currentContext.onCameraFail
This is applicable where ever the application control is moving from one context to other eg:backbone view to underscore functions and moving back to callback function etc.
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 want to do something that in a classical object oriented language like Java, C# etc. is very easy to do. I simply want to access a property of an instantiated object. The object is globally scoped in the browser's window object, and provided by the twitter #anywhere API.
For my code examples, assume you have already logged the user in.
If I were using java for instance, I would say (assuming all fields were public:
twttr = new twtter();
String screenName = twtter.currentUser.data('screen_name');
For some reason, this is way hard in Javascript. I've gotten a workaround working where inside the anonymous method that the twitter anywhere API is using, I set the value I want to a DOM element, and fish it out later. This is ugly though. I just want to access it directly.
Here's what I have so far, which doesn't even pass syntax checks in eclipse:
function AnywhereFacade()
{
var twitterReference;
window.twttr.anywhere
(
return function(T)
{
twitterReference = T;
};
)
getValue(propertyToGet)
{
return twitterReference.currentUser.data(propertyToGet);
}
};
var anywhereFacade = AnywhereFacade();
var screen_name = anywhereFacade.getValue("screen_name");
alert("screen name is: " + propertyGetter);
Please help! Why is Javascript so hard to use anyway? What I'm trying to do is use a closure I think.
Thanks!
I have done something similar in my app since I am using the Facebook JavaScript SDK and Twitter SDK and want to provide a consistent interface to access both. So I namespace the variables under App. For twitter anywhere, this is how the variable is captured.
window.App = {};
twttr.anywhere(function(T) {
App.Twitter = {
getValue: function(property) {
return T.currentUser.data(property);
},
getPublicTimeline: function() {
return T.Status.publicTimelime();
}
};
});
We are calling the anywhere function and passing it a callback function. The callback function is needed because the anywhere library might not be loaded at this point. By passing the entire function, we are saying that this function should be executed whenever the anywhere library is loaded.
Now when the library does load, this function will execute, define the App.Twitter property which contains a getValue function. The anywhere or T object is captured in the closure.
If you now call,
App.Twitter.getValue("screen_name");
the actually anywhere object (T), will be used to get the screen_name property.
this is all I needed to do.
document.getElementById('messagePanel').innerHTML = "loading...";
window.twttr.anywhere(function(T)
{
document.getElementById('messagePanel').innerHTML = "screen_name: " + T.currentUser.data('screen_name');
});
this made me realize my issue was just that I had to use a callback for when twitter returned from the async call. that helped me solve my initial problem of how to wrap it for gwt.