I think this is fairly simple,
Is there a simple way to add a secondary name for a property (I think this one is String specific – I'm not sure), i.e.,
c = length // this line pseudo code
'hello world'.length // returns 11
'hello world'.c // this line is pseudo code, meant to return 11
In the example above, there's an alias created for the property length. Is that possible to do in JavaScript?
1. With Bracket Notation
With bracket notation, you can access the property like so:
'hello world'[c]
This does the same thing as 'hello world'.length
if c
is 'length'
as a string.
var c = 'length';
console.log('hello world'[c]);
The only difference is that the property is a string. Bracket notation is a property accessor.
2. With Object.defineProperty()
Now if you want an alias:
Object.defineProperty(String.prototype, 'c', {
get: function() {
return this.length;
}
});
console.log("hello world".c);
The above uses Object.defineProperty
to define a property for the existing object, String's prototype
object. That way, all instances of a string will have this new property. Per the documentation:
The
Object.defineProperty()
method defines a new property directly on an object, or modifies an existing property on an object, and returns the object.Syntax
Object.defineProperty(obj, prop, descriptor)
Where obj
is the object being modified, prop
is the new or existing property, and descriptor
is the descriptor for the new or existing property.
Thus, the above defines a property for the object String.prototype
, with name c
. Its descriptor is a get function which returns the length of this
. In the example above, this
refers to the string so it returns the length of the string. You can read more about getters here.
This can also be defined for more types by changing to the applicable prototype (obj
), such as using Object.prototype
instead. However, this has potential issues, as trying to return this.length
on an object without a length property will return undefined, as seen here. You can also use Object.defineProperties
to define multiple properties at a time.
To expand on @AndrewLi's answer, there are a bunch of alias-like things you can do with Object.defineProperty()
.
I'll write them as functions that relate a source object with property, sProp, and a target object with property, tProp. Source and target can be the same object (allowing a property to be an alias to another property on the same object), but this is not a requirement. Also, the source (or target) can be a prototype (like Object.prototype, String.prototype, etc..)
This one's not really an alias, nor does it use Object.defineProperty()
. The target is assigned the VALUE of the source, not a reference to it. This means that when the source changes, the target does not.
function assign(target, tProp, source, sProp) {
target[tProp] = source[sProp];
return target;
}
let myTarget = {}
let mySource = {b: 12}
myTarget = assign(myTarget, 'a', mySource, 'b')
// "alias" was assigned source value
console.log('"alias":',myTarget.a) // 12
// changes to source independent of "alias"
mySource.b = 13
console.log("source:", mySource.b) // 13
console.log('"alias":', myTarget.a) // still 12
When the property definition does not have a setter is it effectively a read-only value. Changes to the source property will be reflected in the alias; however, you cannot set the value of the alias.
function read(target, tProp, source, sProp){
Object.defineProperty(target, tProp, {
enumerable: true,
configurable: true,
get(){
return source[sProp];
}
})
return target;
}
let myTarget = {}
let mySource = {b: 12}
myTarget = read(myTarget, 'a', mySource, 'b')
// Alias gets value from source
console.log("alias:", myTarget.a) // 12
// No setter effectively means read-only
myTarget.a = 15
console.log("alias:", myTarget.a) // 12
// Changes to source are seen in target
mySource.b = 15
console.log("source:", mySource.b) //15
console.log("target:", myTarget.a) //15
This alias modifies the read-only version above to set the source property whenever the alias (target) property is set. In this way the source and target always remain in sync.
function sync(target, tProp, source, sProp){
Object.defineProperty(target, tProp, {
enumerable: true,
configurable: true,
get(){
return source[sProp];
},
set(value){
source[sProp] = value;
}
})
return target;
}
let myTarget = {}
let mySource = {b: 12}
myTarget = sync(myTarget, 'a', mySource, 'b')
// Alias gets value from source
console.log("alias:", myTarget.a) // 12
// Changing alias' value modifies the source
myTarget.a = 15
console.log("alias:", myTarget.a) // 15
console.log("source:", mySource.b) // 15
// Changing source modifies alias still
mySource.b = 20
console.log("source:", mySource.b) // 20
console.log("alias:", myTarget.a) // 20
This allows you to default an alias/target value until otherwise updated. Unlike the read-only case, you can change the alias/target value, yet unlike the the sync, when you change the alias you do not update the source - instead the alias becomes a regular value.
function setDefault(target, tProp, source, sProp){
Object.defineProperty(target, tProp, {
enumerable: true,
configurable: true,
get(){
return source[sProp];
},
set(value){
delete target[tProp];
target[tProp] = value;
}
})
return target;
}
let myTarget = {}
let mySource = {b: 12}
myTarget = setDefault(myTarget, 'a', mySource, 'b')
// Alias gets value from source
console.log('alias:', myTarget.a) // 12
// Changing source modifies alias still
mySource.b = 15
console.log('source:', mySource.b) // 15
console.log('alias:', myTarget.a) // 15
// Changing alias' value DOES NOT modify source
myTarget.a = 20
console.log("alias:", myTarget.a) // 20
console.log("source:", mySource.b) // 15
// The relationship between source and alias is BROKEN
mySource.b = 100
console.log("source:", mySource.b) // 100
console.log("alias:", myTarget.a) // 20
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With