Parse object dot notation to retrieve a value of an object - javascript

I'm finding myself struggling with a little problem.
Let's say I've got an object:
var foo = {
bar: {
baz: true
}
};
Now I also have a String 'foo.bar.baz'. I'd now like to retrieve the value from the object using the string.
Please note: This is just an example, the solution needs to be dynamic.
Update:
I need the variable name also to be dynamic and parsed from the string. Also I can't be sure that my variable is a property of the window.
I have already built a solution using eval, but this is pretty ugly I think:
http://jsfiddle.net/vvzyX/

For example,
function get(obj, path) {
return path.split('.').reduce(function(obj, p) {
return obj[p]
}, obj);
}
Demo:
tree = {
foo: {
bar: 1,
baz: { quux: 3 },
},
spam: 1
}
console.log(get(tree, 'foo.baz.quux')) // 3

Here is how you can do this:
function getValue(namespace, parent) {
var parts = namespace.split('.'),
current = parent || window;
for (var i = 0; i < parts.length; i += 1) {
if (current[parts[i]]) {
current = current[parts[i]];
} else {
if (i >= parts.length - 1)
return undefined;
}
}
return current;
}
var foo = {
bar: {
baz: true
}
};
console.log(getValue('foo.bar.baz')); //true
The first argument of the function is the namespace (dot separated values) and the second one is the parent object, if parent is not provided then window is used.
One more example using the parent argument:
var str = 'foo.bar.baz';
foo = {
bar: {
baz: true
}
};
result = getValue(str, foo);
console.log(result);
Here is an example in jsfiddle.
Similar approach is used in YUI. Their approach is called Namespace pattern. The main benefit is simulation of packages/namespaces. The only difference between this script and the namespace pattern is that the namespace function creates nested structure instead of only returning value.

Try this:
var name = [window].concat('foo.bar.baz'.split('.')).reduce(function(prev, curr) {
return prev[curr];
});
console.log(name);
// -> 'true'

What I can think of is using string split to split that string into an array first, and access the object via [] to access the attribute of that object with a loop

Related

Is there any way to intercept methods triggered with [] in js? [duplicate]

