Last active
September 18, 2015 10:44
-
-
Save ochafik/1e54b00f14595a230883 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Gets a property descriptor for a target instance, skipping its class | |
* and walking up the super-classes hierarchy. | |
* | |
* @private | |
* @param {!Object} target | |
* @param {!string} name | |
* @return {!Object.<ObjectPropertyDescriptor>|undefined} | |
*/ | |
$jscomp.getSuperPropertyDescriptor_ = function(target, name) { | |
var getPrototypeOf = $jscomp.global.Object.getPrototypeOf; | |
var getOwnPropertyDescriptor = $jscomp.global.Object.getOwnPropertyDescriptor; | |
var cls = getPrototypeOf(target); | |
while (cls != null) { | |
cls = getPrototypeOf(cls); | |
var desc = getOwnPropertyDescriptor(cls, name); | |
if (desc != null) { | |
return desc; | |
} | |
} | |
return undefined; | |
}; | |
/** | |
* Gets a property of a target instance using its super class getter or value, | |
* or returns undefined if that property is not defined on any ancestor. | |
* | |
* @param {!Object} target | |
* @param {!string} propertyName | |
* @return {*} | |
*/ | |
$jscomp.superGet = function(target, propertyName) { | |
var desc = $jscomp.getSuperPropertyDescriptor_(target, propertyName); | |
return desc && (desc.get ? desc.get.call(target) : desc.value); | |
}; | |
/** | |
* Gets a method of a target instance on its super class, and binds it to the | |
* target. Note that functions returned by super getters are also treated as | |
* methods for all practical purposes. | |
* | |
* @param {!Object} target | |
* @param {!string} methodName | |
* @return {!Function} | |
*/ | |
$jscomp.superGetBound = function(target, methodName) { | |
var method = $jscomp.superGet(target, methodName); | |
if (!(method instanceof Function)) { | |
throw new Error('Not a function: ' + method); | |
} | |
return method.bind(target); | |
}; | |
/** | |
* Sets a property on a target instance using its super setter if is defined | |
* on any ancestor, or setting it as a simple property on the target otherwise. | |
* | |
* @param {!Object} target | |
* @param {!string} propertyName | |
* @param {*} value | |
*/ | |
$jscomp.superSet = function(target, propertyName, value) { | |
var desc = $jscomp.getSuperPropertyDescriptor_(target, propertyName); | |
if (desc) { | |
if (!desc.setter) { | |
throw new TypeError('No setter for super.' + propertyName); | |
} | |
desc.setter.call(target, value); | |
} | |
target[propertyName] = value; | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script src='example.js'></script> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
class SuperClass { | |
get value() { return 1 } | |
get f() { return function() { return this.value } } | |
} | |
class ThisClass extends SuperClass { | |
test() { return super.f(); } | |
} | |
var c = new ThisClass(); | |
console.log(c.test()); | |
console.log(c); | |
class SuperClass { | |
set x(v) {} | |
} | |
class ThisClass extends SuperClass { | |
// get x() {} | |
test() { | |
// super.foo = 'bar'; | |
// super.bar; | |
window.console.log(super.x); | |
// this.x; | |
// this.x = 1; | |
// super.x = 1; | |
} | |
} | |
new ThisClass().test(); | |
"use strict"; | |
class Granny { | |
get x() { return "Granny" } | |
} | |
class Mommy extends Granny { | |
set x(v) { console.log("Mommy.x = " + v) } | |
} | |
class Me extends Mommy { | |
get x() { return "Me" } | |
test() { | |
// this.x = "Value for this.x"; | |
super.x = "Value for super.x"; | |
console.log("super.x = " + super.x); | |
console.log("this.x = " + this.x); | |
} | |
} | |
new Me().test(); | |
"use strict"; | |
class SuperClass { | |
set x(v) { | |
this.v = v; | |
} | |
} | |
class ThisClass extends SuperClass { | |
set x(v) { | |
super.x = v; | |
super.y = v; | |
} | |
}; | |
var c = new ThisClass(); | |
c.x = 1; | |
// super.x existed and was called: it set `this.v`. | |
console.log("c.x = " + c.x); // -> undefined | |
console.log("c.v = " + c.v); // -> 1 | |
// super.y didn't exist: not an issue, it was set on the instance. | |
console.log("c.y = " + c.y); // -> 1 | |
"use strict"; | |
class Base { | |
get x() { return this.value; } | |
} | |
class Sub extends Base { | |
get x() { | |
console.log("super.x = " + super.x); | |
console.log("Base.prototype.x = " + Base.prototype.x); | |
console.log("super.prototype.x = " + super.prototype.x); | |
} | |
} | |
Base.prototype.value = "value of Base.prototype"; | |
var sub = new Sub(); | |
sub.value = "value of the instance"; | |
sub.x; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment