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()
Related
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.
Say I have a type called MyObject and I want to add the method myMethod to it. Is there any difference (logically, but also performance-wise) between the following ways?
#1
function MyObject() {
...
}
MyObject.prototype.myMethod = function() {
...
};
#2
function MyObject() {
this.myMethod = function() {
...
};
...
}
#3
function MyObject() {
this.myMethod = myMethod;
...
}
function myMethod() {
...
}
I wouldn't mind knowing if there's a performance difference - e.g. if way #2 is costly because it defines the function separately every time an object is instantiated - but I'm mostly concerned with whether the results are equivalent.
In addition, with method #2, isn't this the same way that a class-level/static method would be defined, so does it have the danger of being called like MyObject.myMethod();? If myMethod used this and it was called on MyObject rather than an instance of MyObject, I would think this would cause issues. So does the compiler/interpreter check to see whether this is present or would it throw an error?
#1: This is the preferred way to write "class-level" methods. This saves on memory (as you'll see in #2) and JS engines can know that each instance will have this method and optimize around that.
#2: You're right, this one is more costly because it creates a new function for each instance. The difference here is that you can include private variables generated in the constructor. For example:
function MyObject() {
var name = 'Me';
this.getName = function() {
return name;
};
}
Only things created in the constructor will have access to name.
#3: This approach is largely the same as #1 but I imagine that JavaScript engines are not written to optimize for this case (but this might not be true and may change, JS engines are constantly evolving). This also creates a global function (assuming you're not using a module system) which can create major issues later.
Option 1: You can call my method without instantiating MyObject:
MyObject.prototype.myMethod();
Options 2: You must instantiate the MyObject to be able to access myMethod.
This will fail:
MyObject2.myMethod();
Uncaught TypeError: undefined is not a function
This will not:
var myObject = new MyObject2();
myObject.myMethod();
Check out the code pen: http://codepen.io/sessa/pen/tfqln
Hey guys i have a question regarding prototype in javascript.
Which of the following is the correct and best way to use prototype and why?
var myClass = function(){
this.anotherFunction();
}
myClass.prototype.anotherFunction = function(){
console.log('my prototype function');
}
var foo = new myClass(); // which automaticaly performs the function
OR
var myClass = function(){
}
myClass.prototype.anotherFunction = function(){
console.log('my prototype function');
}
var foo = new myClass();
foo.anotherFunction(); // performs the function only when called
Thanks!
The first implementation calls a method directly from the constructor. These methods are quite often some kind of initialization methods that build the needed inner state of the this context. In non JavaScript appropriate OOP speak this would mean that a method is called directly from your class constructor that builds up some initial state.
The second implementation exposes the prototype function anotherFunction as part of the public interface.
In short: Both variants are correct but implement different concepts
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/
I'm building a fairly complex web app that begins with a main menu where the user makes his initial selections. This is the first time I've tried a true OOP approach using inheritance in JavaScript and I've run into my first problem with the "this" keyword not referring to what I expect it to. I'm guessing that it's the result of a broader problem with my OOP/inheritance approach, so I would appreciate an answer that not only tells me how to solve this individual issue, but also provides deeper feedback and advice on my general approach.
I'm only going to post the JS code because I don't think the HTML is relevant, but I can certainly post that as well if necessary.
The following code defines the main class Select. It then creates a subclass of Select called SelectNum (look towards the end of the code). In SelectNum, I'm trying to override the mouseover method of Select, but not entirely -- I want to first call the super's (Select's) method, and then run some additional code. But when this subclass's mouseover method runs, I immediately get the following error:
"Uncaught TypeError: Cannot call method 'stop' of undefined"
Basically, this.shine is undefined.
To start with, I'm using the following code from O'Reilly's JavaScript: The Definitive Guide:
function inherit(p) {
if (Object.create){ // If Object.create() is defined...
return Object.create(p); // then just use it.
}
function f() {}; // Define a dummy constructor function.
f.prototype = p; // Set its prototype property to p.
return new f(); // Use f() to create an "heir" of p.
}
And my code:
Select = function(el){
return this.init(el);
}
Select.prototype = {
init: function(el){
var that = this;
this.el = el;
this.shine = el.children('.selectShine');
el.hover(function(){
that.mouseover();
},function(){
that.mouseout();
});
return this;
},
mouseover: function(){
this.shine.stop().animate({opacity:.35},200);
},
mouseout: function(){
var that = this;
this.shine.stop().animate({opacity:.25},200);
}
}
//Sub-classes
SelectNum = function(el){
this.init(el);
this.sup = inherit(Select.prototype); //allows access to super's original methods even when overwritten in this subclass
return this;
}
SelectNum.prototype = inherit(Select.prototype);
SelectNum.prototype.mouseover = function(){
this.sup.mouseover(); //call super's method... but this breaks down
//do some other stuff
}
EDIT
The response from Raynos worked. this.sup.mouseover() no longer threw the error, and the correct code was run. However, I actually need to create a SelectNum subclass called SelectLevel. Unlike SelectNum that overrides its superclass' mouseover() method, SelectLevel does NOT need to override SelectNum's mouseover() method:
SelectLevel = function(el){
this.init(el);
this.sup = inherit(SelectNum.prototype); //allows access to super's original methods even when overwritten in this subclass
for(var k in this.sup){
this.sup[k] = this.sup[k].bind(this);
}
}
SelectLevel.prototype = inherit(SelectNum.prototype);
With this code, the mouseover() method simply gets called continuously. I believe that's because this is now bound to the SelectLevel object, so this.sup in the line this.sup.mouseover() in SelectNum always refers to SelectNum, so it just keeps calling itself.
If I remove the this.sup[k] = this.sup[k].bind(this); binding in SelectLevel, then I get the error Uncaught TypeError: Cannot call method 'mouseover' of undefined. It appears that this.sup.mouseover() gets called continuously, calling the mouseover method on each object in the prototype chain. When it gets up to Object, that's when this error gets thrown because, of course, Object doesn't have a sup property.
It seems like I can solve this by removing the this.sup[k] = this.sup[k].bind(this); binding in SelectLevel, and then wrapping the this.sup.mouseover() in an if statement that checks first for the sup property before calling the mouseover() method on it: i.e. if(this.sup !== undefined), but this really just doesn't feel right.
Ultimately, I think I'm missing something fundamental about how to subclass in JavaScript. While solutions to these particular issues do shed some light on how prototypal inheritance works in JS, I really think I need a better understanding on a broader level.
this.sup.mouseover();
calls the .mouseover method on the object this.sup. What you want is
this.sup.mouseover.call(this)
You don't want to call it on this.sup you want to call it on this.
If that's a pain in the ass then you can do the following in your constructor
this.sup = inherit(Select.prototype);
for (var k in this.sup) {
if (typeof this.sup[k] === "function") {
this.sup[k] = this.sup[k].bind(this);
}
}
That basically means override every method with the same function but hard bind the value of this to what you expect/want.