cocos2d-iphone jsb & cocos2d-html5 compatibility: ctor, init, associateWithNative - javascript

I'm writing a cross-platform game with cocos2d (iphone jsb + cocos2d-html5) and I'm wondering how to actually make it cross-platform. Code that would work with -html5 won't necessarily work with -iphone jsb and vice versa.
Currently I'm stuck at the following (related) questions:
What's the difference between ctor and init?
When should I overload ctor, and when should I overload init?
When I should I call _super() from ctor and/or init?
When should I call .init() from ctor if I overload do ctor?
How should I instantiate objects? With var inst = new Obj(); inst.init();? Or just var inst = new Obj();? I understand there are .create() methods which make sense, but I'm asking in the case of me writing my own create methods.
When should I use associateWithNative?
I had some code that worked with the html5 version, but then I got an error saying the object was already initialized on the iPhone jsb version, so clearly I was getting something wrong. I've tried look at the MoonWarriors code but it seems to never use associateWithNative, which I thought was required, and it sometimes overloads ctor, sometimes not, sometimes calls init from the ctor, sometimes not, etc...

ad 1-5.
I've found out that overwriting ctor - even though might seem more convenient especially for somebody coming from JS world at the moment might cause problems when compiling cocos2d-js code on other platforms - if you stumble on ERROR in *: Invalid Proxy object error it might be because of the overwriting the ctor method (was in few cases for me). Also sometimes constructor methods on native classes will expect parameters that you overwrite/handle on your end for classes that inherit from native classes and it might cause some conflicts as well.
Apart of that all the differences were described by Kex - I'd say looking at provided samples and cocos2d source the safest and "Cocos2d way" would be to use combination of init methods and static factory create.
ad 6.
It is no longer required to use the associateWithNative method (you can read more here: cocos2d-js-devel)

For me it's hard to find the way out too, I have the same problem, I developed the game mostly testing on browser & now I also have lots of issues & cannot port it to iOS,.
As far as your question goes:
ctor calls constructor for the class, init initializes the new object.
You should overload ctor when subclassing, init when doing custom initialization behavior for the object of the class your
subclassing.
I'd say always, although I also noticed that this is not everywhere present at the MoonWarriors demo.
I think that's not a good practice.
var inst = new Obj(); & then inst.init() or the other way is to call var inst = Obj.create();
associateWithNative should be called in ctor
About creating objects from a class you've created, e.g. if you have a var Warrior which has _hp as a private property & you want to assign it at creation, there are 3 ways as far as I understood:
1.With Constructor:
var myWarrior = new Warrior(hp);
& then you set the _hp in the constructor ctor:function(hp)..
2.With Initialization:
var myWarrior = new Warrior();
myWarrior.init(hp);
& then you set the _hp in the initialization init:function(hp)..
3.With Factory Method:
var myWarrior = Warrior.create(hp);
& then you set the _hp in the create method which would be after the declaration of the var Warrior & it will create a new object & initialize it properly.
EDIT: Also starting from cocos2d-iphone-2.1-rc2 you'll no longer need to override ctor in order to place associateWithNative since from that build on that call is not needed.

Related

Javascript - Dependency Injection without implementation-contract (interface)

New to javascript. Let's say I have a constructor like this:
function Dependent(dependency) {
this.doSomething = function(x) {
dependency.doSomethingReal(x);
}
}
var impl = new SomeImplementation();
var dependent = new Dependent(impl);
console.log(dependent.doSomething(3));
My understanding is that there is nothing in the language that can help to ensure that impl can in fact fulfill its responsibilities (actually has a method called doSomethingReal that takes an argument).
A few questions come up:
In the constructor-function should I manually check the dependency argument to ensure that it has all the things Dependent requires?
Should I just not worry about it?
How do the other libraries deal with this situation? For example, I know there are a couple DI projects...or MVC projects that for example require their view objects to implement certain well-known-methods.
I realize that I can just pass a function into the constructor. In other words, if dependency was a function then we'd just invoke it. Is that the safest way to do it? I don't think that's what the MVC projects do...also there are times that it makes sense to pass in an object.
You can use instanceof to check if an object is an instance of another one.
For example, within your code:
function Dependent(dependency) {
// here we could check that dependency is an instance of SomeImplementation
if (!(dependency instanceof SomeImplementation))
throw "dependency must be an instance of SomeImplementation";
this.doSomething = function(x) {
dependency.doSomethingReal(x);
}
}
var impl = new SomeImplementation();
var dependent = new Dependent(impl);
console.log(dependent.doSomething(3));
In javascript it's also common to use the 'duck typing' method to validate an object. For example:
console.log (
'isABird' in duck &&
'walks' in duck &&
'swims' in duck &&
'quacks' in duck ?
"juhm... I'm pretty sure we're dealing with a duck" :
"meh... since I a expect a duck to be a bird, walks, swims and quacks, then this buddy is definitely not a duck"
);
Well, as far as I have understood it, Duck Typing would be the natural way to deal with this problem in JavaScript since JavaScript is not a strict typed language.
In consequence this would mean that you indeed just accept, that JavaScript is loosely typed and that you will have to deal with runtime-errors when you try to access a method on an object that does not have this method. (Your option 2)
Apart from that, you could use a pattern that tries to simulate interfaces or abstract classes in JavaScript which works like you have suggested in option 1 and which is described here in detail:
http://www.addyosmani.com/resources/essentialjsdesignpatterns/book/#decoratorpatternjavascript
(Chapter "Pseudo-classical Decorators")
But this would also just lead to runtime-errors. The exceptions might just rise up a little earlier but not at "compile time". So in both designs you will need to test your application in order to find type-related-errors.
So I tent to accept that Duck Typing.

