Spider Monkey dynamically created script (from JS), attached to an object - javascript

I am working on an application that utilizes Spider Monkey to run our JS. I only have a single object type (JSNode) that acts as an interface to a complex DOM consisting of various objects with properties and methods. Everything is created and registered on the fly. I am running into a problem where I have an object with a function that needs to be associated dynamically. The problem is when I run the script from the context of the associated object, the NewResolve (which I usually use to recognize and define the properties), as far as I can tell cannot know it's a function definition to allow me to define the function on the fly. I don't get the sense that JS_CompileScript will correctly build the function and associate it with the HandleObject. And of course I can't utilize JS_CompileFunction without doing all of the script parsing myself, which to me feels like the point of utilizing spider monkey in the first place, but maybe I am wrong.
Any ideas or guidance on this issue?

Related

Adding properties to DOM objects and functions, and to the window object?

I've read a number of questions that state it is unwise to add properties to DOM element objects; and they seem to make a great deal of sense. The best suggestion I came across to accomplish the same end was to use a Weak Map with the DOM node reference as the key.
That led me to wonder about adding properties to function objects. Is that "safe" to do or should another object or map be used for this also. I'm referring to functions on the window object. Can the property names I add clash with names in the function object in the future?
That brings up a related matter I've been trying to understand which is that some claim that the window object is so cluttered up that it ought not to be added to and scripts should be modules now. Modules appears to be more isolated than my limited experience with simple namespaces. Is there anything to be gained through using scripts of type module over just declaring another object and making your functions methods of that object? That object would still be added to the window object.
Thank you.
That led me to wonder about adding properties to function objects. Is that "safe" to do or should another object or map be used for this also. I'm referring to functions on the window object. Can the property names I add clash with names in the function object in the future?
It's not safe in that, if you do it, others could do it too. For example:
// Your code
RegExp.description = 'some description for the constructor!';
setTimeout(() => {
console.log(RegExp.description);
});
// Someone else's code
RegExp.description = "someone else's description";
The only consolation is that it's pretty unlikely for such a thing to happen.
Similarly, it's pretty unlikely for some random English word that one library creates for itself on the window collides with another word that another library creates for itself on the window - but it's not impossible. For that reason
That object would still be added to the window object.
can be seen as slightly less than optimal on huge pages, where collisions are a real possibility.
Is there anything to be gained through using scripts of type module over just declaring another object and making your functions methods of that object?
Yes, see above. If all of your code is in module scripts, there should be no need to put any object onto the window, in most cases. In addition to the above, module scripts often make projects easier to manage because they make all dependencies explicit through the use of import statements. They're also very easily integrated into a build process like Webpack - and build processes allow for all sorts of neat things that aren't easily done otherwise.

Are methods within a function object not implicitly linked as a member?

