Skip to content

Instantly share code, notes, and snippets.

@XoseLluis
Last active August 14, 2019 15:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save XoseLluis/b6a3d96f22b48b32d961b83b1771f3e4 to your computer and use it in GitHub Desktop.
Save XoseLluis/b6a3d96f22b48b32d961b83b1771f3e4 to your computer and use it in GitHub Desktop.
Privatize a JavaScript (TypeScript) method at runtime
function calledFromInsideClass(className:string):boolean{
let stackTrace = (new Error()).stack; // Only tested in latest FF and Chrome
//console.log("stackTrace: " + stackTrace);
stackTrace = (stackTrace as string).replace(/^Error\s+/, ''); // Sanitize Chrome
let callerLine = stackTrace.split("\n")[2]; // 1st item is this function, 2nd item is the privatizedMethod, 3rd item is the caller
return callerLine.includes(className + ".");
}
function privatizeMethod(classFn: any, methodName: string){
let originalMethod = classFn.prototype[methodName];
let privatizedMethod = function(){
if (calledFromInsideClass(classFn.name)){
console.log("privatized method called from inside");
return originalMethod.call(this, ...arguments);
}
else{
throw new Error(`privatized method ${originalMethod.name} called`);
}
};
classFn.prototype[methodName] = privatizedMethod;
}
class City{
constructor(private name: string,
private extension: number,
private population: number){}
public growCity(percentage: number){
console.log("growCity invoked");
this.growExtension(percentage);
this.growPopulation(percentage);
}
public growExtension(percentage: number){
console.log("growExtension invoked");
this.extension = this.extension + (this.extension * percentage /100);
}
public growPopulation(percentage: number){
console.log("growPopulation invoked");
this.population = this.population + (this.population * percentage /100);
}
private privateMethod(){
console.log("I'm a private method");
}
}
let city = new City("Paris", 105, 2140000);
//city.privateMethod();
//trick to invoke a private method
(city as any).privateMethod();
city.growCity(2);
console.log(JSON.stringify(city, null, "\t"));
//privatize the the City.growPopulation method
privatizeMethod(City, City.prototype.growPopulation.name);
city.growCity(3); //continues to work fine, it invokes internally our new private method
try{
city.growPopulation(3);
}
catch(ex){
console.log("EXCEPTION: " + ex.message); ////EXCEPTION: privatized method growPopulation called
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment