1

I'm trying to make a change in one spot to affect the config object passed into all instantiations of an object. The object is made available globally as follows:

function Crayons(){
  return {
    foo: ThirdPartyFoo
  }
}

The object is initialized in my project with var myFoo = new Crayons().foo({color: "red"});

I'd like to make {color: "blue"} the default, so that if someone doesn't pass in a color, blue is set.

I tried doing

function Crayons(){
  var fooWithDefaults = function(){
    this = new ThirdPartyFoo(arguments); //this is invalid
    this.color = "blue"; //and this would overwrite color if it was set
  }

  return {
    foo: fooWithDefaults
  }
}

But the new keyword is throwing me off, as I don't know how to create a javascript constructor that essentially says this = new 3rdPartyFoo.

What am I missing?

Peter Seliger
  • 11,747
  • 3
  • 28
  • 37
adamdport
  • 11,687
  • 14
  • 69
  • 91
  • 3
    `this.color = given || "blue"` – Andrew Li Sep 07 '16 at 12:51
  • @AndrewL. that will work for the color, but I still don't know how to construct the object. – adamdport Sep 07 '16 at 12:55
  • Firstly `Crayons` is not implemented as a true constructor but as a factory instead. Thus, there is no need invoking it with the `new` operator. Secondly `Crayons` does not feature a method `foo`. If invoked it does return an object featuring a property `foo` that does refer to `ThirdPartyFoo` which possibly could be a constructor. Please correct your example to something that is at least valid code or can be run without throwing errors ( I'm referring to `var myFoo = new Crayons.foo({color: "red"});` ) – Peter Seliger Sep 07 '16 at 13:07
  • @PeterSeliger good catch, edited. better? – adamdport Sep 07 '16 at 13:11
  • Set default value for the argument at the definition of `ThirdPartyFoo` Such as `ThirdPartyFoo(arg = {color: 'blue'}){...code...}` – Redu Sep 07 '16 at 13:20
  • Define a constructor with 2 parameters. If one isn't passed it's undefined, then use || – Andrew Li Sep 07 '16 at 13:21

2 Answers2

2

You can either decorate the constructor:

function Crayons(){
  function fooWithDefaults() {
    3rdPartyFoo.apply(this, arguments); // this is what you're looking for
    if (!this.color) // or whatever to detect "not set"
      this.color = "blue";
  }
  fooWithDefaults.prototype = 3rdPartyFoo.prototype; // to make `new` work

  return {
    foo: fooWithDefaults
  }
}

Or you just make it a factory that returns an instance:

function Crayons(){
  function fooWithDefaults(arg) {
    var that = new 3rdPartyFoo(arg); // you should know how many arguments it takes
    if (!that.color) // or whatever to detect "not set"
      that.color = "blue";
    return that;
  }

  return {
    foo: fooWithDefaults
  }
}

Here you can also drop the new when calling var myFoo = Crayons.foo({color: "red"});

An alternative to modifying the instance after its creation would be to decorate the options that are passed in, which is in general the better solution:

function Crayons(){
  function fooWithDefaults(arg) {
    if (!arg.color) // or whatever to detect "not set"
      arg.color = "blue";
    return new 3rdPartyFoo(arg);
  }

  return {
    foo: fooWithDefaults
  }
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • I don't want to "drop the `new`" as I'm trying to avoid refactoring. Your first solution is what I was looking for though. Thanks! – adamdport Sep 07 '16 at 13:00
  • I meant you *can* drop `new` in the call to `fooWithDefaults`, not that you need to do it. I'd consider the third solution the cleanest one. – Bergi Sep 07 '16 at 13:35
0

function ThirdPartyCrayon(config) {           // constructor :: possible original Crayon implementation

    Object.assign(this, config);
    this.type = "thirdpartycrayon";
}


function createCrayonSetting(defaultConfig) { // factory (creates a closure)

    function CrayonWithDefaults() {           // constructor :: customized Crayon wrapper

        Object.assign(this, defaultConfig);
        ThirdPartyCrayon.apply(this, arguments);
    }

    return {
        Crayon: CrayonWithDefaults
    }
}


var
    setting = createCrayonSetting({color: "blue", strokeWidth: "thin"}),

    crayon1 = new setting.Crayon({color: "red", strokeWidth: "bold"}),
    crayon2 = new setting.Crayon({color: "green"});
    crayon3 = new setting.Crayon();


console.log("crayon1 : ", crayon1);
console.log("crayon2 : ", crayon2);
console.log("crayon3 : ", crayon3);
Peter Seliger
  • 11,747
  • 3
  • 28
  • 37