Can you extend an object that has access to private properties with a function that can also access those private properties?

I am creating an object inside of an enclosure. Also in the enclosure are private properties that the object's functions can access - and this works as expected.
My issue: I want others to be able to extend my object with functions of their own (functions from a different context), but those functions will also need access to the same private properties - and I have not been able to find a way to make this work.
I've tried various configurations of .call, and also wrapping their function in a new function, amongst other things. I feel like I've gotten close to a solution, but have just fallen short.
Here's a bit of simplified example code that accurately reflects my situation:
//extension object
//fn2 can be any function, with any number of arguments, etc.
var obj1 = {};
obj1.fn2 = function (s1, s2){ console.log(priv); };
//actual object
var obj2 = (function (){
//private property
var priv = "hello world";
//return object
var obj3 = {};
//return object's native fn (works)
obj3.fn = function (s){ console.log(priv); };
//extension happens here - but is obviously not correct
obj3.fn2 = obj1.fn2;
//return object
return obj3;
})();
//try output
obj2.fn("goodbye world"); //works
obj2.fn2("goodbye world", "thx 4 teh phish"); //fails
Any insight would be appreciated. And I totally understand if what I want just isn't possible - but it sure seems like it should be :P
EDIT: Thank you all for the responses. I fully understand that the properties are more easily accessed as public, and that normally inherited objects won't have access to them otherwise. However, since the new function is being attached to the original object I have to believe there's a way to use the original context and not the context the new function was created in.
Now, I'm the first to say that eval is evil - and, in fact, I've never used it, or even considered using it, before. However, I'm trying everything I can think of to make this work - and I stumbled across this (seemingly) working solution:
obj3.fn2 = eval(obj1.fn2.toString());
So, if I check to make sure that obj1.fn2 is a typeof function, is there any way this could be harmful to my code? It doesn't execute the function, so I can't see how - but maybe I'm missing something?
Javascript doesn't have a "protected" analog. You either get super private or completely public. From here you can choose to:
Reconsider your class design, and have the subclasses depend only on the public interface of the parent class.
Add getter and setter functions to the public interface. Not necessarily the best thing though as you might just as well make the properties public (besides best practice issues and whatnot)
Just use public properties instead. This is the "natural" way to do OO inheritance in Javascript and is usually not a problem if you use a donvention like adding an underscore to the beggining of the name. As a bonus you can use the prototypal inheritance feature (it is nice knowing how to use this instead of only closure-based classes)
function Base(){
this._priv = "Hello world"
};
Base.prototype = {
fn: function(){
console.log(this._priv);
}
}
var obj2 = new Base();
obj2.fn = function(){ ... }
I hate to answer my own question - seems like a bit of a faux pas - but c'est la vie. (because I woke up French today?)
So, while I found that the eval() solution I presented last night in the edit to my original question does seem to be a valid solution, and a proper use of eval for retaining the object's context within the new function, it is far from perfect.
Firstly, it works in FF, but both IE and Chrome seem to hate it (those were the next ones I tried, and I quit trying others after they both failed). Though I'm sure it could probably be made to work across browsers, it seems like a hassle.
Secondly, it does give quite a bit of power to the new function, and as I look at my code more I do like the idea of controlling exactly what these new functions being added to my object get access to.
Thirdly, .eval() is typically pretty slow - and it turns out that .apply() (which is typically faster) just may work well enough.
This is because I realized at some point last night that no new functions on this object will need to set any of the private variables (at least, I'm fairly certain they won't) - and .apply() works fine to pass the values through for them to read.
I'm sure there's more to it than just those 3 things, but for now I think I'm going to go with more of a 'wrapper' solution - something like this:
var f = function (){
var fauxThis = {};
fauxThis.priv = priv;
obj1.fn2.apply(fauxThis, arguments);
};
obj3.fn2 = f;
//(To be placed where I had "obj3.fn2 = obj1.fn2;")
I am certainly willing now to consider the use of eval() in very specific cases - and may even revisit this specific use of it before I make my final decision of which direction to take. (especially if I can think of a case where the private value would need to be set)
Thanks all for your input!
The quickest and easiest solution is to prefix any supposedly private properties with the underscore (_).
Personally I like to bottle my private properties into a single object which would be placed on the object, like so:
obj.publicProp = 20;
obj._.privateProp = true;
I wouldn't worry so much about it though, the underscore is basically a universal symbol for private so those using the script will know that it's private and shouldn't be touched. Or, better yet, just leave it out of the public documentation ;)
There are other methods and you can use which do emulate "true" protected variables, but they're not the best as they avoid garbage collection, and can be clunky to use.