I can't seem to find the way to overload the [] operator in javascript. Anyone out there know?
I was thinking on the lines of ...
MyClass.operator.lookup(index)
{
return myArray[index];
}
or am I not looking at the right things.
You can do this with ES6 Proxy (available in all modern browsers)
var handler = {
get: function(target, name) {
return "Hello, " + name;
}
};
var proxy = new Proxy({}, handler);
console.log(proxy.world); // output: Hello, world
console.log(proxy[123]); // output: Hello, 123
Check details on MDN.
You can't overload operators in JavaScript.
It was proposed for ECMAScript 4 but rejected.
I don't think you'll see it anytime soon.
The simple answer is that JavaScript allows access to children of an Object via the square brackets.
So you could define your class:
MyClass = function(){
// Set some defaults that belong to the class via dot syntax or array syntax.
this.some_property = 'my value is a string';
this['another_property'] = 'i am also a string';
this[0] = 1;
};
You will then be able to access the members on any instances of your class with either syntax.
foo = new MyClass();
foo.some_property; // Returns 'my value is a string'
foo['some_property']; // Returns 'my value is a string'
foo.another_property; // Returns 'i am also a string'
foo['another_property']; // Also returns 'i am also a string'
foo.0; // Syntax Error
foo[0]; // Returns 1
foo['0']; // Returns 1
Use a proxy. It was mentioned elsewhere in the answers but I think that this is a better example:
var handler = {
get: function(target, name) {
if (name in target) {
return target[name];
}
if (name == 'length') {
return Infinity;
}
return name * name;
}
};
var p = new Proxy({}, handler);
p[4]; //returns 16, which is the square of 4.
We can proxy get | set methods directly. Inspired by this.
class Foo {
constructor(v) {
this.data = v
return new Proxy(this, {
get: (obj, key) => {
if (typeof(key) === 'string' && (Number.isInteger(Number(key)))) // key is an index
return obj.data[key]
else
return obj[key]
},
set: (obj, key, value) => {
if (typeof(key) === 'string' && (Number.isInteger(Number(key)))) // key is an index
return obj.data[key] = value
else
return obj[key] = value
}
})
}
}
var foo = new Foo([])
foo.data = [0, 0, 0]
foo[0] = 1
console.log(foo[0]) // 1
console.log(foo.data) // [1, 0, 0]
As brackets operator is actually property access operator, you can hook on it with getters and setters. For IE you will have to use Object.defineProperty() instead. Example:
var obj = {
get attr() { alert("Getter called!"); return 1; },
set attr(value) { alert("Setter called!"); return value; }
};
obj.attr = 123;
The same for IE8+:
Object.defineProperty("attr", {
get: function() { alert("Getter called!"); return 1; },
set: function(value) { alert("Setter called!"); return value; }
});
For IE5-7 there's onpropertychange event only, which works for DOM elements, but not for other objects.
The drawback of the method is you can only hook on requests to predefined set of properties, not on arbitrary property without any predefined name.
one sneaky way to do this is by extending the language itself.
step 1
define a custom indexing convention, let's call it, "[]".
var MyClass = function MyClass(n) {
this.myArray = Array.from(Array(n).keys()).map(a => 0);
};
Object.defineProperty(MyClass.prototype, "[]", {
value: function(index) {
return this.myArray[index];
}
});
...
var foo = new MyClass(1024);
console.log(foo["[]"](0));
step 2
define a new eval implementation. (don't do this this way, but it's a proof of concept).
var MyClass = function MyClass(length, defaultValue) {
this.myArray = Array.from(Array(length).keys()).map(a => defaultValue);
};
Object.defineProperty(MyClass.prototype, "[]", {
value: function(index) {
return this.myArray[index];
}
});
var foo = new MyClass(1024, 1337);
console.log(foo["[]"](0));
var mini_eval = function(program) {
var esprima = require("esprima");
var tokens = esprima.tokenize(program);
if (tokens.length == 4) {
var types = tokens.map(a => a.type);
var values = tokens.map(a => a.value);
if (types.join(';').match(/Identifier;Punctuator;[^;]+;Punctuator/)) {
if (values[1] == '[' && values[3] == ']') {
var target = eval(values[0]);
var i = eval(values[2]);
// higher priority than []
if (target.hasOwnProperty('[]')) {
return target['[]'](i);
} else {
return target[i];
}
return eval(values[0])();
} else {
return undefined;
}
} else {
return undefined;
}
} else {
return undefined;
}
};
mini_eval("foo[33]");
the above won't work for more complex indexes but it can be with stronger parsing.
alternative:
instead of resorting to creating your own superset language, you can instead compile your notation to the existing language, then eval it. This reduces the parsing overhead to native after the first time you use it.
var compile = function(program) {
var esprima = require("esprima");
var tokens = esprima.tokenize(program);
if (tokens.length == 4) {
var types = tokens.map(a => a.type);
var values = tokens.map(a => a.value);
if (types.join(';').match(/Identifier;Punctuator;[^;]+;Punctuator/)) {
if (values[1] == '[' && values[3] == ']') {
var target = values[0];
var i = values[2];
// higher priority than []
return `
(${target}['[]'])
? ${target}['[]'](${i})
: ${target}[${i}]`
} else {
return 'undefined';
}
} else {
return 'undefined';
}
} else {
return 'undefined';
}
};
var result = compile("foo[0]");
console.log(result);
console.log(eval(result));
You need to use Proxy as explained, but it can ultimately be integrated into a class constructor
return new Proxy(this, {
set: function( target, name, value ) {
...}};
with 'this'. Then the set and get (also deleteProperty) functions will fire. Although you get a Proxy object which seems different it for the most part works to ask the compare ( target.constructor === MyClass ) it's class type etc. [even though it's a function where target.constructor.name is the class name in text (just noting an example of things that work slightly different.)]
So you're hoping to do something like
var whatever = MyClassInstance[4];
?
If so, simple answer is that Javascript does not currently support operator overloading.
Have a look at Symbol.iterator. You can implement a user-defined ##iterator method to make any object iterable.
The well-known Symbol.iterator symbol specifies the default iterator for an object. Used by for...of.
Example:
class MyClass {
constructor () {
this._array = [data]
}
*[Symbol.iterator] () {
for (let i=0, n=this._array.length; i<n; i++) {
yield this._array[i]
}
}
}
const c = new MyClass()
for (const element of [...c]) {
// do something with element
}