semi-novice programmer here (on and off with C++ for years, dabbling with C# mostly with Unity) and when creating objects and methods within objects it's to be expected that that method is a member of that object.
If I create a new object I can access the function with dot notation object.method.
For Javascript it appears that isn't the case?
I read somewhere about it being something like a first class object (not sure what that means) and I have to explicitly say that the method is a part of the object.
So for example in JS
function testObject() {
let x = whatever;
function testMethod() {
}
}
Is a failure, it will not work. testObject has no idea testMethod is a member.
I have to use
this.testMethod = function() {}
before it can be registered.
I just want to be sure cause I can't really find much info even from youtube videos and websites.
I want to fully grasp knowledge of why for once instead of just shrugging my shoulders and just letting it be.
If what I've stated is true can someone give me a heads up why JS is different in this regard? And if there are any other pitfalls with JS objects that I might not notice from a C programmer background.
Thanks.
Edit:
Thanks for the comments. This is also why programming can be such a pain. you look for info, want to delve into it and get such conflicting information. If you google does javascript have classes, first thing you'll see is javascript doesn't have classes (well this is obviously a lie delving deeper). Why say that when it is provably false? Don't care if it's not class based. Don't say there are no classes (Not you specifically just shouting out to the internet).
I know how to declare an object literal and was looking at the youtube video
https://www.youtube.com/watch?v=PFmuCDHHpwk&list=PLTjRvDozrdlxEIuOBZkMAK5uiqp8rHUax&index=2
to brush up on the basics, get my head back in the game and learn a new language. Doubled down on researching just what it all means and it's sticking for once (but I digress). He discusses about Object literals then changes his code into something similar that I presented thag he called a function object.
Is that not a thing?
Am I doing it wrong?
Apparently what I have is not an object?
Though the definition of an object is a group of data in a single unit which includes member variables and methods that work on that data.
Should I forget what I'm seeing and just stick with object literals?

"Some JS files act more like libraries - they [...] never manipulate QML component instances directly" - middle ground?

Quote from Defining JavaScript Resources In QML:
Some JavaScript files act more like libraries - they provide a set of helper functions that take input and compute output, but never manipulate QML component instances directly.
What if I want a JS file that both:
manipulates QML component instances (that are passed to it as arguments)
doesn't get a copy of its code and data stored for every QML component instance that imports it?
I could get the "no data stored on every instance" part by, well, not putting global variables in the JS file. But, for some strange reason, a copy of the "code" part seems to be stored for every instance as well. I don't get why this is but I want to know whether I can circumvent it, and at what cost.
I think that the line you quoted from the documentation is incorrect, or at least very poorly worded; you can still have a JS file with .pragma library in it and manipulate QML objects that are passed in as arguments to its functions. The sentence was probably referring to the previous section.
To share data across qml files, consider using a qml Singleton.
For data sharing purpose, I would not suggest using .pragma library (#Mitch) for following reasons.
.pragma library js provides limited functionality in qml object manipulation. While simple qml object manipulation (like property reading/writing) could be done with a .pragma library js, it does NOT allow creating/deleting qml objects (as you can in regular non-library js). It will suck when your application becomes dynamic.
.pragma library creating only one instance is merely an optimization in Qt implementation. It's never guaranteed that Qt creates exactly one instance, nor that your data would actually be shared.
Well, .pragma library is not designed to do data sharing work from the very beginning. Just, don't try to do it this way.

Call class member of another JSAPI object from root JSAPI object (created by prepscript)

Looking at this page from firebreath.org I found this excerpt:
You can return a JSAPI instance to a JavaScript caller in the form of a JSAPIPtr and use that to make calls on a different JSAPI object, e.g. plugin().method1().method2() will call method1() on the Root JSAPI object and method2() on the JSAPI object returned in the first call.
Any examples?
My objective:
I want to call another class's (which is also implementing FB:JSAPIAuto) member (say ABCAPI:FB:JSAPIAuto ) through my root JSAPI object which is created automatically by the prepscript i.e. same as described above by creating the JSAPIPtr of the class. Am I right here?
Also, whether the JSAPI object of ABCAPI that was created by me should also get a plugin reference or not?
I went through this page too, but am not able to follow.
Till now, I could create a method returning FB::JSAPIPtr which had the value of another Class (implementing FB::JSAPIAuto) pointer.
A little example would be a great help here!
*Another doubt:
How do you expose a simple c++ class(not extending any Firebreath class) to the Javascript so that i can access its members?*I found a v8 Javascript engine thing.Don't have any idea about this. I want my plugin to be available for all other browsers too apart from chrome.Do i need this?
Okay, there are a couple of things here. First, the prep script doesn't create JSAPI objects for you -- that was fbgen. This is an important distinction because you will run the prep script many times, but fbgen you only run once to create the project skeleton.
Next, you're making this far more complicated than it needs to be. A JSAPI object is just a class object; if you have a reference to it in C++, you can call a member of the other class just like you would any other object. There is nothing magical about it, except maybe when you give it to javascript, and then just that the methods you expose to javascript are the only ones you can use.
What you haven't explained is where the reference to the second JSAPI object comes from. Are you passing it in from javascript? If so, things get more tricky, and you'll have to call it using ->Invoke like you would a method on any other javascript object passed in from the page. Did you create it in c++? If so, then you just use it like any other object.
As to whether or not the hypothetical ABCAPI object should get a plugin reference or not, that's totally up to you. The Root JSAPI object doesn't need one, it's just for your convenience in case you want to access the plugin.
For examples, go look at FBTestPlugin in the firebreath code base. It has examples of nesting JSAPI objects and such.

Can I JsDoc a return value for a Factory method properly?

I am looking for ways to build a system where I do not need to load all source files in order to play the application. My past project had over 200 .js files (I am not kidding!) and it was really slow to do a page reload to test features you develop.
I looked into Dojo and I see how they have built a dynamic loader. Basically you just load a single core component, then everything else will be loaded when needed.
I am thinking about implementing a factory method in my application that allows me to construct new instances of objects in JavaScript:
var user = MyApp.create('MyApp.model.User');
instead of:
var user = new MyApp.model.User();
The reasoning why I'd like to ditch the new keyword is because the former approach allows me to dynamically load the component in a lazy-loaded fashion if it does not exist already. The factory method can just look if the target object is defined, and if it is not, it would load it.
The only problem I am facing with that is the fact IDEs no longer understand user is type of MyApp.model.User which is certainly not a good thing.
Is there a way to solve this dilemma? Can I somehow JsDoc that factory method?
If your factory method returns various types of objects, based on the argument, then you can't document the return value for the factory method itself (using #returns) in a way that IDEs can make sense of. At least I'm not aware of any way to do it.
But you can solve your problem, easily, by annotating the variable which holds the object, like this:
/**
* #type {MyApp.model.User}
*/
var user = MyApp.create('MyApp.model.User');
Of course, I don't know if your particular IDE can interpret this. Mine can (using Komodo).

Categories