Skip to content

Instantly share code, notes, and snippets.

@hiddentao
Last active November 13, 2018 18:18
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save hiddentao/5946053 to your computer and use it in GitHub Desktop.
Save hiddentao/5946053 to your computer and use it in GitHub Desktop.
Generate overridable getters and setters in Javascript
// see blog post: http://www.hiddentao.com/archives/2013/07/08/generate-overridable-getters-and-setters-in-javascript/
Function.prototype.generateProperty = function(name, options) {
// internal member variable name
var privateName = '__' + name;
options = options || {};
options.get = ('undefined' === typeof options.get ? true : options.get );
options.set = ('undefined' === typeof options.set ? true : options.set );
// pre-initialise the internal variable?
if (options.defaultValue) {
this.prototype[privateName] = options.defaultValue;
}
var definePropOptions = {},
getterName = '__get_' + name,
setterName = '__set_' + name;
// generate the getter
if(true === options.get) {
this.prototype[getterName] = function() {
return this[privateName];
};
}
// use custom getter
else if (options.get) {
this.prototype[getterName] = options.get;
}
// disable getter
else {
this.prototype[getterName] = function() {
throw new Error('Cannot get: ' + name);
}
}
definePropOptions.get = function() {
return this[getterName].call(this);
};
// generate the setter
if(true === options.set) {
this.prototype[setterName] = function(val) {
this[privateName] = val;
};
}
// use custom setter
else if (options.set) {
this.prototype[setterName] = options.set;
}
// disable setter
else {
this.prototype[setterName] = function() {
throw new Error('Cannot set: ' + name)
};
}
definePropOptions.set = function(val) {
this[setterName].call(this, val);
};
// do it!
Object.defineProperty(this.prototype, name, definePropOptions);
};
@hiddentao
Copy link
Author

Example usage:

var ClassA = function() {}

ClassA.generateProperty('name', {
  defaultValue: 'john',
  get: function() {
    return this.__name + ' smith';
  },
  set: false
});

var a = new ClassA();

console.log(a.name);  // john smith

a.name = 'terry'; // Error: cannot set: name
console.log(a.name);  // john smith

a.__name = 'mark';
console.log(a.name);  // mark smith

Override in subclass:

var ClassB = function() {}
ClassB.prototype = Object.create(ClassA.prototype);

ClassB.prototype.__get_name = function() {
  return this.__name + ' oliver';
}

ClassB.prototype.__set_name = function(val) {
  this.__name = val;
}

var b = new ClassB();

console.log(b.name);  // john oliver

b.name = 'terry';
console.log(b.name);  // terry oliver

b.__name = 'mark';
console.log(b.name);  // mark oliver

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