How to avoid writing ugly code while dealing with object properties in javascript

I find that when I write javascript I encounter a situation where I am forced to write ugly code. This is due to my inability to reconcile the following two criteria:
1) Define data using shorthand, e.g. var data = { a: 1, b: { c: 2, d: 3 ... } }
2) Use a primitive operator to check for property existence
For example consider a function which returns the intersection of two Object instances' keys as an Array of the intersecting keys:
var intersection = function(obj1, obj2) {
var result = [];
for (var k in obj1) if (k in obj2) result.push(k);
return result;
};
That code looks quite nice. But unfortunately, it doesn't always work as expected! This is due to the inconsistency between for (x in y), and if (x in y): Using for (x in y) will only iterate over "own" properties (properties which return true for hasOwnProperty), while if (x in y) while apply for "own" and "non-own" properties!
If I call intersection like so:
var obj1 = { toString: 'hahaha' };
var obj2 = {};
var intersectingKeys = intersection(obj1, obj2);
I will wind up with intersectingKeys === [ 'toString' ]; Obviously this is not correct: an intersection operation involving an empty set (as obj2 appears to be) must return an empty set. While {} is clearly intended to be "empty", our problem is that ('toString' in {}) === true. This also applies to terms such as 'constructor', 'valueOf', as well as any new properties that are introduced to Object.prototype in the future.
In my opinion, if a native operator can provide iteration over keys, a native operator should be able to verify whether a key will appear in an iteration. It feels inconsistent and ugly, to me, to use a native operator for one, but a function call for the other. For that reason I dislike this fix:
var safeIntersection = function(obj1, obj2) {
var result = [];
for (var k in obj1) if (obj2.hasOwnProperty(k)) result.push(k);
return result;
};
If if (x in y) must be used, I only see one other possible solution: Ensure that the parameters passed to intersection have no properties at all, apart from properties explicitly defined by our code. In other words, ensure that we only work with prototype-less objects:
var obj1 = Object.create(null, {
toString: {
configurable: true,
enumerable: true,
writable: true,
value: 'hahaha'
}
});
var obj2 = Object.create(null, {});
var intersectingKeys = intersection(obj1, obj2);
Note that this code uses intersection, not safeIntersection, and still works because obj1 and obj2 are prototype-less. But the problem is, now data definition is really, really clunky! Look at how much code it takes to define an object with a single "toString" property. This approach prevents us from using javascript's beautiful object-shorthand. Even if we write a utility function to encompass prototype-less object creation, the definition of nested objects is still incredibly clunky:
// Utility function for prototype-less object definition
var obj = function(props) {
return Object.create(null, props.map(function(v) {
return {
writable: true,
configurable: true,
enumerable: true,
value: v
};
}));
};
// Now defining `obj1` looks ok...
var obj1 = obj({ toString: 'hahaha' });
// But for large, nested object definitions it's sooper ugly:
var big = obj({
a: 'a value',
b: 'b value',
moreProps: obj({
wheee: 'yay',
evenMoreProps: obj({
prop: 'propMeUp'
/* ... */
})
/* ... */
})
});
Javascript's object-definition shorthand is a huge perk of the language, and throwing it away by being forced to wrap all { ... } instances in a function call seems like a tremendous pity.
My ideal solution to this problem would involve converting the shorthand object constructor to produce prototype-less objects. Perhaps a global setting:
// Perhaps along with other global settings such as:
'use strict';
Error.stackTraceLimit = Infinity;
// We could also have:
Object.shorthandIncludesPrototype = false;
Although even if this solutions were available it would break tons and tons of pre-existing libraries. :(
How do I reconcile the following criteria???:
1) Write code that works
2) Use the primitive in operator to check for property existence
3) Define objects using typical shorthand
Perhaps it's impossible to meet all these criteria simultaneously. In that case, what are some of the next-best approaches for keeping code clean in these cases?
You could get first the own properties of the first object with Object.keys and filter with Object.hasOwnProperty the second object's keys.
function intersection(o1, o2) {
return Object.keys(o1).filter({}.hasOwnProperty.bind(o2));
}
console.log(intersection({ a: 10, b: 20, e: 30 }, { a: 10, c: 20, d: 30 })); // ['a']
console.log(intersection({ toString: 'hahaha' }, {})); // []
So, you've set out three incompatible requirements. You say you have to use in. You say objects have to be defined as {} so they will have a prototype. But, you don't like the way in works. And, you want code that uses those, but works differently than they are designed. Those are your two choices.
There's NO answer with those requirements. in works the way it does. You can't change it. We can't change it. Yes, it works differently based on the context, but that's how it's implemented. Deal with that by finding a practical solution to a real problem or write your own language that works the way you want the language to work.
FYI, for a real-world solution you may want to consider a Map object for storing your data and use .get(), .has() and .set() on it. Simple, clear, works.
Prior Answer BEFORE question was massively edited
First off, you can just use Object.create(null); to create a prototype-less object. So, the only properties it will have are the ones you put there.
I'd suggest that rather than accessing a property directly off the object, you just create one reusable function that checks to see if the property name is valid before returning it:
function sendValidProperty(req, res) {
var propName = req.params.propertyName;
if (Object.prototype.hasOwnProperty.call(dataObject, propName) {
res.send(dataObject[propName]);
} else {
res.sendStatus(400);
}
}
router.get('/propertyOfObject/:propertyName', function(req, res) {
sendValidProperty(req, res);
});
Or, you could encapsulate a smaller piece of it:
function getValidProperty(obj, propName) {
return Object.prototype.hasOwnProperty.call(dataObject, propName) ? obj[propName] : null;
}
router.get('/propertyOfObject/:propertyName', function(req, res) {
let val = getValidProperty(dataObject, res.params.propertyName);
if (val !== null) {
res.send(val);
} else {
res.sendStatus(400);
}
});
In either case, you don't have to repeat the checking of a property. That's in the common, shared function. FYI, when you want to use object methods on a prototype-less object, you can use the form I show above: Object.prototype.hasOwnProperty.call(dataObject, propName) instead of dataObject.hasOwnProperty(propName).
One of the main rules of server development is to NEVER trust the input you get from a request. You always have to check it or sanitize it before using it. This whole question kind of sounds like you're trying to avoid doing that. You just can't shortcut checking input and have a fully reliable server.
I have 2 extra solutions that are probably worth mentioning here:
1) Recursive obj function
As I mentioned in the question, having an obj method which creates an un-prototyped value from a regular Object defined via shorthand gets really ugly when it needs to be applied all throughout a nested shorthand structure - but this problem can be somewhat solved if the obj method is recursive, so that it only needs to be applied to the root Object and not explicitly to every inner child property:
var obj = function(val) {
if (val.constructor === Object) {
var ret = Object.create(null);
for (var k in val) ret[k] = obj(val[k]);
} else if (val.constructor === Array) {
var ret = [];
for (var i = 0; i < val.length; i++) ret.push(obj(val[i]));
} else {
var ret = val;
}
return ret;
};
var thing = obj({
prop1: 'hello',
prop2: 'hi',
prop3: [
{ num: 1, val: 'lalala' },
{ num: 2, val: 'heehee' },
{ num: 3, val: 'hoho' },
],
really: {
deep: {
property: {
over: {
here: { val: 'soooo deep' }
}
}
}
}
});
console.log('toString' in thing);
console.log('toString' in thing.prop3[1]);
console.log('toString' in thing.really.deep.property.over.here);
Now it's important that all shorthand objects are wrapped in obj.
2) Clear out Object.prototype
I've found that chrome and node (v0.12.0) will allow me to delete all properties from Object.prototype. The prototype can even be restored at any point in the future if these removed properties are kept in memory:
var savedPrototype = {};
var removePrototype = function() {
savedPrototype = {};
var props = Object.getOwnPropertyNames(Object.prototype);
for (var i = 0; i < props.length; i++) {
savedPrototype[props[i]] = Object.prototype[props[i]];
delete Object.prototype[props[i]];
}
};
var restorePrototype = function() {
for (var k in savedPrototype) {
Object.prototype[k] = savedPrototype[k];
}
};
removePrototype();
var obj = { val: 'haha' };
console.log('toString' in obj); // false
restorePrototype();
console.log('toString' in obj); // true
As jfriend00 already wrote, the question proposes constraints that are fundamentally impossible in the current versions of JavaScript. The best we can do is write some abstractions within the limitations of the language.
We've already looked at some possibilities, such as using a wrapper function (like obj() in the question). Because "universal support" is not a criterion in the question, I'll propose one solution using ES6 Proxies. We can use the has() handler method of a Proxy to alter the behavior of the in operator so that it only considers own properties:
Object.prototype.own = function () {
return new Proxy(this, {
has: function (target, propertyName) {
return target.hasOwnProperty(propertyName);
}
});
};
document.writeln('toString' in {});
document.writeln('toString' in {}.own());
document.writeln('foo' in { foo: 1 });
document.writeln('foo' in { foo: 1 }.own());
This requires a modern browser (no IE; Edge OK) or Node 6.4.0+. Of course, adding members to the prototype of Object is a risky move. We can add additional handlers to the Proxy as needed, or rewrite the implementation for ES5 and below (but this requires significantly more code).
Compatibility concerns aside, this approach satisfies the requirements of the question: we can use object literals and the in operator, and the code is concise and readable. We just need to remember to call own() when we need it.
We can rewrite the intersection() method from the question using this convention:
Object.prototype.own = function () {
return new Proxy(this, {
has: function (target, propertyName) {
return target.hasOwnProperty(propertyName);
}
});
};
var intersection = function(obj1, obj2) {
var result = [];
for (var k in obj1.own()) if (k in obj2.own()) result.push(k);
return result;
};
document.writeln(intersection({ a: 1, b: 2, c: 3 }, { b: 2, c: 3, d: 4}));
Your question could be solved with some beautiful code.
ES5
var intersect = function(obj1, obj2) {
var keys1 = Object.keys(obj1);
var keys2 = Object.keys(obj2);
return keys1.filter(function(k) {
return keys2.indexOf(k) !== -1;
});
}
ES6
let intersect = (obj1, obj2) => {
let keys1 = Object.keys(obj1);
let keys2 = Object.keys(obj2);
return keys1.filter(k => keys2.includes(k));
}
This is the JavaScript way of solving such problems. It is way better, since you don't need to use any loop. The built-in methods like filter(), indexOf() or includes() would perform better than any loop.

