How to pass an extra parameter despite having default parameters in Javascript? - javascript

Consider the example
var example = function(a = 10, b = 15, c) {
return c;
}
So, I want to call the example function with just the value of c. Something like,
example(20); // should return 20, without disturbing the values of a and b
How would I do this in JavaScript?

What you want is can be achieved with destructring assignment but it needs some mods. As i can see you are using es2015/es6 code for setting the default values. You might consider this:
var example = function([a = 10, b = 15, c]) {
console.log(a,b, c);
//return c;
}
example([,,20]);

You should consider using predefined variables in the end of function declaration:
var example = function(a, b = 10, c = 15 ) {
return a;
}
So result would be
example(20); // ->> 20

You could pass null as arguments for a and b when you call example.
var example = function(a = 10, b = 15, c) {
return c;
}
console.log(example(null, null, 20))
Or you could just use object as parameter.
var example = function(obj) {
obj.a = obj.a || 10;
obj.b = obj.b || 15;
return obj.c;
}
console.log(example({c: 20}))

You may have to use object instead :
var example = function(passed_options) {
$.extend( default_options, passed_options );
return c;
}
Hope this helps.
Sample snippet :
var example = function( passed_options ) {
$.extend( {a: 10, b: 15}, passed_options );
return passed_options.c;
}
console.log( example({c: 20}) );
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

You can use a parameter object to simulate named parameters:
var example = function(params) {
const a = params.a || 10;
const b = params.b || 15;
const c = params.c || 20;
}
and invoke:
example({c:42});

Related

Copy object via closure

I'm trying to get a copy of an object like this:
graphs = (function () {
var trends = {
pointSize: 10,
};
// Object Oriented JavaScript - pp 109
var lockVariable = function(x) {
return function() {
return x;
}
};
var getTrendsConfig = function() {
return lockVariable(trends)();
};
return {
getTrendsConfig : getTrendsConfig
};
}());
c = graphs.getTrendsConfig();
c.pointSize = 11;
console.log(graphs.getTrendsConfig())
I was expecting to get printed a "{pointSize: 10}"
Because the getTrendsConfig function would pass the trends object to the lockVariable function, which would return the local value object: "{pointSize : 10}", instead I get "{pointSize: 11}".
I'm taking this from an example of the book "Object Oriented JavaScript" pp 108-109:
How do I get my expected result? Is it possible? And why this doesn't work?
Primitive values, such as numbers, in JavaScript, are immutable. You can copy i to x (as per the book), change i and leave x unchanged.
Objects are not immutable and are only ever addressed by reference. When you return the value of trends (c = graphs.getTrendsConfig();), you are returning a reference to the object (so c and trends both contain a reference to the same object). When you modify it, you modify that object. Getting another copy of trends gives you another copy of the reference… which still points to the same object.
The simple way to deal with this is to move the logic that creates the object inside the function that gets called.
graphs = (function() {
var lockVariable = function(x) {
return function() {
return x;
}
};
var getTrendsConfig = function() {
var trends = {
pointSize: 10,
};
return lockVariable(trends)();
};
return {
getTrendsConfig: getTrendsConfig
};
}());
c = graphs.getTrendsConfig();
c.pointSize = 11;
console.log(graphs.getTrendsConfig())
Although you could simplify that to
graphs = (function() {
var getTrendsConfig = function() {
return {
pointSize: 10,
};
};
return {
getTrendsConfig: getTrendsConfig
};
}());
c = graphs.getTrendsConfig();
c.pointSize = 11;
console.log(graphs.getTrendsConfig())
To go with something close to what your original code is trying to acheive, you could return an explicit copy of the object by using Object.assign()
graphs = (function() {
var trends = {
pointSize: 10,
};
// Object Oriented JavaScript - pp 109
var lockVariable = function(x) {
return Object.assign({}, x);
};
var getTrendsConfig = function() {
return lockVariable(trends);
};
return {
getTrendsConfig: getTrendsConfig
};
}());
c = graphs.getTrendsConfig();
c.pointSize = 11;
console.log(graphs.getTrendsConfig())
graphs = (function () {
var trends = {
pointSize: 10,
};
// Object Oriented JavaScript - pp 109
var lockVariable = function(x) {
return function() {
return x;
}
};
var getTrendsConfig = function() {
return lockVariable(trends)();
};
return {
getTrendsConfig : getTrendsConfig
};
}());
c = Object.assign({}, graphs.getTrendsConfig()); // same as ...graphs.getTrendsConfig() in ES6 spread syntax
c.pointSize = 11;
console.log(graphs.getTrendsConfig());
console.log("c =", c);
It's not producing your expected result because you re-assigned c.pointSize to 11 and that's why you're getting 11;
In JavaScript, assigning an object to a variable is done by reference and not by value. This means that you're simply copying over the object's location in memory, causing any modification to affect the original value.
In your example when you assign c = graphs.getTrendsConfig();, c will now point to the same object's location/address.
When you did this c.pointSize = 11, you modified the same (original) object and not a copy.
Solution:
In other to make a copy of graphs.getTrendsConfig() you could use Object.assign() or the new ES6 spread syntax .... By making a copy you won't be modifying the original object's pointSize variable.

Why isn't my implementation of a Where function working?

I'm trying to implement a Where clause. My attempt
Object.prototype.Where = function ( boofunc ) {
// Returns an object whose own properties are
// those properties p of this object that satisify
// the condition boofunc(p)
var that = {};
for ( var prop in this )
{
var val = this[prop];
if ( boofunc(val) )
{
that.prop = val;
}
}
return that;
}
var obj = { x : 10, y : 11, z : 12 };
var evens = obj.Where(function(prop){obj.prop%2==0});
console.log(evens); // TEST
is not working (the object printed to the console doesn't have x, y or z). Or is there a better way of getting a filtered version of an existing object?
Try this:
Object.prototype.Where = function ( boofunc ) {
// Returns an object whose own properties are
// those properties p of this object that satisify
// the condition boofunc(p)
var that = {};
for ( var prop in this )
{
var val = this[prop];
if ( boofunc(val) )
{
that[prop] = val;
}
}
return that;
}
var obj = { x : 10, y : 11, z : 12 };
var evens = obj.Where(function(prop){ return prop % 2==0; });
console.log(evens); // TEST
Basically, you need to return the value from your boofunc, instead of just checking prop % == 0 you have to actually return its result.
Next, you had a couple of typos, such as obj.prop where obj doesn't exist and also setting the property like that[prop] = val; instead of that.prop = val;
Working fiddle: https://jsfiddle.net/t32jywje/1/

Swapping two properties of objects with function in javascript

I am trying to write a function that will take two objects, people in this case, and swap only two of their attributes. Here is my function for the Person:
function Person (tall, weight, gender, iq, favoriteColor) {
this.tall = tall;
this.weight = weight;
this.gender = gender;
this.iq = iq;
this.favoriteColor = favoriteColor;
}
var joe = new Person("6-2", 180, "male", 130, "blue");
var bob = new Person("5-11", 150, "male", 120, "red");
So i want to swap JUST their IQs and favoriteColor.
So far I have:
function Swap(a, b) {
var i = a;
a = b;
b = i;
console.log(a, b);
}
This obviously swaps all their properties, but i cannot figure out how to swap just two and still have them log as objects. I have tried:
function Swap(a, b) {
var a = a.iq + a.favoriteColor;
var b = b.iq + b.favoriteColor;
var i = a;
a = b;
b = i;
console.log(a, b);
}
but this returns in the console:
120red 130blue.
Technically it swapped the two values, but their structure as an object is gone and the other three properties that they were supposed to keep of their own are also gone. How do I write the swap function to do this?
Thanks!
This is what you want. You need to swap the individual fields. You can't add them like you are doing. Also, it's best not to use the same name for variables that you've already declared, it's just too confusing.
function Swap(a, b) {
var i = a.iq;
a.iq = b.iq;
b.iq = i;
i = a.favoriteColor;
a.favoriteColor= b.favoriteColor;
b.favoriteColor = i;
console.log(a, b);
}
function Swap(a, b) {
var newBIq = a.iq
var newBColor = a.favoriteColor;
var newAIq = b.iq
var newAColor = b.favoriteColor;
a.iq = newAIq;
a.favoriteColor = newAColor;
b.iq = newBIq;
b.favoriteColor = newBColor
console.log(a, b);
}
Here you see the 4 values needed. I hope the naming helps understanding better than just i,j :D
If we take this solution to swap values...
b = [a, a = b][0];
...we could do this...
function Swap(a, b) {
b.iq = [a.iq, a.iq = b.iq][0];
b.favoriteColor = [a.favoriteColor, a.favoriteColor = b.favoriteColor][0];
}
and if you can use ECMAScript 6, you could even do
function Swap(a, b) {
[a.iq, b.iq] = [b.iq, a.iq]
[a.favoriteColor, b.favoriteColor] = [b.favoriteColor, a.favoriteColor]
}
This will swap all the values for the keys in an array of keys between objects a and b:
function Swap(a,b, keys){
for(var i=0; i<keys.length; i++){
var currentKey = keys[i];
var temp = a[currentKey];
a[currentKey] = b[currentKey];
b[currentKey] = temp;
}
}

Programmatically create a new object

I am trying to create a function which will take arguments arg1, arg2... then pass them into a constructor for a new object C like so: new C(arg1, arg2...), so to make a new instance of C the user would simply have to call C(arg) instead of new C(arg). Here is my first attempt:
var C = function(a){ this.a = a; }
var Cn = function(){
new C.apply(this, arguments);
}
Cn(0) // Should make a new C with a property a equal to 0
new C(0) // ie the same as this
Edit: Note, I need it to take an arbitrary number of arguments and not use eval. I'm making a library implementing Algebraic Data Types in js.
Edit: The solution was to take Jeremy's Idea and adapt it to take an unbounded number of arguments:
var C = function() {
// A unique object so we can identify when we used the 'newless' constructor
var newlessConstructorObj = {}
// Check to see if C has been called with `new`
if(!(this instanceof C))
// If not pass arguments as single arg back to C
return new C(newlessConstructorObj, arguments);
// Check to see if we got here from the line above, if so the arguments were passed in the second arg
var args = (arguments[0] === newlessConstructorObj) ? arguments[1] : arguments
// Do stuff with args
this.a = args[0];
}
C(0);
new C(0);
If you want to be able to call the function with or without the new keyword, you have to follow this pattern:
C = function(a) {
if (!(this instanceof C)) {
return new C(a);
}
this.a = a;
}
so to create a new instance of "C":
c = new C(a);
and
c = C(a);
will both return a properly formed instance of C
I would have picked Fabrizio Calderan's solution any day, but because you want this specific functionality - here is what predecessors tell us:
you can apply arguments to prototype.constructor (but there are issues when doing it with native types, like Number):
var Cn = function(){
return C.prototype.constructor.apply(C, arguments);
}
Link: Instantiating a JavaScript object by calling prototype.constructor.apply
or.. use eval:
function construct(Constructor)
{
/*
* or Array.prototype.slice.call(arguments, 1).map(function() { ... })
* in JavaScript 1.6+, compatibles, and with augmented Array.prototype
*/
var args = [];
for (var i = 1, len = arguments.length; i < len; i++)
{
args[i - 1] = "arguments[" + i + "]";
}
/* or args.join(", ") if you need it pretty-printed */
return eval("new Constructor(" + args + ")");
}
function Foo()
{
window.alert(Array.prototype.slice.call(arguments, 0).join(", "));
}
var f = construct(Foo, /bar/g, {baz: 42});
Link: http://groups.google.com/group/comp.lang.javascript/browse_thread/thread/ff1a104bdc33d5c8
something like this?
var C = function(obj){
var a;
for (a in obj) {
this[a] = obj[a];
}
}
var Cn = function(obj) { return new C(obj); }
instance = Cn({
a : 1,
b : 2
})
instance.a //1
instance.b //2
instance.c //undefined
Doing it with a fixed number of args is simple:
// assuming one arg
function Cn(arg) {
return new C(arg);
}
// assuming two args
function Cn(arg0, arg1) {
return new C(arg0, arg1);
}
and so on. You can even make a general version for any number of parameters by iterating over arguments to create a string, then eval it. Crass, but effective.
But what's the point? Just to save typing 4 characters?
If you don't care about having a correct instanceof check you can try this:
var C = function(a){ this.a = a; }
var Cn = function(){
return C.apply({}, arguments); // notice an empty object here
}
Cn(0) // Should make a new C with a property a equal to 0
new C(0) // ie the same as this
Updated for ES6, you can use the spread operator:
var C = function(a){ this.a = a; }
var Cn = function(...args){
return new C(...args);
}
assert.deepStrictEqual(Cn(10), new C(10));

Create an object based on 2 others [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How can I merge properties of two JavaScript objects dynamically?
I have two objects a and b defined like this:
a = {
a: 1,
af: function() { console.log(this.a) },
};
b = {
b: 2,
bf: function() { console.log(this.b) },
};
What I want now is to create another object which will get the properties of a and b, like this:
c = {
a: 1,
af: function() { console.log(this.a) },
b: 2,
bf: function() { console.log(this.b) },
}
Note that a and b need to stay the same.
Any idea of how to do this ?
You could do a for in loop for both a and b, and copy all hasOwn properties to a new object.
var c = {};
for (var p in a)
if(a.hasOwnProperty(p))
c[p] = a[p];
for (var p in b)
if(b.hasOwnProperty(p))
c[p] = b[p];
DEMO
Or, if you happen to be using jQuery, you could do:
var c = $.extend({}, a, b);
var desc = Object.getOwnPropertyDescriptor,
props = Object.getOwnPropertyNames,
define = Object.defineProperty;
function extend( target ) {
return {
with: function( source ) {
props( source ).forEach(function( key ) {
define( target, key, desc( source, key ) );
});
}
};
}
So now we can go like
var c = Object.create( null );
extend( c ).with( a );
extend( c ).with( b );
Disclaimer: the provided codes assume we are in a ES5 or ES5 shimed environment !
var i, c={};
for (i in a) { if (a.hasOwnProperty(i)) { c[i] = a[i]; } }
for (i in b) { if (b.hasOwnProperty(i)) { c[i] = b[i]; } }
You can abstract this functionality into your own "extend" function similar to the one provided by jQuery:
function extend() {
var i, j, x, o=(arguments[0] || {});
for (i=1; i<arguments.length; i++) {
x = arguments[i];
for (j in x) { if (x.hasOwnProperty(j)) { o[j] = x[j]; } }
}
return o;
}
var c = extend({}, a, b);

Categories

Resources