Skip to content

Instantly share code, notes, and snippets.

@anba
Created June 14, 2013 12:52
Show Gist options
  • Save anba/9f0acbb29bf755d26f37 to your computer and use it in GitHub Desktop.
Save anba/9f0acbb29bf755d26f37 to your computer and use it in GitHub Desktop.
ECMAScript 6: automatically binding extracted methods (http://www.2ality.com/2013/06/auto-binding.html)
// http://www.2ality.com/2013/06/auto-binding.html
(function(global) {
const Function_bind = Function.prototype.call.bind(Function.prototype.bind);
function autoBind(obj) {
const handler = {
get(target, name, receiver) {
const result = Reflect.get(target, name, receiver);
if (typeof result != 'function') {
return result;
}
return Function_bind(result, receiver);
}
};
return new Proxy(obj, handler);
}
const boundPrototypes = new WeakMap();
function getBoundPrototypeFromConstructor(constructor) {
const proto = constructor.prototype;
if (!boundPrototypes.has(proto)) {
boundPrototypes.set(proto, autoBind(proto));
}
return boundPrototypes.get(proto);
}
class BoundClass { }
BoundClass[getSym("@@create")] = function() {
return Object.create(getBoundPrototypeFromConstructor(this));
}
Object.defineProperty(BoundClass, getSym("@@hasInstance"), {
value(obj) {
if (obj != null && typeof obj == 'object') {
const boundProto = getBoundPrototypeFromConstructor(this);
if (boundProto === Reflect.getPrototypeOf(obj)) {
return true;
}
}
return Function.prototype[getSym("@@hasInstance")].call(this, obj);
}
});
class Person extends BoundClass {
constructor(name) {
this.name = name;
}
describe() {
return `I'm ${this.name}`;
}
}
class Employee extends Person {
constructor(name, title) {
super(name);
this.title = title;
}
describe() {
return `${super()} (${this.title})`;
}
}
global.Person = Person;
global.Employee = Employee;
// tests
let jill = new Person('Jill');
let jillDescribe = jill.describe;
let john = new Employee('John', 'CFO');
let johnDescribe = john.describe;
print(jill.describe()); // prints "I'm Jill"
print(jillDescribe()); // prints "I'm Jill"
print(john.describe()); // prints "I'm John (CFO)"
print(johnDescribe()); // prints "I'm John (CFO)"
print(jill instanceof Person && !(jill instanceof Employee)); // true
print(john instanceof Person && john instanceof Employee); // true
})(this);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment