Set default value of Javascript object attributes

Javascript

Javascript Problem Overview


Is there a way to set the default attribute of a Javascript object such that:

let emptyObj = {};
// do some magic
emptyObj.nonExistingAttribute // => defaultValue

Javascript Solutions


Solution 1 - Javascript

Since I asked the question several years ago things have progressed nicely.

Proxies are part of ES6. The following example works in Chrome, Firefox, Safari and Edge:

let handler = {
  get: function(target, name) {
    return target.hasOwnProperty(name) ? target[name] : 42;
  }
};

let emptyObj = {};
let p = new Proxy(emptyObj, handler);

p.answerToTheUltimateQuestionOfLife; //=> 42

Read more in Mozilla's documentation on Proxies.

Solution 2 - Javascript

Use destructuring (new in ES6)

There is great documentation by Mozila as well as a fantastic blog post that explains the syntax better than I can.

To Answer Your Question
var emptyObj = {};
const { nonExistingAttribute = defaultValue } = emptyObj;
console.log(nonExistingAttribute); // defaultValue
Going Further

Can I rename this variable? Sure!

const { nonExistingAttribute: coolerName = 15} = emptyObj;
console.log(coolerName); // 15

What about nested data? Bring it on!

var nestedData = {
    name: 'Awesome Programmer',
    languages: [
        {
            name: 'javascript',
            proficiency: 4,
        }
    ],
    country: 'Canada',
};

var {name: realName, languages: [{name: languageName}]} = nestedData ;

console.log(realName); // Awesome Programmer
console.log(languageName); // javascript

Solution 3 - Javascript

There isn't a way to set this in Javascript - returning undefined for non-existent properties is a part of the core Javascript spec. See the discussion for this similar question. As I suggested there, one approach (though I can't really recommend it) would be to define a global getProperty function:

function getProperty(o, prop) {
    if (o[prop] !== undefined) return o[prop];
    else return "my default";
}

var o = {
    foo: 1
};

getProperty(o, 'foo'); // 1
getProperty(o, 'bar'); // "my default"

But this would lead to a bunch of non-standard code that would be difficult for others to read, and it might have unintended consequences in areas where you'd expect or want an undefined value. Better to just check as you go:

var someVar = o.someVar || "my default";

Solution 4 - Javascript

my code is:

function(s){
    s = {
        top: s.top || 100,    // default value or s.top
        left: s.left || 300,  // default value or s.left
    }
    alert(s.top)
}

Solution 5 - Javascript

The way I achieve this is with the object.assign function

const defaultProperties = { 'foo': 'bar', 'bar': 'foo' };
const overwriteProperties = { 'foo': 'foo' };
const newObj = Object.assign({}, defaultProperties, overwriteProperties);
console.log(defaultProperties);  // {"foo": "bar", "bar": "foo"}
console.log(overwriteProperties);  // { "foo": "foo" };
console.log(newObj);  // { "foo": "foo", "bar": "foo" }

Solution 6 - Javascript

This sure sounds like the typical use of protoype-based objects:

// define a new type of object
var foo = function() {};  

// define a default attribute and value that all objects of this type will have
foo.prototype.attribute1 = "defaultValue1";  

// create a new object of my type
var emptyObj = new foo();
console.log(emptyObj.attribute1);		// outputs defaultValue1

Solution 7 - Javascript

This seems to me the most simple and readable way of doing so:

let options = {name:"James"}
const default_options = {name:"John", surname:"Doe"}

options = Object.assign({}, default_options, options)

Object.assign() reference

Solution 8 - Javascript

Or you can try this

dict = {
 'somekey': 'somevalue'
};

val = dict['anotherkey'] || 'anotherval';

Solution 9 - Javascript

I think the simplest approach is using Object.assign.

If you have this Class:

class MyHelper {
	constructor(options) {
		this.options = Object.assign({
			name: "John",
			surname: "Doe",
			birthDate: "1980-08-08"
		}, options);
	}
}

You can use it like this:

let helper = new MyHelper({ name: "Mark" });
console.log(helper.options.surname); // this will output "Doe"

Documentation (with polyfill): https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

Solution 10 - Javascript

Simplest of all Solutions:

dict = {'first': 1,
	    'second': 2,
        'third': 3}

Now,

dict['last'] || 'Excluded'

will return 'Excluded', which is the default value.

Solution 11 - Javascript

I saw an article yesterday that mentions an Object.__noSuchMethod__ property: JavascriptTips I've not had a chance to play around with it, so I don't know about browser support, but maybe you could use that in some way?

Solution 12 - Javascript

I'm surprised nobody has mentioned ternary operator yet.

var emptyObj = {a:'123', b:'234', c:0};
var defaultValue = 'defaultValue';
var attr = 'someNonExistAttribute';
emptyObj.hasOwnProperty(attr) ? emptyObj[attr] : defaultValue;//=> 'defaultValue'


