Skip to content

Instantly share code, notes, and snippets.

@hagino3000
Last active January 16, 2020 13:11
Show Gist options
  • Save hagino3000/2290705 to your computer and use it in GitHub Desktop.
Save hagino3000/2290705 to your computer and use it in GitHub Desktop.
__noSuchMethod__ for Chrome
/**
* Enable route to __noSuchMethod__ when unknown method calling.
*
* @param {Object} obj Target object.
* @return {Object}
*/
function enableMethodMissing(obj) {
var functionHandler = createBaseHandler({});
functionHandler.get = function(receiver, name) {
return function(){};
}
var calledProperty;
var trapFn = Proxy.createFunction(functionHandler, function() {
return obj.__noSuchMethod__(calledProperty, Array.prototype.slice.call(arguments));
});
var propertyAccessHandler = createBaseHandler(obj);
propertyAccessHandler.get = function(receiver, name) {
if (name in obj) {
return obj[name];
} else {
calledProperty = name;
return trapFn;
}
}
return Proxy.create(propertyAccessHandler);
/**
* Create trap functions (internal)
*
* @param {Object} obj Original object.
* @return {Object} Proxy handler.
*/
function createBaseHandler(obj) {
return {
getOwnPropertyDescriptor: function(name) {
var desc = Object.getOwnPropertyDescriptor(obj, name);
if (desc !== undefined) { desc.configurable = true; }
return desc;
},
getPropertyDescriptor: function(name) {
var desc = Object.getPropertyDescriptor(obj, name);
if (desc !== undefined) { desc.configurable = true; }
return desc;
},
getOwnPropertyNames: function() {
return Object.getOwnPropertyNames(obj);
},
getPropertyNames: function() {
return Object.getPropertyNames(obj);
},
defineProperty: function(name, desc) {
return Object.defineProperty(obj, name, desc);
},
delete: function(name) {
return delete obj[name];
},
fix: function() {
if (Object.isFrozen(obj)) {
return Object.getOwnPropertyNames(obj).map(function(name) {
return Object.getOwnPropertyDescriptor(obj, name);
});
}
return undefined;
},
has: function(name) {
return name in obj;
},
hasOwn: function(name) {
return Object.prototype.hasOwnProperty.call(obj, name);
},
set: function(receiver, name, val) {
// No check
// But normally needs checking property descriptor
obj[name] = val;
},
enumerate: function() {
var result = [];
for (var name in obj) { result.push(name); }
return result;
},
keys: function() {
return Object.keys(obj);
}
};
}
}
var Ninja = function(name, age) {
this.name = name;
this.age = age;
return enableMethodMissing(this);
}
Ninja.prototype.getName = function() {
return this.name;
}
Ninja.prototype.__noSuchMethod__ = function(methodName, args) {
console.log('method name:' + methodName);
console.log(args);
};
var sasuke = new Ninja('Sasuke', 0);
sasuke.getName(); // => Sasuke
sasuke.hoge(1,2,3); // => __noSuchMethod__('hoge', [1,2,3])
sasuke.hoge; // => undefined
sasuke.age; //=> 0
@piroor
Copy link

piroor commented Apr 5, 2012

How different from noSuchMethod ?

@hagino3000
Copy link
Author

This works same as noSuchMethod
But I think noSuchMethod is non-standard, but Proxy will be ECMAScript standard.

@piroor
Copy link

piroor commented Apr 5, 2012

Yes, it was my real question: why you use the name "methodMissing" different from "noSuchMethod" ? I think I should use well known name if the feature newly implemented is similar to the old one. Of course, it's just a matter of taste...

@hagino3000
Copy link
Author

Make sense. I fixed.

@gbosetti
Copy link

How can I use this? I got a "Proxy is not defined" error. See: http://jsfiddle.net/795Z4/

@stephan-nordnes-eriksen
Copy link

I am getting "Proxy is not defined" in node webkit :( Is there a work-around?

@CamiloMM
Copy link

This needs a flag. Go to chrome:flags or just wait until it's ready (it's not like it's going to be of much use for now, unless you're making like a Firefox or Chrome extension)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment