Is it possible to get the object property name as a string
person = {};
person.first_name = 'Jack';
person.last_name = 'Trades';
person.address = {};
person.address.street = 'Factory 1';
person.address.country = 'USA';
I'd like to use it like this:
var pn = propName( person.address.country ); // should return 'country' or 'person.address.country'
var pn = propName( person.first_name ); // should return 'first_name' or 'person.first_name'
NOTE: this code is exactly what I'm looking for. I understand it sounds even stupid, but it's not.
This is what I want to do with it.
HTML
person = {};
person.id_first_name = 'Jack';
person.id_last_name = 'Trades';
person.address = {};
person.address.id_address = 'Factory 1';
person.address.id_country = 'USA';
extPort.postMessage
(
{
message : MSG_ACTION,
propName( person.first_name ): person.first_name
}
};
----------------------ANSWER-----------------------
Got it thanks to ibu. He pointed the right way and I used a recursive function
var res = '';
function propName(prop, value) {
for (var i in prop) {
if (typeof prop[i] == 'object') {
if (propName(prop[i], value)) {
return res;
}
} else {
if (prop[i] == value) {
res = i;
return res;
}
}
}
return undefined;
}
var pn = propName(person, person.first_name); // returns 'first_name'
var pn = propName(person, person.address.country); // returns 'country'
DEMO: http://jsbin.com/iyabal/1/edit
I know a best practice that using Object.keys(your_object). It will parse to array property name for you. Example:
var person = { firstName: 'John', lastName: 'Cena', age: '30' };
var listPropertyNames = Object.keys(person); //["firstName", "lastName", "age"]
I hope this example is useful for you.
You can accomplish this by converting all object properties into functions which will return the their own names
var person = {};
person.firstname = 'Jack';
person.address = "123 Street";
function getPropertyName(obj, expression) {
var res = {};
Object.keys(obj).map(k => { res[k] = () => k; });
return expression(res)();
}
let result = getPropertyName(person, o => o.address);
console.log(result); // Output: 'address'
If anyone's looking for a TypeScript version of MarsRobot's answer, try this:
function nameof<T>(obj: T, expression: (x: { [Property in keyof T]: () => string }) => () => string): string
{
const res: { [Property in keyof T]: () => string } = {} as { [Property in keyof T]: () => string };
Object.keys(obj).map(k => res[k as keyof T] = () => k);
return expression(res)();
}
Usage:
const obj = {
property1: 'Jim',
property2: 'Bloggs',
property3: 'Bloggs',
method: () => 'a string',
child: { property4: 'child1' }
};
const test1 = nameof(obj, x => x.property1);
const test2 = nameof(obj, x => x.property2);
const test3 = nameof(obj, x => x.method);
const test4 = nameof(obj.child, x => x.property4);
console.log(test1); // -> 'property1'
console.log(test2); // -> 'property2'
console.log(test3); // -> 'method'
console.log(test4); // -> 'property4'
This version works even when objects have multiple properties with the same value (unlike some of the other answers above), and with editors like Visual Studio will provide intellisense for the property names when you get here: nameof(obj, x => x.
You can wrap your property in a function and then convert the function to a string and get the property out of it.
For example:
function getPropertyName(propertyFunction) {
return /\.([^\.;]+);?\s*\}$/.exec(propertyFunction.toString())[1];
}
Then to use it:
var myObj = {
myProperty: "testing"
};
getPropertyName(function() { myObj.myProperty; }); // myProperty
Beware that minifiers could break this.
Edit: I have created a compiler transform that works with babel and the typescript compiler (see ts-nameof). This is a much more reliable than doing something at runtime.
Yes you can, with a little change.
function propName(prop, value){
for(var i in prop) {
if (prop[i] == value){
return i;
}
}
return false;
}
Now you can get the value like so:
var pn = propName(person,person.first_name);
// pn = "first_name";
Note I am not sure what it can be used for.
Other Note wont work very well with nested objects. but then again, see the first note.
Using Proxy:
var propName = ( obj ) => new Proxy(obj, {
get(_, key) {
return key;
}
});
var person = {};
person.first_name = 'Jack';
person.last_name = 'Trades';
person.address = {};
person.address.street = 'Factory 1';
person.address.country = 'USA';
console.log(propName(person).first_name);
console.log(propName(person.address).country);
I use the following in TypeScript. This way retains type-information and disallows selecting non-existing property keys.
export function getPropertyName<T extends object>(obj: T, selector: (x: Record<keyof T, keyof T>) => keyof T): keyof T {
const keyRecord = Object.keys(obj).reduce((res, key) => {
const typedKey = key as keyof T
res[typedKey] = typedKey
return res
}, {} as Record<keyof T, keyof T>)
return selector(keyRecord)
}
const obj = {
name: 'test',
address: {
street: 'test',
}
}
console.log(getPropertyName(obj, (x) => x.name)) // name
console.log(getPropertyName(obj.address, (x) => x.street)) // street
I like one liners, here's a generic solution:
const propName = (obj,type) => Object.keys(obj).find(key => obj[key] === type)
propName(person, person.age)
Following up on #David Sherret's answer with ES6 it can be made super simple:
propName = f => /\.([^\.;]+);?\s*\}$/.exec(f.toString())[1]
let prop = propName(() => {obj.name}); // myProperty
I prefer it clean and simple like this:
var obj = {
sessionId: 123,
branchId: 456,
seasonId: 789
};
var keys = Object.keys(obj);
for (var i in keys) {
console.log(keys[i]); //output of keys as string
}
You could create a namespacing method for the object. The method will need to mutate the object so that the strings becomes an object instead to hold two properties, a value and a _namespace.
DEMO: http://jsfiddle.net/y4Y8p/1/
var namespace = function(root, name) {
root._namespace = name;
function ns(obj) {
for( var i in obj ) {
var a = obj._namespace.split('.')
if ( a.length ) {
a.push(i);
}
if( typeof obj[i] == 'object' ) {
obj[i]._namespace = a.join('.');
ns(obj[i]);
return;
}
if( typeof obj[i] == 'string' ) {
var str = obj[i].toString();
obj[i] = {
_namespace: a.join('.'),
value: str
};
}
}
}
ns(root);
};
namespace(person, 'person');
console.log(person.address.street._namespace) // person.address.street
console.log(person.address.street.value) // 'Factory 1'
So now you can do:
var o = { message: MSG_ACTION };
o[ person.first_name._namespace ] = person.first_name.value;
extPort.postMessage(o);
I am in same situation.
Here is thy way to get it done using Lodash or UnderScore library, with one limitation of value to be unique:
var myObject = {
'a': 1,
'b': 2,
'c': 3
}
_.findKey(myObject, function( curValue ) { return myObject.a === curValue });
Plain JavaScript
function getPropAsString( source, value ){
var keys = Object.keys( source );
var curIndex,
total,
foundKey;
for(curIndex = 0, total = keys.length; curIndex < total; curIndex++){
var curKey = keys[ curIndex ];
if ( source[ curKey ] === value ){
foundKey = curKey;
break;
}
}
return foundKey;
}
var myObject = {
'a': 1,
'b': 2,
'c': 3
}
getPropAsString( myObject, myObject.a )
But, I would prefer to fix the code as solution. An example:
var myObject = {
'a': {key:'a', value:1},
'b': {key:'b', value:2},
'c': {key:'c', value:3}
}
console.log( myObject.a.key )
I am late to the party but I took a completely different approach, so I will throw in my approach and see what the community thinks.
I used Function.prototype.name to do what I want.
my properties are functions that when called return the value of the property, and I can get the name of the property (which is a function) using .name
Here is an example:
person = {
firstName(){
return 'John';
},
address(){
return '123 street'
}
}
person.firstName.name // 'firstName'
person.address.name // 'address'
Note:
you can't easily change the value of a property (e.g firstname) at run time in this case.
you would need to create a function (.name would be anonymous in this case) and this function would return a new named function which return the new value:
// note the () at the end
person.firstName = new Function('', 'return function firstName(){return "johny"}')();
person.firstName.name ; // 'firstName'
person.firstName(); // 'johny'
Improved Solution for TypeScript using PROXY from Isk1n solution:
//get property name
export function getPropertyName<T>(obj: any): T {
return new Proxy(obj, {
get(_, key) {
return key;
}
});
}
and usage:
sampleItem: TestClass = new TestClass();
getPropertyName<TestClass>(this.sampleItem).LayoutVersion
No, it's not possible.
Imagine this:
person.age = 42;
person.favoriteNumber = 42;
var pn = propName(person.age)
// == propName(42)
// == propName(person.favoriteNumber);
The reference to the property name is simply lost in that process.
I need to write a function in JavaScript that takes a number and returns an object that returns chainable functions (without using OOP).
Example:
func(3).not().not().equals(4)
would outputs false.
And:
func(5).equals(5)
would output: true
This is the code I have written:
const func = (obj) => {
const obj2 = {
not: () => {
return !obj
},
equals: (num) => {
return obj === num
}
}
return obj2
}
It works when I call func(3).not() or func(5).equals(5), but doesn't allow me to chain the functions so calling func(5).not().equals(5) returns an error saying that this is not a function.
What am I not seeing here?
That's a very weird way to compose functions. Let's think about what's actually happening.
func(3).not().not().equals(4)
// is equivalent to
not(not(equals(4)(3)))
// where
const not = x => !x;
const equals = x => y => x === y;
The simplest way to implement this chain would be as follows.
const equals = x => toBool(y => x === y);
const toBool = func => ({
not: () => toBool(x => !func(x)),
func
});
const example1 = equals(4).not().not().func(3);
const example2 = equals(5).func(5);
console.log(example1); // false
console.log(example2); // true
However, this is a forward chain. You want a backward chain. Unfortunately, there's a problem.
In a forward chain .func(x) marks the end of the chain.
In a backward chain .equals(x) marks the end of the chain.
This means that in a backward chain, you wouldn't be able to write the following expression.
func(3).not().not().equals(4).add(1)
// expected to be equivalent to
not(not(equals(4)(add(1)(3))))
// but actually equivalent to
not(not(equals(4)(3))).add(1)
// which evaluates to
false.add(1)
On the other hand, you would be able to do this quite easily using a forward chain.
const id = x => x;
const toNum = func => ({
add: x => toNum(y => x + func(y)),
equals: x => toBool(y => x === func(y)),
func
});
const toBool = func => ({
not: () => toBool(x => !func(x)),
func
});
const { add, equals } = toNum(id);
const example1 = equals(4).not().not().func(3);
const example2 = add(1).equals(4).not().not().func(3);
console.log(example1); // false
console.log(example2); // true
By the way, this is an object-oriented design pattern even though it doesn't make use of classes.
My advice would be to write plain old functions.
const add = (x, y) => x + y;
const equals = (x, y) => x === y;
const not = x => !x;
const example1 = not(not(equals(4, 3)));
const example2 = not(not(equals(4, add(1, 3))));
console.log(example1); // false
console.log(example2); // true
The simplest solutions are usually the best. Source: Occam's razor.
To return another object with the same methods that wraps the new value, simply call func again:
const func = (obj) => {
const obj2 = {
not: () => {
return func(!obj)
// ^^^^^^^^^^^^^^^^^
},
equals: (num) => {
return obj === num
}
}
return obj2
}
console.log(func(3).not().not().equals(4))
console.log(func(5).equals(5))
console.log(func(3).not())
You can use a closure to store both the initial input and the state of the operation:
const func = (input) => {
let not = false
const obj = {
not: () => {
not = !not
return obj
},
equals: (num) => {
return not ? input !== num : input === num
}
}
return obj;
}
console.log(func(5).not().equals(5))
console.log(func(5).not().not().equals(5))
console.log(func(5).not().equals(4))
console.log(func(5).not().not().equals(4))
You could take an object for return as interface and store value and negation.
var object = {
func: function (value) {
object.left = value;
return object;
},
not: function() {
object.negation = !object.negation;
return object;
},
equals: function (value) {
var result = value === object.value;
return object.negation ? !result : result;
}
},
func = object.func;
console.log(func(3).not().not().equals(4));
I am trying to implement Memoize function that takes Symbol() as an argument. Is there a way to add Symbol('foo') as an argument?
let obj = {};
let counter = 1;
function foo() {
counter += 1;
return counter;
}
function memoize(fn) {
const cache = {};
return (...args) => {
const stringifiedArgs = JSON.stringify(args);
const result = (cache[stringifiedArgs] = !cache.hasOwnProperty(
stringifiedArgs
)
? fn(...args)
: cache[stringifiedArgs]);
return result;
};
}
let id = Symbol('id');
const memoizedFoo = memoize(foo);
console.log(memoizedFoo(id)); // 2
console.log(memoizedFoo(null)); // 2
console.log(memoizedFoo(id)); // 2
console.log(memoizedFoo(null)); //2
console.log(memoizedFoo(5)); // 3
console.log(memoizedFoo(5)); // 3
console.log(memoizedFoo(obj)); // 4
console.log(memoizedFoo(obj)); // 4
console.log(memoizedFoo(4)); // 5
The reason it does not work is that a symbol has no JSON equivalent, and so JSON.stringify will return null for any Symbols in the arguments array.
One way to solve it is to apply toString to it:
const stringifiedArgs = JSON.stringify(
args.map(arg => typeof arg === "symbol" ? arg.toString() : arg)
);
You could of course extend this to other types, or else use a Map which supports any type as its keys.
How do I read and interpret the following line of a function:
const canUser = (permission) => (permissions) => (guideSlug) => {
This is the full function:
const canUser = (permission) => (permissions) => (guideSlug) => {
if (!permissions) return false;
const globalPermissions = permissions['*'] || {};
const guidePermissions = permissions[guideSlug] || {};
return globalPermissions[permission] || guidePermissions[permission] || false;
};
Edit
If I have an object like this:
export const checks = {
canInvite: canUser('invite'),
}
I'm importing canInvite into my component and then running that function, giving it a guideSlug (string) to run the function. It works and checks out, I'm just not entirely sure how to understand what this does from the const canUser function definition
Any clarity here would be helpful. Thanks!
const foo = function(x) { return x + 1 } can be loosely written as const foo = x => x + 1. The latter is called an arrow function
So
const canUser = (permission) => (permissions) => (guideSlug) => {
if (!permissions) return false;
const globalPermissions = permissions['*'] || {};
const guidePermissions = permissions[guideSlug] || {};
return globalPermissions[permission] || guidePermissions[permission] || false;
};
is same as
const canUser = function(permission) {
return function(permissions) {
return function (guideSlug) {
if (!permissions) return false;
const globalPermissions = permissions['*'] || {};
const guidePermissions = permissions[guideSlug] || {};
return globalPermissions[permission] || guidePermissions[permission] || false;
}
}
};
This is called partial application or currying, both are kinda same I'm not sure which is the accurate term here.
Here's a case where it's useful...
const foo = (x, y) => { /* something to be done with x and y */ }
let x = foo(a,b);
let y = foo(a,c);
let z = foo(a,d);
Here as you can see there's a lot as in the code which is kinda repetitive and less readable. Writing it in the following way solves the problem...
const foo = x => y => { /* something to be done with x and y */ }
let fooA = foo(a); // fooA is the `y => {}` function with `x = a` "partially applied"
let x = fooA(b);
let y = fooA(c);
let z = foo(a)(d); // you can still write it like this
Another advantage of such pattern is that you can pass around fooA to other function or if you want to store it in an abstraction of a like const somethingRelevantToA = { foo: foo(a), bar: "some other prop ofa" }.
Also you are reusing the logic if you want something like fooA and fooB and they have something in common like...
const foo = x => y => {
/* piece of code independent of x (this is being reused) */
/* piece of code dependent only on y or x and y both */
}
So basically instead of writing fooA and fooB separately you are writing foo and thus reusing the logic.
That piece of code can be rewritten in ES5 like this:
var canUser = function canUser(permission) {
return function (permissions) {
return function (guideSlug) {
if (!permissions) return false;
var globalPermissions = permissions['*'] || {};
var guidePermissions = permissions[guideSlug] || {};
return globalPermissions[permission] || guidePermissions[permission] || false;
};
};
};
This is called currying. Which, as state in this article, is the process of taking a function with multiple arguments and turning it into a sequence of functions each with only a single argument.
Assuming you have permissions and guideSlug defined somewhere,
var permissions = {'accounts':{'invite': true}, '*':{'home': '/'}};
var guideSlug = 'accounts';
You could call the function with:
canUser('invite')(permissions)(guideSlug)
var permissions = {'accounts':{'invite': true}, '*':{'home': '/'}};
var guideSlug = 'accounts';
var canUser = function(permission) {
return function(permissions) {
return function (guideSlug) {
if (!permissions) return false;
var globalPermissions = permissions['*'] || {};
var guidePermissions = permissions[guideSlug] || {};
console.log(globalPermissions);
console.log(guidePermissions);
return globalPermissions[permission] || guidePermissions[permission] || false;
}
}
};
console.log(canUser('invite')(permissions)(guideSlug));
One thing I noticed in your example is that it calls only the first function, which means it will return a function back to checks.canInvite when you call it here:
export const checks = {
canInvite: canUser('invite'),
}
I have encountered a question where I need to allow default args to be set on a function in JavaScript:
function dfltArgs(func, params) {
const strFn = func.toString()
console.log(strFn)
const args = /\(([^)]+)\)/.exec(strFn)[1].split(',')
const defaultVal = (arg, val) => typeof arg !== 'undefined' ? arg : val
return (...dynamicArgs) => {
const withDefaults = args.map((arg, i) =>
defaultVal(dynamicArgs[i], params[args[i]]))
return func(...withDefaults)
}
}
function add (a, b) { return a + b }
var add_ = dfltArgs(add,{b:9})
console.log(add_(10)) // Should be 19
var add_ = dfltArgs(add_,{b:3})
console.log(add_(10)) // Should now be 13
However, I need to be able to call this function more than once and overwrite previously set defaults:
var add_ = defaults(add,{b:9})
add_(10) // Should be 19
var add_ = defaultArguments(add_,{b:3})
add_(10) // Should now be 13
This does not work in my implementation, because the stringified function on the second call is: (...dynamicArgs) => {, etc.
How can I refactor this? Probably need to use bind somehow?
Instead of your complicated default args thing, why not just use some arrow functions with real default arguments:
var _add = (a, b = 8) => add(a, b);
That way you can easily change the bound things:
var add_ = (a = 2, b) => _add(a, b);
add_() // 10