attr = 'c'; // => 'c'
emptyObj.hasOwnProperty(attr) ? emptyObj[attr] : defaultValue; // => 0

In this way, even if the value of 'c' is 0, it will still get the correct value.

Solution 13 - Javascript

var obj = {
  a: 2,
  b: 4
};

console.log(obj);

--> {a: 2, b: 4}

function applyDefaults(obj) {
  obj.a ||= 10;
  obj.b ||= 10;
  obj.c ||= 10;
}

// do some magic
applyDefaults(obj);

console.log(obj);

--> {a: 2, b: 4, c: 10}

This works because

undefined || "1111111" --> "1111111"
"0000000" || "1111111" --> "0000000"

as null, undefined, NaN, 0, "" (Empty String), false itself, are all considered to be equivalent to false (falsy). Anything else is true (truthy).

Note that this is not uniformly supported across browsers and nodejs versions (confirm for yourself).

So two troublesome cases are the empty String "" and 0 (zero). If it is important not to override those, you might need to rewrite this as:

if (typeof obj.d == "undefined") obj.d = "default"

This will be better supported across browsers also.

Alternatively you could write this as:

obj.d ??= "default"

This is the nullish assignment which applies only to values that are null or undefined (nullish) - of which the empty string is not part. However, this has again a diminished cross-browser support.

See also on the official Mozilla Website - Assigning a default value to a variable.

Solution 14 - Javascript

This is actually possible to do with Object.create. It will not work for "non defined" properties. But for the ones that has been given a default value.

var defaults = {
    a: 'test1',
    b: 'test2'
};

Then when you create your properties object you do it with Object.create

properties = Object.create(defaults);

Now you will have two object where the first object is empty, but the prototype points to the defaults object. To test:

console.log('Unchanged', properties);
properties.a = 'updated';
console.log('Updated', properties);
console.log('Defaults', Object.getPrototypeOf(properties));

Solution 15 - Javascript

Object.withDefault = (defaultValue,o={}) => {
  return new Proxy(o, {
    get: (o, k) => (k in o) ? o[k] : defaultValue 
  });
}

o = Object.withDefault(42);
o.x  //=> 42

o.x = 10
o.x  //=> 10
o.xx //=> 42

Solution 16 - Javascript

One approach would be to take a defaults object and merge it with the target object. The target object would override values in the defaults object.

jQuery has the .extend() method that does this. jQuery is not needed however as there are vanilla JS implementations such as can be found here:

http://gomakethings.com/vanilla-javascript-version-of-jquery-extend/

Solution 17 - Javascript

If you only have an object that is a single level deep (nested object properties will not merge as expected since it directly destructures from the first level), you can use the following destructuring syntax:

const options = {
    somevar: 1234,
    admin: true
};

const defaults = {
    test: false,
    admin: false,
};

var mergedOptions = {...defaults, ...options};

Of which the output would be:

console.log(options);
// { somevar: 1234, admin: true }

console.log(mergedOptions);
// { test: false, admin: true, somevar: 1234 }

Or even formatted as a single statement (this is slightly unreadable though):

const options = {...{
    // Defaults
    test: false,
    admin: false,
}, ...{
    // Overrides
    somevar: 1234,
    admin: true
}};

Solution 18 - Javascript

I came here looking for a solution because the header matched my problem description but it isn't what i was looking for but i got a solution to my problem(I wanted to have a default value for an attribute which would be dynamic something like date).

let Blog = {
title  : String,
image  : String,
body   : String,
created: {type: Date, default: Date.now}
}

The above code was the solution for which i finally settled.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionsandstromView Question on Stackoverflow
Solution 1 - JavascriptsandstromView Answer on Stackoverflow
Solution 2 - JavascriptalexdriedgerView Answer on Stackoverflow
Solution 3 - JavascriptnrabinowitzView Answer on Stackoverflow
Solution 4 - JavascriptKiyanView Answer on Stackoverflow
Solution 5 - JavascriptColinView Answer on Stackoverflow
Solution 6 - Javascriptjfriend00View Answer on Stackoverflow
Solution 7 - Javascriptjoaquin kellerView Answer on Stackoverflow
Solution 8 - Javascriptuser1386350View Answer on Stackoverflow
Solution 9 - JavascriptgianlucaparadiseView Answer on Stackoverflow
Solution 10 - JavascriptGil BaggioView Answer on Stackoverflow
Solution 11 - JavascriptJames LongView Answer on Stackoverflow
Solution 12 - JavascriptAlan DongView Answer on Stackoverflow
Solution 13 - JavascriptYoYoView Answer on Stackoverflow
Solution 14 - JavascriptNilsView Answer on Stackoverflow
Solution 15 - JavascriptVlad VView Answer on Stackoverflow
Solution 16 - JavascriptDoug AmosView Answer on Stackoverflow
Solution 17 - JavascriptFlameView Answer on Stackoverflow
Solution 18 - JavascriptJibin PhiliposeView Answer on Stackoverflow