Non Predefined Javascript Function Names and their execution [duplicate] - javascript

There is a noSuchMethod feature in some javascript implementations (Rhino, SpiderMonkey)
proxy = {
__noSuchMethod__: function(methodName, args){
return "The " + methodName + " method isn't implemented yet. HINT: I accept cash and beer bribes" ;
},
realMethod: function(){
return "implemented" ;
}
}
js> proxy.realMethod()
implemented
js> proxy.newIPod()
The newIPod method isn't implemented yet. HINT: I accept cash and beer bribes
js>
I was wondering, is there was a way to do something similar for properties? I'd like to write proxy classes that can dispatch on properties as well as methods.

UPDATE: ECMAScript 6 Proxies are widely supported now. Basically, if you don't need to support IE11, you can use them.
Proxy objects allow you to define custom behavior for fundamental operations, like property lookup, assignment, enumeration, function invocation, etc.
Emulating __noSuchMethod__ with ES6 Proxies
By implementing traps on property access, you can emulate the behavior of the non-standard __noSuchMethod__ trap:
function enableNoSuchMethod(obj) {
return new Proxy(obj, {
get(target, p) {
if (p in target) {
return target[p];
} else if (typeof target.__noSuchMethod__ == "function") {
return function(...args) {
return target.__noSuchMethod__.call(target, p, args);
};
}
}
});
}
// Example usage:
function Dummy() {
this.ownProp1 = "value1";
return enableNoSuchMethod(this);
}
Dummy.prototype.test = function() {
console.log("Test called");
};
Dummy.prototype.__noSuchMethod__ = function(name, args) {
console.log(`No such method ${name} called with ${args}`);
return;
};
var instance = new Dummy();
console.log(instance.ownProp1);
instance.test();
instance.someName(1, 2);
instance.xyz(3, 4);
instance.doesNotExist("a", "b");
Original 2010 answer
There is only one existing thing at the moment that can actually do what you want, but unfortunately is not widely implemented:
ECMAScript Harmony Proxies.
There are only two working implementations available at this time, in the latest Firefox 4 betas (it has been around since FF3.7 pre-releases) and in node-proxy for server-side JavaScript -Chrome and Safari are currently working on it-.
It is one of the early proposals for the next version of ECMAScript, it's an API that allows you to implement virtualized objects (proxies), where you can assign a variety of traps -callbacks- that are executed in different situations, you gain full control on what at this time -in ECMAScript 3/5- only host objects could do.
To build a proxy object, you have to use the Proxy.create method, since you are interested in the set and get traps, I leave you a really simple example:
var p = Proxy.create({
get: function(proxy, name) { // intercepts property access
return 'Hello, '+ name;
},
set: function(proxy, name, value) { // intercepts property assignments
alert(name +'='+ value);
return true;
}
});
alert(p.world); // alerts 'Hello, world'
p.foo = 'bar'; // alerts foo=bar
Try it out here.
EDIT: The proxy API evolved, the Proxy.create method was removed in favor of using the Proxy constructor, see the above code updated to ES6:
const obj = {};
const p = new Proxy(obj, {
get(target, prop) { // intercepts property access
return 'Hello, '+ prop;
},
set(target, prop, value, receiver) { // intercepts property assignments
console.log(prop +'='+ value);
Reflect.set(target, prop, value, receiver)
return true;
}
});
console.log(p.world);
p.foo = 'bar';
The Proxy API is so new that isn't even documented on the Mozilla Developer Center, but as I said, a working implementation has been included since the Firefox 3.7 pre-releases.
The Proxy object is available in the global scope and the create method can take two arguments, a handler object, which is simply an object that contains properties named as the traps you want to implement, and an optional proto argument, that makes you able to specify an object that your proxy inherits from.
The traps available are:
// TrapName(args) Triggered by
// Fundamental traps
getOwnPropertyDescriptor(name): // Object.getOwnPropertyDescriptor(proxy, name)
getPropertyDescriptor(name): // Object.getPropertyDescriptor(proxy, name) [currently inexistent in ES5]
defineProperty(name, propertyDescriptor): // Object.defineProperty(proxy,name,pd)
getOwnPropertyNames(): // Object.getOwnPropertyNames(proxy)
getPropertyNames(): // Object.getPropertyNames(proxy)
delete(name): // delete proxy.name
enumerate(): // for (name in proxy)
fix(): // Object.{freeze|seal|preventExtensions}(proxy)
// Derived traps
has(name): // name in proxy
hasOwn(name): // ({}).hasOwnProperty.call(proxy, name)
get(receiver, name): // receiver.name
set(receiver, name, val): // receiver.name = val
keys(): // Object.keys(proxy)
The only resource I've seen, besides the proposal by itself, is the following tutorial:
Harmony Proxies: Tutorial
Edit: More information is coming out, Brendan Eich recently gave a talk at the JSConf.eu Conference, you can find his slides here:
Proxies are Awesome!