Javascript create reference to an object property?

I understand that in javascript, primitives are passed by value and objects are passed by reference.
I'm interested in creating a workaround of some kind that would let me get a reference to an object property containing a primitive. For example, what I wish would work is:
var someObject = {a: 1, b: 2};
var myRef = someObject.b;
myRef ++;
someObject.b #=> 3
Of course, this doesn't work. I'm aware that you could create a getter and setter function instead, or use one object to reference another object, but what I'd really like is some kind of workaround that allowed me to define a variable as a reference to the property of another object, and so far it seems this just can't be done.
So, my question is simply: is this even possible, and if so, how?
Primitive types are immutable, so no, it's not possible. You can wrap your primitive type with an object, like this:
function MyNumber(n) { this.n = n; }
MyNumber.prototype.valueOf = function() { return this.n; }
var someObject = { a: 1, b: new MyNumber(2) };
var myRef = someObject.b;
MyNumber.call(myRef, myRef + 1);
console.log(+someObject.b); // convert to number with +
OR
var someObject = {
a: { value: 1 },
b: { value: 2 },
};
var myRef = someObject.b;
my_inc(myRef); // function my_inc (obj) { obj.value++; }
// someObject.b.value == 3
The React framework uses a very simple pattern to encapsulate values.
function Link(value, requestChange)
{
this.value = value;
this.requestChange = requestChange;
}
You can pass around the object, the current value can be accessed by inspecting the value property of the object, if you want to change it you can call requestChange with a new value, you can change the value. The advantage would be to have the actual "storage location" and the logic for changing the value decoupled from the value read and write access. Note that the values can also be complex objects.
You could also achieve something similar with closures:
var someObject = {
a: 1,
b: 2
};
function property(object, prop) {
return {
get value () {
return object[prop]
},
set value (val) {
object[prop] = val;
}
};
}
var ref = property(someObject, "b");
ref.value; // 2
++ref.value; // 3
someObject.b; // 3
This works because the getter and setter functions have access to whatever bindings were in scope at the time of their creation (object and prop). You can now pass ref around, store it in a data structure, etc.
No, there isn't a nice way to do it.
You can use a work-around if you want to. Something like wrapping all your primary data types with single element arrays:
var someObject = {a: [1], b: [2]};
var myRef = someObject.b;
myRef[0]++;
someObject.b[0]; // 3
That's less than ideal though, as you have to use [0] to access the property all the time. There are some cases where it can be useful though, and the default toString of a single element array is just the toString of its element, so you can use the property directly in a string context:
console.log('My value: ' + someObject.b); // 'My value: 3'
if you want to "link" or "synchronize" two properties , each of a different object, you could do it like this:
var someObject = {
a: 1,
b: 2
};
var linkedObject = {
a:1,
b:2
}
function property(object, prop) {
return {
get value () {
return object[prop]
},
set value (val) {
object[prop] = val;
}
};
}
var s_prop = 'b'
var o_ref = property(someObject, s_prop);
var tmp = linkedObject[s_prop];
Object.defineProperty(
linkedObject,
s_prop,
{
set: function(value) {
o_ref.value = value;
},
get: function() {
return o_ref.value
}
}
);
linkedObject[s_prop] = tmp
someObject.b = 333 /// linkedObject.b is also 333 now
console.log(someObject.b) // 333
console.log(linkedObject.b)// 333
linkedObject.b = {"test": 2}
console.log(someObject.b) // {test:2}
console.log(linkedObject.b)// {test:2}
someObject.b.test = 3
console.log(someObject.b) // {test:3}
console.log(linkedObject.b)//{test:3}
I don't know how satisfying this is, but you could do it if you were ok with wrapping the desired object in an object like so:
var a = {a:{a:1},b:2};
var b = a.a;
b.a++;
a.a.a //=> 2
It isn't exactly what you asked for, but it would work.

