Given class A and class B, where class B inherits from class A ...
// Define class A
dojo.declare("mynamespace.A",null,{
myMethodA: function() { this.myMethodB() }
});
// Define class B
dojo.declare("mynamespace.B",mynamespace.A,{
myMethodB: function() {}
});
Is it legal to call this.myMethodB() in the scope of class A (parent class)?
I have seen this in a piece of software and I do not understand it. I know that in Java, this is not possible unless you typecast A to B. But is dojo any different?
Your buzzword of this question would be this.inherited(arguments);
Your question goes for calling a method which is not in the current inheritance scope - and would by a true object oriented programmer be called invalid.. However it is possible (still) since the loader declared everything in global scope, e.g. you can access any module via mynamespace.X and then add prototype.theMethod.
Once you have inheritance as in mynamespace.B all of the functionalities of both A and B are 'this' scoped. It is simply like a merged hash of stuff, say for all methods and variables in A do set instance B[key] = property A[key].
However if you would encounter an override where the property is prototyped for both 'class' A and B - there is a mechanism in the declare / construct chain which allows for calling 'super' (or parent class, following your notation).
For the special property constructor it is allways so, that the inheritance bubbles[period].
For any methods that are declared only once, you cannot with respect of yourself call it if it is not an inherited method - and it will then be accessible via 'this'
For any methods which have overrides, the function 'this.inherited(arguments);' will send you upwards, one tick to the current parent class of callee. Look at the extended fiddle here
var AClass = dojo.declare("mynamespace.A", null, {
constructor: function(args) {
this.overriddenMethod();
},
overriddenMethod: function() {
}
});
var BClass = dojo.declare("mynamespace.B", [AClass], {
constructor: function() { },
overriddenMethod: function() {
// call super before anything else is processed in this method
// by placing following call you can control function callflow
this.inherited(arguments);
}
});
// will call A.constructor, then A.overriddenMethod
new AClass();
// will call B.constructor, A.constructor, B.overriddenMethod and then
// A.overriddenMethod via the call to super
// in B.overriddenMethod which A.constructor
// calls (note that A.constructor callflow 'aims' B.override not A.override)
new BClass();
There is no static compilation in JavaScript, therefore, as #akonsu has mentioned yet, it is technically possible, but it's not a pattern to follow:
var a = new mynamespace.A();
a.myMethodA(); // ilegal: Uncaught TypeError: Object [object Object] has no method 'methodB'
var b = new mynamespace.B();
b.myMethodA() // legal
You can also execute method/function in a given scope in JavaScript, i.e. as a method of given object:
a.myMethodA.call(b); // legal as `this` inside `myMethodA` will be referencing to object `b`
Practically, I think mynamespace.A may emulate abstract class with abstract method myMethodB as you know it from Java. Class mynamespace.A when subclassed, the subclass should implement myMethodB. But doing it this way is very error prone and I would do it in a more robust manner:
// Define class A
dojo.declare("mynamespaca.A", null, {
myMethodA: function() {
this.myMethodB();
},
myMethodB: function() {
// abstract method
console.warn("Abstract method [myMethodB] was not implemented.");
// or: throw new Error("Abstract method [myMethodB] was not implemented.");
}
});
// Define class B
dojo.declare("mynamespace.B", mynamespace.A, {
myMethodB: function() {
// implement abstract method here
}
});
You can call any method using the prototype object.
myMethodA: function() { mynamespace.B.prototype.myMethodB(); }
Here is a working example:
http://jsfiddle.net/cswing/7cBJm/
Related
I have a function called Observable. As per all functions, I can call certain methods on the function, that even though they do not exist directly on the function, JS moves 'down the prototypical chain' and gets the method on the function. Example of such methods is 'toString()'
function Observable(forEachy) {
this._forEachy = forEachy;
}
console.log(Observable.toString()) // "function Observable(forEach) {this._forEach = forEach;}"
Now, when I set Observable.prototype to a new object and define some methods in that object, and call those methods on Observable, it throws an error.
Observable.prototype = {
forEachy: function (onNext) {
return onNext();
}
}
console.log(Observable.forEachy(()=>"Hi, John")) // error: Observable.forEachy is not a function
But I can call those methods on the prototype and it works just fine.
console.log(Observable.prototype.forEachy(()=>"Hi, John")); // "Hi, John"
Setting a new instance to Observable just works fine.
const abc = new Observable("HI");
console.log(abc.forEachy(()=>"Hello world")); // "Hello world"
Please, why is that?
Also, apart from passing in the argument received in the constructor to the newly created object, what else does the statement this._forEachy = forEachy do?
const abc = new Observable("HI");
console.log(abc._forEachy) // "HI"
Your example works as expected. You should consider getting more information about Prototypes in JavaScript.
When you declare something as Function.prototype = function(){}, it works similar to methods in OOP programming. In oop you can't call Class.method(), can you? You have to first create an instance to call this method. However, keep in mind that there is a lot of differences between OOP and prototype inheritance. In reality, your "prototype" is not the abstraction. It's the existing object :)
Though, if you want to follow this way, you can create class and define static method:
class Observable {
static forEachy(){
// your code here
}
}
and then:
Observable.forEachy()
Javascript's new Proxy feature offers some interesting features for debugging. For example you can "defend" an object by putting it behind a Proxy with a get handler that throws if you access an undefined property. This helps catch typos and other kinds of mistakes.
This could be used something like this:
class Something {
constructor()
{
this.foo = "bar";
allObjects.push(this);
}
};
function defend(o)
{
return new Proxy(o, DebugCheckHandler);
};
let rawSomething = new Something();
let defendedSomething = defend(rawSomething);
Code can be diligently written to only deal in terms of defendedSomething. However in this example, the Something constructor passes this somewhere else (to allObjects). This ends up having the same effect as using both rawSomething and defendedSomething across the codebase.
Problems then arise from the fact the proxy reference does not equal its original reference, since rawSomething !== defendedSomething. For example, allObjects.includes(defendedSomething) will return false if it contains rawSomething, because includes does a strict === check.
Is there a good way to solve this without making too many changes to the code?
Instead of letting the new operator call [[Construct]], which produces a real instance, you can:
Create an object which inherits from the prototype of the constructor.
Use it as the handler of the proxy.
Call the constructor passing the proxy as the this value.
function Something() {
this.foo = "bar";
allObjects.push(this);
}
function defendIntanceOf(C) {
var p = new Proxy(Object.create(C.prototype), DebugCheckHandler);
C.call(p);
return p;
};
let defendedSomething = defendIntanceOf(Something);
Note I used the function syntax instead of the class one in order to be able to use Function.call to call [[Call]] with a custom this value.
Iirc, the only way to influence the this value in a constructor - which is what you need here - is through subclassing. I believe (but can't test) that the following should work:
function Defended() {
return new Proxy(this, DebugCheckHandler);
// ^^^^ will become the subclass instance
}
class Something extends Defended {
// ^^^^^^^^^^^^^^^^ these…
constructor() {
super();
// ^^^^^^^ …should be the only changes necessary
// and `this` is now a Proxy exotic object
this.foo = "bar";
allObjects.push(this);
}
};
let defendedSomething = new Something();
To avoid misunderstanding, let's agree on the meaning of certain words first. The following meanings are not universally accepted ones, I only suggest them as a context for this question.
function -- an instance of Function. It has a procedure associated with it.
object -- an instance of any other class. Does not have a procedure associated with it.
procedure -- a block of code that can be executed. In JS procedures can only be found associated with functions.
method -- a function that is stored in a property of another object. Methods execute in their host objects' contexts.
In JavaScript it is common that objects are customized with properties and methods, while functions don't. In other words, if you see this in code:
foo.bar // Accessing a property on an instance
foo.baz() // Calling a method on an instance
then foo is almost certainly an object and not a function.
But technically functions are no different from objects (in fact, functions in JS are considered to be objects, it's just me distinguishing them for clarity).
And if you do this:
const foo = function () { /*...*/ }
foo() // Calling the function's procedure
foo.bar // Accessing a property on the function
foo.baz() // Calling a method on the function
...it will work just fine.
I would like to introduce two more terms so that you can understand what I mean. I'm not trying to alter the rules of JavaScript here, just want to be understood.
function-object -- an function that is used as an object: has its own properties and/or methods.
main method -- the procedure of a function-object itself, as opposed to methods stored as properties on a function-object.
Many JS libraries offer function-objects, for example jQuery and LoDash. I. e. you can do both $() and $.map().
Okay, now to the matter.
I would like to be able to create my own function-objects with the following requirements:
I should be able to use the ES2015 class declaration to describe the class of my function-object. Or at least the way of describing the class should be convenient enough. Imperatively assigning properties and methods to a function is not convenient.
The main method of my function object should execute in the same context as its other methods.
The main method and other methods should be bound to the same instance. For example if I have a main method and a normal method that both do console.log(this.foo), then assigning to myFunctionObject.foo should modify the behavior of both the main mehtod and the other method.
In other words, I want to be able to do this:
class Foo {
constructor () { this.bar = 'Bar'; }
mainMethod () { console.log(this.bar); }
anotherMethod () { console.log(this.bar); }
}
...but an instance of Foo should have foo.mainMethod() available simply as foo().
And doing foo.bar = 'Quux' should modify the behavior of both foo() and foo.anotherMethod().
Maybe there's a way to achieve it with class Foo extends Function?
If you don't override anything, new Foo will return an object type, not a function type. You can potentially do
class Foo {
constructor(){
const foo = () => foo.mainMethod();
Object.setPrototypeOf(foo, this);
foo.bar = 'Bar';
return foo;
}
mainMethod () { console.log(this.bar); }
anotherMethod () { console.log(this.bar); }
}
so that new Foo will return a function that has explicitly been set up so that it returns a function with the proper prototype chain configuration. Note that I'm explicitly setting foo.bar instead of this.bar so that hasOwnProperty will still work as expected throughout the code.
You could also work around this by setting it up via a base class, e.g.
class CallableClass {
constructor(callback){
const fn = (...args) => callback(...args);
Object.setPrototypeOf(fn, this);
return fn;
}
}
class Foo extends CallableClass {
constructor(){
super(() => this.mainMethod());
this.bar = 'Bar';
}
mainMethod () { console.log(this.bar); }
anotherMethod () { console.log(this.bar); }
}
I'm writing this in real ES6, but you'll have to change the rest/spread args to a normal function if you want it to work in Node v4. e.g.
const foo = function(){ callback.apply(undefined, arguments); };
The downside to both of these approaches is that they rely on Object.setPrototypeOf, which does not work in IE<=10, so it will depend what support you need. The general understanding is that Object.setPrototypeOf is also very slow, so I'm not sure you have a ton of options here.
The main alternative that ES6 provides for this case would be Proxies, but they are not at all well supported yet.
AFAIK there is no way to add a [[Call]] method to an existing object.
Proxies might seem a potential solution, but the problems are that the proxy object is a different object than the [[ProxyHandler]], and that the [[ProxyHandler]] must already have a [[Call]] method in order to be able to set an "apply" trap.
Therefore, the only viable solution is creating a new function with the desired [[Call]], replace its [[Prototype]], and make the constructor return that function instead of the "real" instance.
class Foo {
constructor () {
var instance = function(){ return instance.mainMethod(); };
Object.setPrototypeOf(instance, Foo.prototype);
return Object.assign(instance, {bar: 'Bar'});
}
mainMethod () { console.log(this.bar); }
anotherMethod () { console.log(this.bar); }
}
I have the following code: http://jsfiddle.net/pepNU/1/
I want to make a static reference to "YourGame" and indeed the "Settings" inside it, so the only way I could think of doing this was add it as a private variable(class if you will) and then reference it as a variable in the return of YourGame, thus it could be called like:
YourGame.Settings.GetFrameRate();
What are your thoughts on this? Should I be doing something more like this to namespace:
YourGame.Settings = function...
I obviously cannot just plonk the function inside the return as I then cannot get to the GetFrameRate() function returning within the Settings with a simple call like the aforementioned
What you did is fine, but since you just need a single instance and there is no constructor logic, you could also have used an object literal:
var YourGame = {
Settings : {
// ...
},
// ...
}
If you need an instantiable "class" with "static" properties, you can also add properties to the constructor directly:
var YourGame = function() {
// constructor logic
}
YourGame.foo = 10; // static property
var game = new YourGame; // instance
game.foo; // undefined
YourGame.foo; // 10
I have come to understand that constructor functions can be instantiated to create new objects in javascript which has its own _proto_ property and also giving the property 'prototype' to the constructor function.
function MyController() {
var controllerName = 'initialcontroller';
function init() {
console.log(controllerName);
}
this.init = init;
}
Here, init can be called like this:
var mycontroller = new MyController();
mycontroller.init();
Supposing I am only instantiating only once and never again, isn't this an overkill if I don't intend to use all the prototype properties being provided by the MyController.prototype ?
Question: Instead, can i not code like this using the revealing module pattern?
var myController = function() {
var controllerName = 'initialcontroller';
function init() {
console.log(controllerName);
}
return {
init : init
}
}();
Here, init can be called like this:
myController.init();
In this case, if I try to access any property inside myController that is not present, the javascript engine won't try to find whether the property exists anywhere in the prototype chain, thus saving my time.
Or is there any other advantages of instantiating a function that i am overlooking?
If you simply want a "singleton"-like object with some methods and other properties, you could just use an object literal to simplify things even more:
var myController = {
init: function (foo) {
// do something with foo or whatever
}
}
myController.init("bar");
Or - if you need some "private" internal state, use the regular revealing module pattern:
var myController = (function () {
var internal = "i am private";
return {
init: function () {
// blah blah
}
};
}());
myController.init();
About the prototype lookup time: Yeah, theoretically, the lookup traverses up the prototype chain when you're trying to access a non-existing property. Theoretically, this might be a tiny bit faster for plain ol' Object instances that have "no" specific constructor. In reality, this performance impact should be quite negligible. Don't attempt to optimize here unless you REALLY need it. :)