Here's how to get behaviour similar to __noSuchMethod__
First of all, here's a simple object with one method:
var myObject = {
existingMethod: function (param) {
console.log('existing method was called', param);
}
}
Now create a Proxy which will catch access to properties/method and add your existing object as a first parameter.
var myObjectProxy = new Proxy(myObject, {
get: function (func, name) {
// if property or method exists, return it
if( name in myObject ) {
return myObject[name];
}
// if it doesn't exists handle non-existing name however you choose
return function (args) {
console.log(name, args);
}
}
});
Now try it:
myObjectProxy.existingMethod('was called here');
myObjectProxy.nonExistingMethod('with a parameter');
Works in Chrome/Firefox/Opera. Doesn't work in IE(but already works in Edge). Also tested on mobile Chrome.
Creation of proxy can be automated and invisible i.e. if you use Factory pattern to build your objects. I did that to create workers which internal functions can be called directly from the main thread. Using workers can be now so simple thanks to this cool new feature called Proxy. The simplest worker implementation ever:
var testWorker = createWorker('pathTo/testWorker.js');
testWorker.aFunctionInsideWorker(params, function (result) {
console.log('results from worker: ', result);
});

I don't believe this type of metaprogramming is possible (yet) in javascript. Instead, try using the __noSuchMethod__ functionality to achieve the effect with property getters. Not cross-browser as it's a Mozilla extension.
var proxy = {
__noSuchMethod__: function(methodName, args) {
if(methodName.substr(0,3)=="get") {
var property = methodName.substr(3).toLowerCase();
if (property in this) {
return this[property];
}
}
}, color: "red"
};
alert(proxy.getColor());

You can use the Proxy class.
var myObj = {
someAttr: 'foo'
};
var p = new Proxy(myObj, {
get: function (target, propName) {
// target is the first argument passed into new Proxy,
// in this case target === myObj
return 'myObj with someAttr:"' + target.someAttr
+ '" had "' + propName
+ '" called on it.';
}
});
console.log(p.nonExsistantProperty);
// outputs:
// myObj with someAttr:"foo" had "nonExsistantProperty" called on it

There is __defineGetter__, __defineSetter__, __lookupGetter__ and __lookupSetter__ in addition to __noSuchMethod__ in SpiderMonkey.

Although this is an old question I was looking into this today. I wanted to be able to seamlessly integrate code from another context, maybe a different web page or server.
Its the sort of thing that breaks in the long run, but I think its an interesting concept none the less. These things can be useful for mashing code together quickly, ( which then exists for years, buried somewhere ).
var mod = modproxy();
mod.callme.first.now('hello', 'world');
mod.hello.world.plot = 555;
var v = mod.peter.piper.lucky.john.valueOf;
console.log(v);
mod.hello.world = function(v) {
alert(v);
return 777;
};
var v = mod.hello.world('funky...');
console.log(v);
var v = mod.hello.world.plot.valueOf;
console.log(v);
mod.www.a(99);
mod.www.b(98);
function modproxy(__notfound__) {
var mem = {};
return newproxy();
function getter(target, name, receiver, lname) {
if(name === 'valueOf') {
lname=lname.slice(1);
if(lname in mem) {
var v = mem[lname];
console.log(`rd : ${lname} - ${v}`);
return v;
}
console.log(`rd (not found) : ${lname}`);
return;
}
lname += '.'+name;
return newproxy(() => {}, lname);
} // getter
function setter(obj, prop, newval, lname) {
lname += '.' + prop;
lname = lname.slice(1);
console.log(`wt : ${lname} - ${newval}`);
mem[lname] = newval;
} // setter
function applyer(target, thisArg, args, lname) {
lname = lname.slice(1);
if(lname in mem) {
var v = mem[lname];
if(typeof v === 'function') {
console.log(`fn : ${lname} - [${args}]`);
return v.apply(thisArg,args);
}
return v;
}
console.log(`fn (not found): ${lname} - [${args}]`);
} // applyer
function newproxy(target, lname) {
target = target || {};
lname = lname || '';
return new Proxy(target, {
get: (target, name, receiver) => {
return getter(target, name, receiver, lname);
},
set: (target, name, newval) => {
return setter(target, name, newval, lname);
},
apply: (target, thisArg, args) => {
return applyer(target, thisArg, args, lname);
}
});
} //proxy
} //modproxy
I implemented a valueOf step to read values, because it seems the property is 'get-ted' first.
I dont think its possible to tell at the time the property is 'get-ted' if its going to be invoked or read ( or required for further chaining ).
Its ok for single level properties. The property is either there or its not and either the required type or its not.
I'll work on it further, looking at promises for async/await routines, proxying existing objects and finer control of how properties are accessed when I am more familiar with how the code behaves and is best implemented.
I created a repository on GitHub: modproxy.js/README.md
CodePen: modproxy.js
My original question:
does javascript have an equivalent to the php magic class __call

Related

es6 proxy safe deep object

