In order to emulate classical, Java-like classes in JavaScript I have a function called
"createClass":
It has 3 arguments:
* Name and path of the constructor function, that should be created.
* Path of the superclass.
* JavaScript object with methods of the class.
For example:
myApp.createClass("myapp.core.JString", "myapp.core.BaseString", {
abc: function () {
...
First I create a constructor function
Cf = function () {
...
If there is a super class ("Base" is the constructor function of the super class):
protoObj = new Base();
protoObj.constructor = Cf;
Now, method by method of the new class, I put them on to the protoObj:
("protos" is the object with the "class" methods)
for (name in protos) {
????????????????????
protoObj[name] = protos[name]
But before putting the methods to the protoObj, I want to create convenience methods for
calling superclass methods from overwritten methods:
init: function () {
this.jstring_super_init();
...
So, where the question marks are, I want to place the following code:
(classnameLast in this case is "jstring" => last part of class path => lowercase)
if ((typeof protos[name] === "function") &&
(protoObj[name]) &&
(typeof protoObj[name] === "function")) {
supername = classnameLast + "_super_" + name;
protoObj[supername] = XXXXXXXXXXXXX
In the place, where the multiple X are, I tried several things, but nothing worked. It should call the method of the overwritten superclass.
Many thanks in advance for your help
Maybe you could do something like this:
for (name in protos) {
var super_function = ...; //wherever it comes from
protoObj[name] = protos[name];
protos[name]._super = super_function;
}
Then, from within the function, you should have access to the super function via this._super. You can even do this._super.call(this, ...) to ensure that the super function is called in the context of this.
Hopefully I'm understanding you correctly. Also, if I can make a suggestion, there might be an easier way to handle classical objects and inheritance. If you don't want to use Typescript, at least try the inheritance model that they use (which is quite common).
http://pastebin.com/Z2kaXqEv
EDIT: What helped me was using the Typescript playground (http://www.typescriptlang.org/Playground/). Play around with it and the class features it has, and see how it compiles to Javascript. That'll help you better understand exactly how you can accomplish classical inheritance in Javascript.
I tried this for XXXXXXXXXXXX, and it worked:
(function(name1, Base1){
return function() {
Base1.prototype[name1].apply(this, arguments);
};
})(name, Base);
I debugged a "jstring_super_init" function call in Firefox 19, Firebug 1.11.2.
Firebug behaved very strangely, jumping to wrong places of the code!!
Then, I inserted "console.log(this.cid);" after the superinit-call.
The cid, which is placed on to "this" in the init method of the super class, was there!!
When debugging with Google Chrome Version 25, it jumps to the right function!
Related
Assume we have some classes A and B:
Class A {
constructor(a) {
this.a = a;
};
showInfo() {
console.log(this.a)
};
};
Class B {
constructor(b) {
this.b = b;
};
printText() {
console.log('its B!');
};
};
Then we create an instance of B like this:
const objB = new B(
new A(3)
);
So now we have objB with its own method inside - printText, and we surely can call it.
But what if i want somehow when calling not existing method in objB to make it pass through to encapsulated A class in there and look for invoking this method on him, like this: objB.showInfo() - to give me 3 here ?
Same story, but at this time i want when calling not existing method on A to make it pass through to B outside (like that printText)?
P.S. Don't wanna use super() and inheritance, just composition and wrapping objects, hope you've got the point.
Just a little warning at the start: this might make your program harder to debug, and it also might be a little complicated for something like this. As others have suggested, you should probably investigate other options which may be simpler and also less in the way of everything else your code does.
Here's the code which provides the functionality:
function makeGetProxy(t){
return new Proxy(t, {
get(obj,prop){
if(prop in t){
return t[prop];
}else{
var keys = Object.keys(obj);
for (var i = 0; i < keys.length; i++) {
var val = t[keys[i]];
if(prop in val){
return val[prop];
// what about a recursive function?
}
}
return undefined;
}
}
});
}
And one itty bitty change to your constructor in B:
class B {
constructor(b) {
this.b = b;
return makeGetProxy(this);
};
printText() {
console.log('its B!');
};
};
If you want, you can also do the same to A.
Let's slow down. What just happened? I'll explain.
Since the properties we might request don't already exist, we're going to have to use a getter (see resources) to properly send back the value required. But, since we don't know the property names, we need a Proxy (see resources) to have a "catch-all" kind of get method.
The proxy will check if the property requested prop already exists, and if so, returns it. If it doesn't exist, it checks all of your properties' properties (all of the sub-properties).
The first result it gets, it returns it. This might cause unexpected bugs in your program. If it doesn't find it, it simply returns undefined.
Then, the proxy is generalized into a function for reuse in multiple classes (as you requested).
So, this can get the properties of a class and the properties of a class' properties, but if you need to go further (with your C class that doesn't exist yet), you can use a recursive function. I currently don't have the implementation for that recursive function, but in my head it would comprise mostly of a modified version of the else block in the makeGetProxy function.
Again, be careful with this code. It might get in the way of other things and cause unnecessary difficulty in debugging.
Resources:
Getters (MDN)
Proxy (MDN)
I borrowed some code from this answer and got the Proxy idea from this answer.
I am reading about prototipcal inheritance. There, and from elsewhere, I am learning this style of avoiding classical inheritance which I am still digesting.
One aspect that still puzzles me, though, is the this pointer, which is said to cause confusion for many like myself who come from classic OO languages. (If I were to avoid classic inheritance, shouldn't I be avoiding this as well?
)
After some reading, I realize that the this pointer is defined not at the time of object/function definition (as in C++) but rather at the site of function call. The this pointer seems (to me) like a dangling pointer whose target depends on where/how you use it.
Using an example in the linked blog article about extending objects, can someone help explain the following:
Can we avoid using this or replacing it with explicit object reference?
A related question is, is the this pointer necessary if I only use prototypical inheritance?
Example from the blog:
It would be nice to combine these two operations into one, ... and
extend it with new properties. This operation, called extend, can be
implemented as a function:
1 Object.prototype.extend = function (extension) {
2 var hasOwnProperty = Object.hasOwnProperty;
3 var object = Object.create(this);
4
5 for (var property in extension)
6 if (hasOwnProperty.call(extension, property) ||
7 typeof object[property] === "undefined")
8 object[property] = extension[property];
9
10 return object;
11 };
Using the above extend function we can rewrite the code for square as
follows:
1 var square = rectangle.extend({
2 create: function (side) {
3 return rectangle.create.call(this, side, side);
4 }
5 });
6
7 var sq = square.create(5);
8
9 alert(sq.area());
Note, this is used in line 3 of both code segments.
If you want to avoid this completely, then you should step away from creating methods that act on the object they are applied on, meaning that you should not have method calls like obj.method(), where method needs to use the state of obj in some way.
So the effect of the following should be the same as obj.method():
var method = obj.method;
method();
In places where the above would fail, you'll need to refactor the code, so that you can in principle use it like this without problems:
var method = obj1.method;
method(obj2); // apply method on obj2
So, in general you'll need to create utility functions that take one more argument: the object to apply the logic on.
In your case this would mean that you don't define extend on Object.prototype (which is considered bad practice anyway), but on Object itself, and give it the extra source object parameter. This is also how many native methods are defined, like Object.assign, Object.keys, et al. Also the definition of rectangle will need some changes to make it work without ever using this:
Object.extend = function (source, extension) {
var hasOwnProperty = Object.hasOwnProperty;
var object = Object.create(source);
for (var property in extension)
if (hasOwnProperty.call(extension, property) ||
typeof object[property] === "undefined")
object[property] = extension[property];
return object;
};
var rectangle = {
create: function (width, height) {
var self = {
width: width,
height: height,
area: function () {
return self.width * self.height;
}
};
return self;
}
};
var square = Object.extend(rectangle, {
create: function (side) {
return rectangle.create(side, side);
}
});
var sq = square.create(5);
console.log(sq.area());
As you have realised, there are lots of ways to work with objects and implement some form of inheritance in JavaScript, and each has its pros and cons.
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.
This question just got upvoted so can update question with what I did
I solved it by iterating over the window object (or user specified object root) and when I found the correct instance I backtracked and got the name from the index. The final solution can be found here
https://github.com/AndersMalmgren/Knockout.BindingConventions
Update end
I'm planning on writing a convention over configuration template source engine for KnockoutJS / MVC.
I'm started with a little client side POC and ran into a show stopper right away
My plan is use this syntax or something similar
MyApp.EditCustomersViewModel = function() {
ko.templates.loadView(this);
};
When doing this it will check the tamplate cache or fetch the templates from server using the object name as key.
The problem is I cant get the name of the prototype object, i tried this
Object.prototype.getName = function() {
var funcNameRegex = /function (.{1,})\(/;
var results = (funcNameRegex).exec((this).constructor.toString());
return (results && results.length > 1) ? results[1] : "";
};
If works for objects defined like this
function MyClass() {
}
If you add a prototype to the above object it will not work, or if you define it like this
MyApp = {};
MyApp.MyClass = function() {
};
Prototype and scoping is two musts so this is a showstopper, any ideas?
Fiddle: http://jsfiddle.net/aRWLA/
edit: The background for this is like this.
On the server you have structure like this
Templates\ [ViewName]\index.html
Templates\ [ViewName]\sub-model-template.html
on the client you will do
MyApp.EditCustomersViewModel = function() {
ko.templates.loadView(this);
};
which will generate a ajax request with the objects name as key, which will fetch all the templates for the view in question
Only hoisted functions (function someFunc() {) have a retrievable name.
Assigned functions do not, because you are not technically naming the function but creating an anonymous function and assigning a reference to it (in the memory) to a named variable.
So it's the var, not the function, that is named.
This makes the very idea of retrieving function names pretty much a none-starter, since in any vaguely mature pattern you'll be writing methods, not hoisted functions - and methods of course are assigned functions.
Named expressions (see other answers) are a partial workaround but these have other issues - not least lack of support in older IEs.
(Sidenote: I've long expected browser vendors to build around this such that the names of assigned functions became retrievable, but no joy yet AFAIK.)
I think you problem in improper replacing function prototype: if you replace function prototype object then you must preserve constructor member in prototype:
function Test1() {
}
Test1.prototype={
constructor: Test1
};
MyApp={};
MyApp.MyClass=function MyClass(){
};
MyApp.MyClass.prototype={
constructor: MyApp.MyClass
};
Your example: http://jsfiddle.net/aRWLA/1/
Modified example: http://jsfiddle.net/aRWLA/2/
You can make use of named function expressions:
MyApp.MyClass = function MyClass() { ... };
But note that (suprise) they don't work correctly in all versions of IE.
See: http://kangax.github.com/nfe/
THIS DOES NOT ANSWER THE QUESTION
However, the code might be useful to other people, so I'm leaving it here, just in case. I don't expect upvotes, but please don't abuse it for downvoting either. Thanks.
I don't know your use case, as such I think you've got a design issue - the problem you describe shouldn't happen in practice.
But let's say you do need to have this working. An easy way to do what you need would be something like:
function findNamed(obj, fn){
for(var p in obj)
if(obj[p] === fn)
return p;
return false;
}
var m = {};
m.MyClass = function() {};
console.log(findNamed(m, m.MyClass));
Of course, the solution could be made into a more appropriate OOP form, but this is just to give an idea.
To replicate your use case, it would look like:
m.MyClass = function() {
findNamed(this, arguments.callee);
};
So, the final code is:
Object.prototype.getNameOfCall = function(fn) {
for(var p in this)
if(this[p] === fn)
return p;
throw "Callback not in object.";
};
var m = {};
m.MyClass = function() {
console.log(this.getNameOfCall(arguments.callee)); // MyClass
};
m.MyClass(); // test it out
This question already has answers here:
Is there an equivalent of the __noSuchMethod__ feature for properties, or a way to implement it in JS?
(6 answers)
Closed 6 years ago.
I'm looking for a way to handle calls to undefined methods and properties in JavaScript.
These would be similar to the PHP magic methods __call, __callStatic, __get.
An example of the code using this might be:
var myObject = {};
myObject.__call = function (called, args) {
alert(called);
alert(args);
return(true);
}
myObject.meow("kitty", "miau");
This would result in the first alert dialog displaying "meow" and the second to display "kitty, miau".
Proxy can do it! Proxy can do EVERYTHING! An answer is given here: Is there a javascript equivalent of python's __getattr__ method? . To rephrase in my own words:
var myObject = new Proxy({},{get(target,name) {
return function() {
alert(name)
console.log(arguments) // alerts are bleh
return true
}
}})
myObject.meow("kitty", "miau") // alerts "meow", logs ["kitty","miau"] to the console, and returns true
Check out the MDN docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
Works in chrome, firefox, and node.js. Downsides: doesn't work in IE - freakin IE. Soon.
If you just want something like PHP's features, read the following solution I came up with. I'm assuming that you'll be putting this functionality on your own objects. Well, as long as they're not functions, you can have the following convention for convenience, and it should work on all browsers:
instead of myobj.foo or myobj['foo'], just use myobj('foo'), and make your object callable when you define it. But you'll have to avoid the use of "new" because "new" can never return a function in Javascript.
var NewFlexible = function() {
var custom = {};
return function(prop) {
if (!(prop in custom)) custom.prop = null;
return custom.prop;
};
};
And then you can create objects like so:
myObj = NewFlexible();
Using something similar to the Douglas Crockford pattern, you could create "classes" that extend this:
var NewDerived = function(options) {
var result = {};
NewFlexible.apply(result, arguments); // parent constructor
// go on to do what you have to do
return result;
};
Or, to forget about constructors, you can just make a wrapper around objects:
var MakeFlexible = function (obj) {
return function(prop) {
if ('prop' in obj) return obj.prop;
obj.prop = null; return obj.prop;
};
}
You'll just have to publish this documentation for all users of your code. It's actually good to expose your functionality through this convention because you don't want to freak people out by using nonstandard javascript.
There is a magic function in Javascript called __noSuchMethod__. Here's an example:
var foo = { __noSuchMethod__ : function(name,params) { alert('invalid function call'); } }
foo.bar();
EDIT: As #jldupont mentioned, this is actually only in Rhino and SpiderMonkey (Mozilla's JS engine); it is not supported in the ECMAScript standard. There are some requests that it be in ECMAScript 4.
I should add for people still looking for a solution, there is this:
var myObject = {};
myObject['dynamicMethod'] = new function (parameters) {
alert(parameters);
};
The only difference here is that you may have to iterate over what you intend on adding. This is pre-generating the methods, instead of simply dynamically handling them.
If you are looking specifically for a method, you will have to wait until ES7, because it looks they arent going to include it that way in harmony, anyway, there is a currently working-standard functionality on this, trought the built-in object Proxy, that is added in ES6, i wrote an answer, in this question, that takes the problem in a wider manner.
Basically involves wrapping the object into a proxy, an loading a handler
get: function(obj, propname) {custom handling}
into the proxy trought it´s constructor, to handle, filter or implement all requests of properties into it.
And it adds even more functionality.... For the complete answer, go into the link.