How to conditionally add properties to a javascript object literal

I am trying to do the following to satisfy the requirements of a code builder (Sencha Cmd to be specific).
This is the essence I what I need to do. The critical factor is that the function body MUST end with a return of an object literal. I cant return a variable due to restrictions in the builder. So, how to add a property 'b' at the point of the pseudo code below if the parameter 'includeB' is true, but NOT add a property AT ALL if it is false. ie b==undefined or b==null is not allowed.
Perhaps it is not possible.
function create(includeB) {
// Can have code here but the final thing MUST be a return of the literal.
// ...
return {
a : 1
// pseudo code:
// if (includeB==true) then create a property called b
// and assign a value of 2 to it.
// Must be done right here within this object literal
}
}
var obj = create(false);
// obj must have property 'a' ONLY
var obj = create(true);
// obj must have properties 'a' and 'b'
Thanks for reading and considering,
Murray
If you can use ES6, use the spread properties.
function create(includeB) {
return {
a : 1,
...(includeB ? { b: 2 } : {}),
};
}
You've pretty much shown a use case for a constructor function instead of using an object literal:
function CustomObject(includeB) {
this.a = 1;
if (includeB) {
this.b = 2;
}
}
//has `a` only
var obj1 = new CustomObject(false);
//has `a` and `b`
var obj2 = new CustomObject(true);
After re-reading your question it appears that you've got limited access in modifying the function. If I'm understanding your question correctly you can only change a limited portion of the script:
function create(includeB) {
// modifications may be done here
// the rest may not change
return {
a : 1
}
}
var obj = create(false);
// obj must have property 'a' ONLY
var obj = create(true);
// obj must have properties 'a' and 'b'
If that's the case, then you could simply skip the later part of the function:
function create(includeB) {
if (includeB) {
return {
a: 1,
b: 2
};
}
return {
a: 1
};
}
You cannot put boolean logic inside a javascript literal definition. So, if your builder requires the the returned object can ONLY be defined as a javascript literal, then you cannot define properties conditionally that way.
If you can create an object inside your function, modify that object using logic and then return that object, then that's pretty easy.
function create(includeB) {
var x = {
a: 1
};
if (includeB) {
x.b = 2;
}
return x;
}
Your other option would be to wrap the create function and do it outside the create function.
function myCreate(includeB) {
var x = create(includeB)
if (includeB) {
x.b = 2;
}
return x;
}
Or, you could even wrap the create function transparently so callers still use create(), but it's behavior has been altered.
var oldCreate = create;
create = function(includeB) {
var x = oldCreate(includeB);
if (includeB) {
x.b = 2;
}
return x;
}
I recently had to do this, and found you could use a self-calling function within an object's definition (if using ES6). This is similar to the accepted answer, but might be useful for others who need to do this without first defining a constructor function.
For example:
let obj = (() => {
let props = { a: 1 };
if ( 1 ) props.b = 2;
return props;
})();
makes the object: { a: 1, b: 2 }
It's handy for more complicated objects, keeping the construction continuous:
let obj = {
a: 1,
b: (() => {
let props = { b1: 1 };
if ( 1 ) props.b2 = 2;
return props;
})(),
c: 3
}
makes the object:
{
a: 1,
b: {
b1: 1,
b2: 2
},
c: 3
}
You could define it later:
var hasA = create(); // has hasA.a
var hasBoth = create();
hasBoth.b = 2; //now has both
Alternatively, using your argument in create:
function create (includeB) {
var obj = {
a : 1
};
if (includeB) {
obj.b = 2;
}
return obj;
}
Below should work. I hope this help.
function create(includeB){
var object = {
a: 1
};
if (includeB)
object.b = 2;
return object;
}
How about this:
function create(includeB) {
return includeB && { a:1, b:2 } || { a:1 };
}
When includeB is true, the create function will return {a:1, b:2}. If includeB is false, it will return whatever is after the or - in this case, the {a:1} object.
create(true) returns { a:1, b:2 }.
create(false) returns { a:1 }
If you would like to use a declaration to satisfy the same requirement once without too much bloat, you can also simply do the following:
var created = function(includeB) {
var returnObj = { a : 1 };
if(includeB) { returnObj.b = 2; }
return returnObj;
}}(); //automatically runs and assigns returnObj to created