Is John Resig's OO JavaScript implementation production safe?

For a long time I have been throwing around the idea of making my JavaScript more object oriented. I have looked at a few different implementations of this as well but I just cannot decide if it is necessary or not.
What I am trying to answer are the following questions
Is John Resig's simple inheritance structure safe to use for production?
Is there any way to be able to tell how well it has been tested?
Besides Joose what other choices do I have for this purpose? I need one that is easy to use, fast, and robust. It also needs to be compatible with jQuery.
Huh. It looks much more complicated than it needs to be, to me.
Actually looking more closely I really take exception to what it is doing with providing this._super() whilst in a method, to call the superclass method.
The code introduces a reliance on typeof==='function' (unreliable for some objects), Function#toString (argh, function decomposition is also unreliable), and deciding whether to wrap based on whether you've used the sequence of bytes _super in the function body (even if you've only used it in a string. and if you try eg. this['_'+'super'] it'll fail).
And if you're storing properties on your function objects (eg MyClass.myFunction.SOME_PRIVATE_CONSTANT, which you might do to keep namespaces clean) the wrapping will stop you from getting at those properties. And if an exception is thrown in a method and caught in another method of the same object, _super will end up pointing at the wrong thing.
All this is just to make calling your superclass's method-of-the-same name easier. But I don't think that's especially hard to do in JS anyway. It's too clever for its own good, and in the process making the whole less reliable. (Oh, and arguments.callee isn't valid in Strict Mode, though that's not really his fault since that occurred after he posted it.)
Here's what I'm using for classes at the moment. I don't claim that this is the “best” JS class system, because there are loads of different ways of doing it and a bunch of different features you might want to add or not add. But it's very lightweight and aims at being ‘JavaScriptic’, if that's a word. (It isn't.)
Function.prototype.makeSubclass= function() {
function Class() {
if (!(this instanceof Class))
throw 'Constructor function requires new operator';
if ('_init' in this)
this._init.apply(this, arguments);
}
if (this!==Object) {
Function.prototype.makeSubclass.nonconstructor.prototype= this.prototype;
Class.prototype= new Function.prototype.makeSubclass.nonconstructor();
}
return Class;
};
Function.prototype.makeSubclass.nonconstructor= function() {};
It provides:
protection against accidental missing new. The alternative is to silently redirect X() to new X() so missing new works. It's a toss-up which is best; I went for explicit error so that one doesn't get used to writing without new and causing problems on other objects not defined like that. Either way is better than the unacceptable JS default of letting this. properties fall onto window and mysteriously going wrong later.
an inheritable _init method, so you don't have to write a constructor-function that does nothing but call the superclass constructor function.
and that's really all.
Here's how you might use it to implement Resig's example:
var Person= Object.makeSubclass();
Person.prototype._init= function(isDancing) {
this.dancing= isDancing;
};
Person.prototype.dance= function() {
return this.dancing;
};
var Ninja = Person.makeSubclass();
Ninja.prototype._init= function() {
Person.prototype._init.call(this, false);
};
Ninja.prototype.swingSword= function() {
return true;
};
var p= new Person(true);
p.dance(); // => true
var n = new Ninja();
n.dance(); // => false
n.swingSword(); // => true
// Should all be true
p instanceof Person &&
n instanceof Ninja && n instanceof Person
Superclass-calling is done by specifically naming the method you want and calling it, a bit like in Python. You could add a _super member to the constructor function if you wanted to avoid naming Person again (so you'd say Ninja._super.prototype._init.call, or perhaps Ninja._base._init.call).
JavaScript is prototype based and not class based. My recommendation is not to fight it and declare subtypes the JS way:
MyDerivedObj.prototype = new MySuperObj();
MyDerivedObj.prototype.constructor = MyDerivedObj;
See how far you can get without using inheritance at all. Treat it as a performance hack (to be applied reluctantly where genuinely necessary) rather than a design principle.
In an a highly dynamic language like JS, it is rarely necessary to know whether an object is a Person. You just need to know if it has a firstName property or an eatFood method. You don't often need to know if an object is an array; if it has a length property and some other properties named after integers, that's usually good enough (e.g. the Arguments object). "If it walks like a duck and quacks like a duck, it's a duck."
// give back a duck
return {
walk: function() { ... },
quack: function() { ... }
};
Yes, if you're making very large numbers of small objects, each with dozens of methods, then by all means assign those methods to the prototype to avoid the overhead of creating dozens of slots in every instance. But treat that as a way of reducing memory overhead - a mere optimisation. And do your users a favour by hiding your use of new behind some kind of factory function, so they don't even need to know how the object is created. They just need to know it has method foo or property bar.
(And note that you won't really be modelling classical inheritance in that scenario. It's merely the equivalent of defining a single class to get the efficiency of a shared vtable.)

Access Silverlight's createObject via Javascript's new operator?

feel free to skip down to the question below
I'm trying to create a bridge so a huge javascript application can be replaced by a new Silverlight-based rewrite as smoothly as possible.
In the legacy application, there is this JS class:
function LatLng(lat, lng, url) { /* snip... */ }
And it is being used a lot throughout my customer's codebase like this:
var ll = new LatLng(12, 34, '567');
However, as the bridge in Silverlight is required to be backwards-compatible and that it be done with maximum maintainibility, I decided to re-create the LatLng class as a ScriptableType in Silverlight:
[ScriptableType]
public class LatLng { /* similar snipped stuff ... */ }
As I go about re-implementing the methods in the class in Silverlight/C#, going so far as to asked and implement this delegate util. Which had allowed me to wire calls from the Javascript side right into the Silverilght runtime with 0 change, by doing this:
var x = new LatLng() // <-- constructor now calls into Silverlight
// and ask for methods to be wired into it
Unfortunately, this approach doesn't work with property getters/setters as there is no such concept in JavaScript (at least not in every major browser yet), the only way to get property getters/setters to work is to let the Silverlight runtime be the one creating the wrapper for my class
i.e. an instance must be created from the Content.services.createObject in JavaScript:
var ll = silverlightObject.Content.services.createObject("LatLng");
This single change, will requires all existing users of the application to go-over their entire codebase in order to upgrade... not good at all
The Problem
Is there a way to re-wire the new
operator in Javascript to returns an
instance from another function
instead?
var ll = new LatLng(13, 100)
/* ^
^
should returns instance created from
silverlightObject.Content.services.createObject
*/
And there are 2 gotchas:
createObject is a Silverlight-managed function, Function.apply or Function.call does not work
The result from createObject is a wrapper, which you cannot iterate over (thus me asking for the delegate util in the first place)
I hope that there is a way out without really having to walk every customers through changing the way LatLng are created...
If you have any ideas please kindly share it here, I've been trying to get this ironed out for the last week to no avail :-(
The new command in JavaScript represents an instance of a function without actually using the base function. This is important to protect a function's inner mechanisms from interference in expectation of reuse.
To circumvent the new command I would transform the LatLng function into a method. A method is a function that is executed using dot notation for the purpose of modifying a variable with a stored value. The original LatLng function contained 3 arguments. When rewriting LatLng rewrite to take only the first two arguments so that the variable that will be activating the method can contain what was originally the third argument.
var ll.LatLng(13, 100);
But remember the variable should have a value before any method is executed against it or it is likely to throw an error. That is why I recommend the original third argument of LatLng instead be used a the value of the variable prior to use of the method.

What is the purpose of `this.prototype.constructor = this;`?

In the ASP.NET ajax library, there is a line that makes me confused.
Type.prototype.registerClass = function Type$registerClass(typeName, baseType, interfaceTypes) {
//..
this.prototype.constructor = this;
//..
}
I know that (this.prototype.constructor === this) == true, so what is significance of this line? I remove the line, and test the library with some code. It seems it is okay. What is the purpose of this line?
I'm not familiar with the asp.net libs, but:
A common pattern in Javascript, especially when trying to simulate class based systems, is to reassign the prototype object to an instance of another object, rather than just adding properties to the prototype object JS gives you. One issue with this is that it gives you the wrong constructor - unless perhaps one resets with a 'correct' value.
My guess would be that at some point before this.prototype.constructor = this;, some object was assigned to the prototype property, which overwrote prototype.constructor. This trick is often used when inheriting object prototypes easily, but still being able to call instanceof to see whether an object instance is of a certain type.
Hard to tell anything more specific than that in this case and a seriously old question, however it might be useful to somebody.

Categories

Resources