I wrote a small wrapper to return undefined in place of typeError when accessing properties that don't exist using a Proxy. Here is the code:
function proxify(event) {
var proxy = new Proxy(event, {
get: function (target, property) {
if (property in target) {
return target[property];
} else {
return '';
}
}
}
});
return proxy;
}
This works when a property is missing 1 level deep.
For example, assuming obj.something does not exist:
obj.something.else
will return undefined
But if the object property is deep nested
obj.something.else.deeper
I receive a typeError
My question is how do I extend the function above to work on deep nested objects?
Thx
You need to wrap the return value in your proxify function:
function proxify(event) {
return isPrimitive(event) ? event : new Proxy(event, { get: getProp });
}
function isPrimitive(v) {
return v == null || (typeof v !== 'function' && typeof v !== 'object');
}
function getProp (target, property) {
if (property in target) {
return proxify(target[property]);
} else {
return proxify({});
}
}
In all honesty, you're probably better off using something like lodash's _.get() or ramda's R.path(). There's no way to know from the first getProp() call how many layers deep the evaluation is going to go, so it has to always return a primitive value or a "truthy" Proxy instance so that the next property access can be intercepted (if one happens). The _.get() method on the other hand takes a string so it can immediately know from the initial invocation that you're only trying to access down so many levels.
I published a library on GitHub (Observable Slim) that enables you to proxy an object and any nested children of that object. It also has a few extra features:
Reports back to a specified callback whenever changes occur.
Will prevent user from trying to Proxy a Proxy.
Keeps a store of which objects have been proxied and will re-use existing proxies instead of creating new ones (very significant performance implications).
Written in ES5 and employs a forked version of the Proxy polyfill so it can be deployed in older browsers fairly easily and support Array mutation methods.
It works like this:
var test = {testing:{}};
var p = ObservableSlim.create(test, true, function(changes) {
console.log(JSON.stringify(changes));
});
p.testing.blah = 42; // console: [{"type":"add","target":{"blah":42},"property":"blah","newValue":42,"currentPath":"testing.blah",jsonPointer:"/testing/blah","proxy":{"blah":42}}]
As idbehold said, you must return a primitive value or new proxy.
I think you dont need loDash to do that, and Yes, you can manage the depth of the nested proxy ! (see my last point, deepProxy.
But, since I'm not sure what you want to do, i would like focus your attention to those few points:
First usage (simulated chain):
function proxify(event){
return isPrimitive(event) ? event : new Proxy(event,{ get: getProp });
}
function isPrimitive(v){
return v == null || (typeof v !== 'function' && typeof v !== 'object');
}
function getProp(target, property){
return (property in target)
? proxify(target[property])
: proxify({});
}
this code as it stands, will simulate nested properties,
but not confer any members dependency (because no assignment, then no preservation).
obj.something.else = 99;
console.log(obj.something.else) // returning a new Proxy()
IMO, it doesn't make sense, or reserved to very specific cases.
Again, it depend of what is your purpose.
Second usage (deep assignment):
Basic not extensible assignment
function proxify(defprop={})
{
return new Proxy(defprop, handler);
};
var handler =
{
get: function(target, property, receiver)
{
if(!(property in target))
target[property] = proxify();
return Reflect.get(target, property, receiver);
},
};
obj.something.else = 99;
console.log(obj.something.else) // returning 99
Extensible to assignment
By using basic chainable proxy, if you try to set a new object (or nested object) you will only trap the root of this new property.
There is no more possible chainning, this is not suitable and not safe.
Remember the following case:
Cyph:
But if the object property is deep nested
obj.something.else.deeper
(Bad way) Assuming this assignment:
var deeper = {toto: "titi"};
obj.something.else = deeper;
console.log(obj.something.else.toto)
// will return "titi"
obj.something.else.toto.something.else = {tutu: "tata"};
// will return a typeError Again
(Good way) To propagate the chain ability
You need to check for the type of value as a true object in the setter trap, and proxify each root properties. The rest of the depth will be converted naturally by the getter trap.
var handler =
{
get: function(target, property, receiver)
{
if(!(property in target))
target[property] = proxify();
return Reflect.get(target, property, receiver);
},
set: function(target, property, value, receiver)
{
// extend proxify to appended nested object
if(({}).toString.call(value) === "[object Object]")
value = deepApply(receiver, property, value);
return Reflect.set(target, property, value, receiver);
},
};
var deepApply = function(receiver,property, data)
{
var proxy = proxify();
var props = Object.keys(data);
var size = props.length;
for(var i = 0; i < size; i++)
{
property = props[i];
proxy[property] = data[property];
}
return proxy;
};
Manage the depth
I invite you to read my actual solution : deepProxy
The level can be auto-defined via the proto declaration
when the object structure is setted. Then you can easily know the current floor and add conditional instructions for each level.
The path of property can be reach from his accessor.

Call same function no matter what function is called in Javascript Object [duplicate]

There is a noSuchMethod feature in some javascript implementations (Rhino, SpiderMonkey)
proxy = {
__noSuchMethod__: function(methodName, args){
return "The " + methodName + " method isn't implemented yet. HINT: I accept cash and beer bribes" ;
},
realMethod: function(){
return "implemented" ;
}
}
js> proxy.realMethod()
implemented
js> proxy.newIPod()
The newIPod method isn't implemented yet. HINT: I accept cash and beer bribes
js>
I was wondering, is there was a way to do something similar for properties? I'd like to write proxy classes that can dispatch on properties as well as methods.
UPDATE: ECMAScript 6 Proxies are widely supported now. Basically, if you don't need to support IE11, you can use them.
Proxy objects allow you to define custom behavior for fundamental operations, like property lookup, assignment, enumeration, function invocation, etc.
Emulating __noSuchMethod__ with ES6 Proxies
By implementing traps on property access, you can emulate the behavior of the non-standard __noSuchMethod__ trap:
function enableNoSuchMethod(obj) {
return new Proxy(obj, {
get(target, p) {
if (p in target) {
return target[p];
} else if (typeof target.__noSuchMethod__ == "function") {
return function(...args) {
return target.__noSuchMethod__.call(target, p, args);
};
}
}
});
}
// Example usage:
function Dummy() {
this.ownProp1 = "value1";
return enableNoSuchMethod(this);
}
Dummy.prototype.test = function() {
console.log("Test called");
};
Dummy.prototype.__noSuchMethod__ = function(name, args) {
console.log(`No such method ${name} called with ${args}`);
return;
};
var instance = new Dummy();
console.log(instance.ownProp1);
instance.test();
instance.someName(1, 2);
instance.xyz(3, 4);
instance.doesNotExist("a", "b");
Original 2010 answer
There is only one existing thing at the moment that can actually do what you want, but unfortunately is not widely implemented:
ECMAScript Harmony Proxies.
There are only two working implementations available at this time, in the latest Firefox 4 betas (it has been around since FF3.7 pre-releases) and in node-proxy for server-side JavaScript -Chrome and Safari are currently working on it-.
It is one of the early proposals for the next version of ECMAScript, it's an API that allows you to implement virtualized objects (proxies), where you can assign a variety of traps -callbacks- that are executed in different situations, you gain full control on what at this time -in ECMAScript 3/5- only host objects could do.
To build a proxy object, you have to use the Proxy.create method, since you are interested in the set and get traps, I leave you a really simple example:
var p = Proxy.create({
get: function(proxy, name) { // intercepts property access
return 'Hello, '+ name;
},
set: function(proxy, name, value) { // intercepts property assignments
alert(name +'='+ value);
return true;
}
});
alert(p.world); // alerts 'Hello, world'
p.foo = 'bar'; // alerts foo=bar
Try it out here.
EDIT: The proxy API evolved, the Proxy.create method was removed in favor of using the Proxy constructor, see the above code updated to ES6:
const obj = {};
const p = new Proxy(obj, {
get(target, prop) { // intercepts property access
return 'Hello, '+ prop;
},
set(target, prop, value, receiver) { // intercepts property assignments
console.log(prop +'='+ value);
Reflect.set(target, prop, value, receiver)
return true;
}
});
console.log(p.world);
p.foo = 'bar';
The Proxy API is so new that isn't even documented on the Mozilla Developer Center, but as I said, a working implementation has been included since the Firefox 3.7 pre-releases.
The Proxy object is available in the global scope and the create method can take two arguments, a handler object, which is simply an object that contains properties named as the traps you want to implement, and an optional proto argument, that makes you able to specify an object that your proxy inherits from.
The traps available are:
// TrapName(args) Triggered by
// Fundamental traps
getOwnPropertyDescriptor(name): // Object.getOwnPropertyDescriptor(proxy, name)
getPropertyDescriptor(name): // Object.getPropertyDescriptor(proxy, name) [currently inexistent in ES5]
defineProperty(name, propertyDescriptor): // Object.defineProperty(proxy,name,pd)
getOwnPropertyNames(): // Object.getOwnPropertyNames(proxy)
getPropertyNames(): // Object.getPropertyNames(proxy)
delete(name): // delete proxy.name
enumerate(): // for (name in proxy)
fix(): // Object.{freeze|seal|preventExtensions}(proxy)
// Derived traps
has(name): // name in proxy
hasOwn(name): // ({}).hasOwnProperty.call(proxy, name)
get(receiver, name): // receiver.name
set(receiver, name, val): // receiver.name = val
keys(): // Object.keys(proxy)
The only resource I've seen, besides the proposal by itself, is the following tutorial:
Harmony Proxies: Tutorial
Edit: More information is coming out, Brendan Eich recently gave a talk at the JSConf.eu Conference, you can find his slides here:
Proxies are Awesome!
Here's how to get behaviour similar to __noSuchMethod__
First of all, here's a simple object with one method:
var myObject = {
existingMethod: function (param) {
console.log('existing method was called', param);
}
}
Now create a Proxy which will catch access to properties/method and add your existing object as a first parameter.
var myObjectProxy = new Proxy(myObject, {
get: function (func, name) {
// if property or method exists, return it
if( name in myObject ) {
return myObject[name];
}
// if it doesn't exists handle non-existing name however you choose
return function (args) {
console.log(name, args);
}
}
});
Now try it:
myObjectProxy.existingMethod('was called here');
myObjectProxy.nonExistingMethod('with a parameter');
Works in Chrome/Firefox/Opera. Doesn't work in IE(but already works in Edge). Also tested on mobile Chrome.
Creation of proxy can be automated and invisible i.e. if you use Factory pattern to build your objects. I did that to create workers which internal functions can be called directly from the main thread. Using workers can be now so simple thanks to this cool new feature called Proxy. The simplest worker implementation ever:
var testWorker = createWorker('pathTo/testWorker.js');
testWorker.aFunctionInsideWorker(params, function (result) {
console.log('results from worker: ', result);
});
I don't believe this type of metaprogramming is possible (yet) in javascript. Instead, try using the __noSuchMethod__ functionality to achieve the effect with property getters. Not cross-browser as it's a Mozilla extension.
var proxy = {
__noSuchMethod__: function(methodName, args) {
if(methodName.substr(0,3)=="get") {
var property = methodName.substr(3).toLowerCase();
if (property in this) {
return this[property];
}
}
}, color: "red"
};
alert(proxy.getColor());
You can use the Proxy class.
var myObj = {
someAttr: 'foo'
};
var p = new Proxy(myObj, {
get: function (target, propName) {
// target is the first argument passed into new Proxy,
// in this case target === myObj
return 'myObj with someAttr:"' + target.someAttr
+ '" had "' + propName
+ '" called on it.';
}
});
console.log(p.nonExsistantProperty);
// outputs:
// myObj with someAttr:"foo" had "nonExsistantProperty" called on it
There is __defineGetter__, __defineSetter__, __lookupGetter__ and __lookupSetter__ in addition to __noSuchMethod__ in SpiderMonkey.
Although this is an old question I was looking into this today. I wanted to be able to seamlessly integrate code from another context, maybe a different web page or server.
Its the sort of thing that breaks in the long run, but I think its an interesting concept none the less. These things can be useful for mashing code together quickly, ( which then exists for years, buried somewhere ).
var mod = modproxy();
mod.callme.first.now('hello', 'world');
mod.hello.world.plot = 555;
var v = mod.peter.piper.lucky.john.valueOf;
console.log(v);
mod.hello.world = function(v) {
alert(v);
return 777;
};
var v = mod.hello.world('funky...');
console.log(v);
var v = mod.hello.world.plot.valueOf;
console.log(v);
mod.www.a(99);
mod.www.b(98);
function modproxy(__notfound__) {
var mem = {};
return newproxy();
function getter(target, name, receiver, lname) {
if(name === 'valueOf') {
lname=lname.slice(1);
if(lname in mem) {
var v = mem[lname];
console.log(`rd : ${lname} - ${v}`);
return v;
}
console.log(`rd (not found) : ${lname}`);
return;
}
lname += '.'+name;
return newproxy(() => {}, lname);
} // getter
function setter(obj, prop, newval, lname) {
lname += '.' + prop;
lname = lname.slice(1);
console.log(`wt : ${lname} - ${newval}`);
mem[lname] = newval;
} // setter
function applyer(target, thisArg, args, lname) {
lname = lname.slice(1);
if(lname in mem) {
var v = mem[lname];
if(typeof v === 'function') {
console.log(`fn : ${lname} - [${args}]`);
return v.apply(thisArg,args);
}
return v;
}
console.log(`fn (not found): ${lname} - [${args}]`);
} // applyer
function newproxy(target, lname) {
target = target || {};
lname = lname || '';
return new Proxy(target, {
get: (target, name, receiver) => {
return getter(target, name, receiver, lname);
},
set: (target, name, newval) => {
return setter(target, name, newval, lname);
},
apply: (target, thisArg, args) => {
return applyer(target, thisArg, args, lname);
}
});
} //proxy
} //modproxy
I implemented a valueOf step to read values, because it seems the property is 'get-ted' first.
I dont think its possible to tell at the time the property is 'get-ted' if its going to be invoked or read ( or required for further chaining ).
Its ok for single level properties. The property is either there or its not and either the required type or its not.
I'll work on it further, looking at promises for async/await routines, proxying existing objects and finer control of how properties are accessed when I am more familiar with how the code behaves and is best implemented.
I created a repository on GitHub: modproxy.js/README.md
CodePen: modproxy.js
My original question:
does javascript have an equivalent to the php magic class __call

How can I define a default getter and setter using ECMAScript 5?

How can I specify a default getter for a prototype?
With default getter I mean a function that is called if obj.undefinedProperty123 is called.
I tried Object.prototype.get = function(property) {..} but this is not called in this case.
In ECMAScript 5, you can only intercept get/set operations on specific named properties (not universally all properties) via Object.defineProperty:
Object.defineProperty(someObj, "someProp", {
get: function() {
console.log("you tried to get someObj.someProp");
return "foo";
}
});
Here, the get function will run any time code tries to read someObj.someProp.
In the upcoming ECMAScript 6 draft, this will be possible via proxies. A proxy has an underlying target object and set/get functions. Any time a set or get operation happens on any of a proxy's properties, the appropriate function runs, taking as arguments the proxy's target object, property name used, and the value used in a set attempt.
var proxyHandler = {
get: function(obj, name){
console.log("you're getting property " + name);
return target[name];
},
set: function(obj, name, value) {
console.log("you're setting property " + name);
target[name] = value;
}
}
var underlyingObj = {};
// use prox instead of underlyingObj to use get/set interceptor functions
var prox = new Proxy(underlyingObj, proxyHandler);
Here, setting to getting property values on prox will cause the set/get functions to run.
What Gareth said, except it's __noSuchMethod__.
Or maybe you were thinking of PHP?
Here's a very good article on the recently standardized property getters/setters, highlighting some previous non-standard incarnations.
http://whereswalden.com/2010/04/16/more-spidermonkey-changes-ancient-esoteric-very-rarely-used-syntax-for-creating-getters-and-setters-is-being-removed/
summary: there's no standard 'catch-all' getter / setter (yet), but Object.defineProperty is the future.
You need to wait for the implementation of the ECMA6 "Proxy" system, designed to do exactly this. See http://wiki.ecmascript.org/doku.php?id=harmony:direct_proxies.
You want to create a Proxy:
const data = {};
const proxy = new Proxy(data, {
get: (target, prop) => {
console.log({ target, prop });
return "My Value";
},
set: (target, prop, value) => {
console.log({ target, prop, value });
return true;
},
});
proxy["foo"] = "bar";
const bar = proxy["foo"];
Firefox it's possible with non-standard noSuchMethod:-
({__noSuchMethod__:function(){alert(1);}}).a();
I am not sure about what you are asking. But If you want a method to be called when the user attempts to Access object.nonExistingProperty . I dont think there is any way to do that.
maybe late to ther party, let just add simple ES5 friendly "class creation": both string props and getters - i needed it for some ancient rewrite, to temporarily support IE (yes, that hurts, still found someone relying on ActiveX)
var MyObj = function () {
var obj = {
url: 'aabbcc',
a: function(){ return this.url;}
}
Object.defineProperty(obj, "urltoo", { get: function () { return this.url; } })
return obj;
}
var X = new MyObj();
x.url // aabbcc
x.urltoo // aabbcc
x.urltoo() // error - not a function
x.a() // aabbcc
x.a // ƒ (){ return this.url;}
I ran into this question because I wanted this behavior: if object property is undefined, return some default value instead.
const options = {
foo: 'foo',
bar: 'bar',
baz: 'baz'
};
function useOptionValue(optionName) {
// I want `options` to return a default value if `optionName` does not exist
const value = options[optionName];
// etc...
}
The simple way to do this (without Proxy or Object.defineProperty overkill for this use case) is like so:
function useOptionValue(optionName) {
const value = options[optionName] || defaultValue;
}
Or, if you want to get fancy, you could use a Symbol:
const default = Symbol.for('default');
const options = {
foo: 'foo',
bar: 'bar',
baz: 'baz',
[default]: 'foobarbaz'
};
function useOptionValue(optionName) {
const value = options[optionName] || options[default];
}

Is there an equivalent of the __noSuchMethod__ feature for properties, or a way to implement it in JS?

There is a noSuchMethod feature in some javascript implementations (Rhino, SpiderMonkey)
proxy = {
__noSuchMethod__: function(methodName, args){
return "The " + methodName + " method isn't implemented yet. HINT: I accept cash and beer bribes" ;
},
realMethod: function(){
return "implemented" ;
}
}
js> proxy.realMethod()
implemented
js> proxy.newIPod()
The newIPod method isn't implemented yet. HINT: I accept cash and beer bribes
js>
I was wondering, is there was a way to do something similar for properties? I'd like to write proxy classes that can dispatch on properties as well as methods.
UPDATE: ECMAScript 6 Proxies are widely supported now. Basically, if you don't need to support IE11, you can use them.
Proxy objects allow you to define custom behavior for fundamental operations, like property lookup, assignment, enumeration, function invocation, etc.
Emulating __noSuchMethod__ with ES6 Proxies
By implementing traps on property access, you can emulate the behavior of the non-standard __noSuchMethod__ trap:
function enableNoSuchMethod(obj) {
return new Proxy(obj, {
get(target, p) {
if (p in target) {
return target[p];
} else if (typeof target.__noSuchMethod__ == "function") {
return function(...args) {
return target.__noSuchMethod__.call(target, p, args);
};
}
}
});
}
// Example usage:
function Dummy() {
this.ownProp1 = "value1";
return enableNoSuchMethod(this);
}
Dummy.prototype.test = function() {
console.log("Test called");
};
Dummy.prototype.__noSuchMethod__ = function(name, args) {
console.log(`No such method ${name} called with ${args}`);
return;
};
var instance = new Dummy();
console.log(instance.ownProp1);
instance.test();
instance.someName(1, 2);
instance.xyz(3, 4);
instance.doesNotExist("a", "b");
Original 2010 answer
There is only one existing thing at the moment that can actually do what you want, but unfortunately is not widely implemented:
ECMAScript Harmony Proxies.
There are only two working implementations available at this time, in the latest Firefox 4 betas (it has been around since FF3.7 pre-releases) and in node-proxy for server-side JavaScript -Chrome and Safari are currently working on it-.
It is one of the early proposals for the next version of ECMAScript, it's an API that allows you to implement virtualized objects (proxies), where you can assign a variety of traps -callbacks- that are executed in different situations, you gain full control on what at this time -in ECMAScript 3/5- only host objects could do.
To build a proxy object, you have to use the Proxy.create method, since you are interested in the set and get traps, I leave you a really simple example:
var p = Proxy.create({
get: function(proxy, name) { // intercepts property access
return 'Hello, '+ name;
},
set: function(proxy, name, value) { // intercepts property assignments
alert(name +'='+ value);
return true;
}
});
alert(p.world); // alerts 'Hello, world'
p.foo = 'bar'; // alerts foo=bar
Try it out here.
EDIT: The proxy API evolved, the Proxy.create method was removed in favor of using the Proxy constructor, see the above code updated to ES6:
const obj = {};
const p = new Proxy(obj, {
get(target, prop) { // intercepts property access
return 'Hello, '+ prop;
},
set(target, prop, value, receiver) { // intercepts property assignments
console.log(prop +'='+ value);
Reflect.set(target, prop, value, receiver)
return true;
}
});
console.log(p.world);
p.foo = 'bar';
The Proxy API is so new that isn't even documented on the Mozilla Developer Center, but as I said, a working implementation has been included since the Firefox 3.7 pre-releases.
The Proxy object is available in the global scope and the create method can take two arguments, a handler object, which is simply an object that contains properties named as the traps you want to implement, and an optional proto argument, that makes you able to specify an object that your proxy inherits from.
The traps available are:
// TrapName(args) Triggered by
// Fundamental traps
getOwnPropertyDescriptor(name): // Object.getOwnPropertyDescriptor(proxy, name)
getPropertyDescriptor(name): // Object.getPropertyDescriptor(proxy, name) [currently inexistent in ES5]
defineProperty(name, propertyDescriptor): // Object.defineProperty(proxy,name,pd)
getOwnPropertyNames(): // Object.getOwnPropertyNames(proxy)
getPropertyNames(): // Object.getPropertyNames(proxy)
delete(name): // delete proxy.name
enumerate(): // for (name in proxy)
fix(): // Object.{freeze|seal|preventExtensions}(proxy)
// Derived traps
has(name): // name in proxy
hasOwn(name): // ({}).hasOwnProperty.call(proxy, name)
get(receiver, name): // receiver.name
set(receiver, name, val): // receiver.name = val
keys(): // Object.keys(proxy)
The only resource I've seen, besides the proposal by itself, is the following tutorial:
Harmony Proxies: Tutorial
Edit: More information is coming out, Brendan Eich recently gave a talk at the JSConf.eu Conference, you can find his slides here:
Proxies are Awesome!
Here's how to get behaviour similar to __noSuchMethod__
First of all, here's a simple object with one method:
var myObject = {
existingMethod: function (param) {
console.log('existing method was called', param);
}
}
Now create a Proxy which will catch access to properties/method and add your existing object as a first parameter.
var myObjectProxy = new Proxy(myObject, {
get: function (func, name) {
// if property or method exists, return it
if( name in myObject ) {
return myObject[name];
}
// if it doesn't exists handle non-existing name however you choose
return function (args) {
console.log(name, args);
}
}
});
Now try it:
myObjectProxy.existingMethod('was called here');
myObjectProxy.nonExistingMethod('with a parameter');
Works in Chrome/Firefox/Opera. Doesn't work in IE(but already works in Edge). Also tested on mobile Chrome.
Creation of proxy can be automated and invisible i.e. if you use Factory pattern to build your objects. I did that to create workers which internal functions can be called directly from the main thread. Using workers can be now so simple thanks to this cool new feature called Proxy. The simplest worker implementation ever:
var testWorker = createWorker('pathTo/testWorker.js');
testWorker.aFunctionInsideWorker(params, function (result) {
console.log('results from worker: ', result);
});
I don't believe this type of metaprogramming is possible (yet) in javascript. Instead, try using the __noSuchMethod__ functionality to achieve the effect with property getters. Not cross-browser as it's a Mozilla extension.
var proxy = {
__noSuchMethod__: function(methodName, args) {
if(methodName.substr(0,3)=="get") {
var property = methodName.substr(3).toLowerCase();
if (property in this) {
return this[property];
}
}
}, color: "red"
};
alert(proxy.getColor());
You can use the Proxy class.
var myObj = {
someAttr: 'foo'
};
var p = new Proxy(myObj, {
get: function (target, propName) {
// target is the first argument passed into new Proxy,
// in this case target === myObj
return 'myObj with someAttr:"' + target.someAttr
+ '" had "' + propName
+ '" called on it.';
}
});
console.log(p.nonExsistantProperty);
// outputs:
// myObj with someAttr:"foo" had "nonExsistantProperty" called on it
There is __defineGetter__, __defineSetter__, __lookupGetter__ and __lookupSetter__ in addition to __noSuchMethod__ in SpiderMonkey.
Although this is an old question I was looking into this today. I wanted to be able to seamlessly integrate code from another context, maybe a different web page or server.
Its the sort of thing that breaks in the long run, but I think its an interesting concept none the less. These things can be useful for mashing code together quickly, ( which then exists for years, buried somewhere ).
var mod = modproxy();
mod.callme.first.now('hello', 'world');
mod.hello.world.plot = 555;
var v = mod.peter.piper.lucky.john.valueOf;
console.log(v);
mod.hello.world = function(v) {
alert(v);
return 777;
};
var v = mod.hello.world('funky...');
console.log(v);
var v = mod.hello.world.plot.valueOf;
console.log(v);
mod.www.a(99);
mod.www.b(98);
function modproxy(__notfound__) {
var mem = {};
return newproxy();
function getter(target, name, receiver, lname) {
if(name === 'valueOf') {
lname=lname.slice(1);
if(lname in mem) {
var v = mem[lname];
console.log(`rd : ${lname} - ${v}`);
return v;
}
console.log(`rd (not found) : ${lname}`);
return;
}
lname += '.'+name;
return newproxy(() => {}, lname);
} // getter
function setter(obj, prop, newval, lname) {
lname += '.' + prop;
lname = lname.slice(1);
console.log(`wt : ${lname} - ${newval}`);
mem[lname] = newval;
} // setter
function applyer(target, thisArg, args, lname) {
lname = lname.slice(1);
if(lname in mem) {
var v = mem[lname];
if(typeof v === 'function') {
console.log(`fn : ${lname} - [${args}]`);
return v.apply(thisArg,args);
}
return v;
}
console.log(`fn (not found): ${lname} - [${args}]`);
} // applyer
function newproxy(target, lname) {
target = target || {};
lname = lname || '';
return new Proxy(target, {
get: (target, name, receiver) => {
return getter(target, name, receiver, lname);
},
set: (target, name, newval) => {
return setter(target, name, newval, lname);
},
apply: (target, thisArg, args) => {
return applyer(target, thisArg, args, lname);
}
});
} //proxy
} //modproxy
I implemented a valueOf step to read values, because it seems the property is 'get-ted' first.
I dont think its possible to tell at the time the property is 'get-ted' if its going to be invoked or read ( or required for further chaining ).
Its ok for single level properties. The property is either there or its not and either the required type or its not.
I'll work on it further, looking at promises for async/await routines, proxying existing objects and finer control of how properties are accessed when I am more familiar with how the code behaves and is best implemented.
I created a repository on GitHub: modproxy.js/README.md
CodePen: modproxy.js
My original question:
does javascript have an equivalent to the php magic class __call

Do Javascript prototypes have something equivalent to Lua's __index & __newindex?

I want to define a behavior on Javascript objects that kicks in when the referenced attribute/method doesn't exist.
In Lua you can do this with metatables and the __index & __newindex methods.
--Lua code
o = setmetatable({},{__index=function(self,key)
print("tried to undefined key",key)
return nil
end
})
So I'm wondering if there is something similar in javascript.
What I'm trying to achieve is a generic RPC interface that works like this (not valid Javascript):
function RPC(url)
{
this.url = url;
}
RPC.prototype.__index=function(methodname) //imagine that prototype.__index exists
{
AJAX.get(this.url+"?call="+ methodname);
}
var proxy = RPC("http://example.com/rpcinterface");
proxy.ServerMethodA(1,2,3);
proxy.ServerMethodB("abc");
So how can I do this?
Can this even be done?
Just FYI: Firefox supports a non-standard __noSuchMethod__ extension.
asked 8 years, 8 months ago
Now we can use 'Proxy'
Proxy - JavaScript | MDN
A simple way to use :
--Lua code
local o = setmetatable({},{__index=function(self,key)
print("tried to undefined key",key)
return nil
end
//With Proxy in Javascript
let o = new Proxy({}, {
get: function (target, key, receiver) {
if (!target.hasOwnProperty(key)){
console.log("tried to undefined key "+key);
}
return Reflect.get(target, key, receiver);
},
set: function (target, key, value, receiver) {
console.log(`set `+ key);
return Reflect.set(target, key, value, receiver);
}
})
get : __index
set : __newindex
Reflect.get : rawget
Reflect.set : rawset
in console:
let o= new Proxy({},{
get: function (target, key, receiver) {
let ret = Reflect.get(target, key, receiver);
if (!target.hasOwnProperty(key)){
console.log("tried to undefined key "+key);
}
return ret;
}
})
>> undefined
o.a
>> VM383:5 tried to undefined key a
>> undefined
o.a = 1
>> 1
o.a
>> 1
Update: this answer is no longer correct. ECMAScript 2015 (ECMA-262 6th Ed. §§ 9.5, 26.2) defined Proxy objects, which can be used to achieve this.
In JavaScript engines that don't provide Proxy, this functionality is still unavailable. In those engines, idioms which in Lua would rely on __index and __newindex will have to be expressed in some other way, like below.
javascript is more like scheme than it is like smalltalk (which supports method not defined) or lua. Unfortunately your request is not supported to the best of my knowledge.
You could emulate this behaviour with an extra step.
function CAD(object, methodName) // Check and Attach Default
{
if (!(object[methodName] && typeof object[methodName] == "function") &&
(object["__index"] && typeof object["__index"] == "function")) {
object[methodName] = function() { return object.__index(methodName); };
}
}
so your example becomes
function RPC(url)
{
this.url = url;
}
RPC.prototype.__index=function(methodname) //imagine that prototype.__index exists
{
AJAX.get(this.url+"?call="+ methodname);
}
var proxy = RPC("http://example.com/rpcinterface");
CAD(proxy, "ServerMethodA");
proxy.ServerMethodA(1,2,3);
CAD(proxy, "ServerMethodB");
proxy.ServerMethodB("abc");
more functionality could be implemented in CAD but this gives you the idea...you could even use it as a calling mechanism that calls the function with arguments if it exists, bypassing the extra step I introduced.
I assume your actual need is more complicated than the example, because you're doing nothing with the parameters you're passing to ServerMethodA and ServerMethodB, and otherwise you would just do something like
function RPC(url)
{
this.url = url;
}
RPC.prototype.callServerMethod = function(methodname, params)
{
AJAX.get(this.url+"?call="+ methodname);
}
var proxy = RPC("http://example.com/rpcinterface");
proxy.callServerMethod("ServerMethodA", [1,2,3]);
proxy.callServerMethod("ServerMethodB", "abc");

Categories

Resources