How do you access the main obj from obj.foo.bar in javascript?

Objects in javascript throw me for a loop!
In this set up...
var obj = {
someVar: "my awesome variable",
foo: {
bar: function(){
alert(this.someVar);
}
}
};
How would I get obj.foo.bar to correctly alert the value of someVar?
Using a captured obj:
var obj = {
someVar: "my awesome variable",
foo: {
bar: function(){
alert(obj.someVar);
}
}
};
alert(obj.someVar);
There's no clever way to walk up the ancestor chain. Objects don't know where they're contained, if you're looking for some type of this.parent type of notation. There's nothing to say that an object even has a single "parent".
foo.foo = new Object();
bar.bar = foo.foo;
bar.bar.parent == ???
A function in Javascript is invoked only in the context of the object which the . operator was applied to. It is not possible to walk up the chain, since Javascript objects are not intrinsically aware of their parent objects.
The only way to do this is to have a separate reference to obj. (Either as a property of bar or a separate variable)
Here's a generalized pattern I just cooked up for upwards traversal. Depending on your needs/assumptions, you can probably drop some complexity.
var obj = (function (parent) {
var obj = {
foo: "foo",
up: function () {
return parent;
}
};
obj.bar = (function (parent) {
var obj = {
baz: function () {
alert(this.up().foo);
},
up: function () {
return parent;
}
};
return obj;
}(obj));
return obj;
}(window));
obj.bar.baz(); // "foo"
It's almost certainly more trouble than it's worth.

Categories

Resources