In this Udacity video on game development, the instructor mentions that Javascript allows us to create an object by giving a handle to its definition. Then, it says that to allow this "an overloaded object definition will update a hash table with a pointer to its class definition".
I quite know what a hash table, a pointer, an overloaded method, and the factory pattern are, but I cannot make sense of this mysterious statement, or of the rest of the explanation.
"Hash table" is just a fancier way of saying "ordinary Javascript object". What the instructor means by "handle to its definition" is just another way of saying "the function that acts as a constructor for the class".
Ultimately, what he means by the statement you mentioned:
each overloaded entity definition will update a hash table with a pointer to its class definition
is the following:
All "subclasses" of Entity will register their constructor function in a single shared hashmap/object using the key which is the type value.
This allows you to get the constructor function (in other words, the function to call new on, which will return an instance of that entity) for any type by accessing gGameEngine.factory[type].
This is nice, because whenever a programmer adds a new type of entity, so long as they remember to add a new entry to that gGameEngine.factory object with the correct key, then that object will contain everything you need to construct any type of supported object.
So the code that iterates over the JSON structure generated by the level editor can create an instance of any type the same way, using something like:
var typeConstructor = gGameEngine.factory(tileSpec.type),
instance;
if (typeConstructor) {
instance = new(typeConstructor)(tileSpec /* or whatever params */);
}
This is similar to the code visible at around the 1 minute mark of the video you linked to.
Make sense now?
I think all he's saying is that you can map references to functions / objects / variables inside another object. He's using one type of property accessor syntax, but I think he's overcomplicating things by using language like 'handle' and 'hash table'.
var someClass = function () {
// stuff
}
var containingObject = {};
containingObject["someClass"] = someClass;
// same thing as
containingObject.someClass = someClass;
Then you can instantiate the class by calling the containingObject property.
var classInstance = new containingObject["someClass"]()
// or
var classInstance = new containingObject.someClass()
Related
I am writing an object pool class that holds onto old unused objects, and when a new one is needed can use one of its reserves (Without the expensive creation of objects). However, I want to be able to save any data to this pool (not limited to something such as extends Poolable). The problem is that most object pools require something like this:
class MyData {
constructor(str) {
this.reset(str)
}
reset(str) {
this.str = str;
}
}
So that when a new instance is needed, the pool can call oldInstance.reset(prams). As stated before, I do not want this (Working with lots of third party tools that I am not feeling like writing wrappers for), so my data looks like this:
class MyData {
constructor(str) {
this.str = str;
}
}
When the pool needs to reset an instance, I need to be able to call the constructor as a function and set the this value to the instance that is being wiped.
This is super easy with old classes that used function/prototype syntax when they were made:
const MyClass = function(str) {
this.str = str;
}
// Reset an instance
const instance = new MyClass("foo");
MyClass.apply(instance, ["bar"])
// done
However when I do that for classes, it complains that you can not use a class without the new keyword. How do I go about doing this?
Fiddle: https://jsfiddle.net/wuqek405/
Edit:
As I said, most object pools need a reset function. I am trying to use the constructor as this function, because it is supposed to “set up” the instance. Another solution would be to generate this reset function based on the class. However, I want it to be as fast as possible, so terribly hacky solutions such as stringifying the class and evaling the constructor wouldn’t be optimal.
This is not possible. A class is not callable1, only constructable - which means creating a new object. This was new in ES6, which overhauled the inheritance model of classes and introduced super. Also, ES2022 will introduce class fields, which also get created during construction without being mentioned in the constructor code.
Your only option is to use only ES5 function-based classes, a transpiler, or writing explicit reset methods.
1: technically, it is callable (typeof C == 'function'), but [[Call]] will always throw an exception
How can I get name of object's class? I mean "Process" in this example
I see two ways to get it. First one is to write a getter in this class like
getClassName(){return "Process"}
But I suppose it will be an error if I try to call this method in object which doesn't belong to this class and hasn't got method like this.
And second one is using object instanceof Process. But maybe there is some way to make it better and more correctly?
You can get it from name on constructor:
console.log(object.constructor.name);
When you do ex = new Example, for instance, in the normal course of things that makes Example.prototype the prototype of the object that was created (ex), and the object inherits a constructor property from that object that refers back to the constructor (Example).
I say "in the normal course of things" because there are various ways those normal relationships can be changed. For instance, code could have overridden the constructor property with an own property on the object (ex.constructor = somethingElse;). To rule out that specific scenario, you could use:
console.log(Object.getPrototypeOf(object).constructor.name);
Live example:
class Example1 {
}
const e1 = new Example1();
console.log(e1.constructor.name); // "Example1"
class Example2 {
constructor() {
this.constructor = "I'm special";
}
}
const e2 = new Example2();
console.log(Object.getPrototypeOf(e2).constructor.name); // "Example2"
The TC39 committee members that specify JavaScript were happy enough to use the instance's constructor property in Promises when building the new promise that then and catch return (see Step 3 here which goes here and reads constructor from the instance) (and in some other places), so you wouldn't be out on your own if you also used it. They don't even go to the prototype of the instance.
But yes, just for completeness, even if you go to the prototype for it, it's still possible for that to lead you astray, since the prototype's constructor property can also be mucked with:
class Example {
}
Example.prototype.constructor = Object; // Why would anyone do this? People are weird.
const e = new Example();
console.log(Object.getPrototypeOf(e).constructor.name); // "Object"
It's also possible to redefine the name on a function:
class Example {
}
// Why would someone do this? People are weird.
Object.defineProperty(Example, "name", {
value: "flibberdeegibbit"
});
const e = new Example();
console.log(Object.getPrototypeOf(e).constructor.name); // "flibberdeegibbit"
So...caveat user.
Note that the function name property is new as of ES2015 (as is class syntax). If you're using class syntax via a transpiler, it may or may not set name correctly.
Generally object instanceof Process is desirable if it's known for sure that object originates from this class/function. There may be situations where this won't be so. The appearance of several Process can be caused by iframes, multiple package versions, etc.
There is name property that already exists in regular functions class constructors. A known pitfall is that it will be mangled in minified code, so it is generally useless in browser JS, and its use can be considered an antipattern. name cannot be reassigned (in some browsers), so a separate property is needed to identify the class.
The proper way is to avoid this problem
But I suppose it will be an error if I try to call this method in object which doesn't belong to this class and hasn't got method like this.
is to use a getter:
class Process {
get className() { return 'Process'; }
...
}
Or a property:
class Process {
...
}
Process.prototype.className = 'Process';
As a result, there may be several Process classes that have Process className identifier. This may be desirable or not. While instanceof associates class instance with one particular class.
Use .constructor.name on the object. Each object's constructor by default refers to his creation function, which has a name property. It returns the name of the function.
class SomeClass {
}
const obj = new SomeClass();
console.log(obj.constructor.name);
Use the name property as follows:
class Process {}
console.log(Process.name);
const process = new Process;
console.log(process.constructor.name);
This is the same way it works for normal prototypal inheritance using functions.
from the page https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Details_of_the_Object_Model:
When JavaScript sees the new operator,
it creates a new generic object and
passes this new object as the value of
the this keyword to the WorkerBee
constructor function. The constructor
function explicitly sets the value of
the projects property, and implicitly
sets the value of the internal
proto property to the value of WorkerBee.prototype. (That property
name has two underscore characters at
the front and two at the end.) The
proto property determines the prototype chain used to return
property values. Once these properties
are set, JavaScript returns the new
object and the assignment statement
sets the variable mark to that object.
So basically if we have this function:
function Bee(first_name, second_name){
this.FirstName=name;
this.SecondName=name;
}
I want to know what is the difference between doing something like var bee1 = new Bee("qwe", "asd"); vs:
var bee1={};
bee1.__proto__=Bee.prototype;
var r=Bee.call(bee1, "qwe", "asd");
if(r!==undefined){
bee1=r;
}
For one thing, var bee1 = new Bee("qwe", "asd"); is cross-browser compatible. Some browsers won't let you mess around with an object's __proto__ field -- IE being one of those.
For another, it's less code, and makes more sense at first glance.
Also, in the second example, as of the first line, you've created bee1 but haven't initialized it. As of the second line, the system will consider it a Bee, but it's still not built like one. If something goes awry in the constructor, or anywhere else between creation and construction, you can end up with a half-baked Bee. This as opposed to new Bee(...), which either gives you back a properly constructed Bee or throws an exception.
I'm a beginner w/ Javascript. I'm looking at the following code that someone else wrote:
function MeetingPage()
{
MeetingPage.colors = new Object();
}
...
var meeting = new MeetingPage();
From what I've seen, I believe that the MeetingPage function creates an object that later someone holds onto in meeting. What is the MeetingPage.colors? Is the MeetingPage prefix some kind of global? Is it a "this" pointer of some kind?
Any suggestions would be appreciated.
It's actually just bad code. MeetingPage.colors = new Object(); is setting a property called colors on the MeetingPage function, i.e:
function MeetingPage(){ }
MeetingPage.colors = {};
Which is perfectly valid since all functions in JavaScript are objects. The problem is that if you have multiple instances of meeting page:
var meeting1 = new MeetingPage();
var meeting2 = new MeetingPage();
The code you posted will reset colors. It should either should be written as this.colors = {}, or it should be set outside of the function as in my first snippet.
This talk was really helpful when I got into different object patterns in javascript. Example code is included in the second link (the video introduces it).
http://alexsexton.com/?p=94
http://alexsexton.com/inheritance/demo/
http://alexsexton.com/?p=51
Of course, you should also definitely read http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742
HTH
This is the JavaScript syntax for creating Class Properties. Note, it is a class property not an instance property, that means it is shared across all instances of the class. (If you know C++ this is like a class static) However, I didn't think it was valid to put a class property inside the constructor itself. I would think that every time a new MeetingPage is created the colors class property will get wiped out.
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.