1

I work with JavaScript (ECMAScript 5). I have a class like this:

My class

function elementClass(htmlType, cssClass, text, value, id) {
    this.htmlType = htmlType;
    this.cssClass = cssClass;
    this.text = text;
    this.value = value;
    this.id = id;
}

Sometimes I need set some properties and I want to use code like below:

var newElement = new elementClass(htmlType ="div",cssClass = "form-group",id = "div1");

I need to pass div1 as id but it passed as third argument.

I can use below code for do it:

var newElement3 = new elementClass();
newElement3.htmlType = "div";
newElement3.cssClass = "form-group";
newElement3.id = "div1";  

But I want to minimize the code numbers like:

var newElement = new elementClass(htmlType ="div",cssClass = "form-group",id = "div1");

fiddle

I read many topics but I couldn't find any solution for doing it.

Is there any way to do it?

Thanks advance.

5
  • What is the issue with either of the three approaches used at linked jsfiddle? Commented Oct 21, 2017 at 13:14
  • @guest271314 I want to use like new elementClass(htmlType ="div",cssClass = "form-group",id = "div1") to minimize the code. Commented Oct 21, 2017 at 13:16
  • The first code example at jsfiddle already does use that pattern. Are you expecting the properties to be assigned to the object automatically within the scope of the default parameter assignment - simply by passing or assigning the parameters? Commented Oct 21, 2017 at 13:17
  • @guest271314 Yes exactly. Commented Oct 21, 2017 at 13:19
  • See also Can we set persistent default parameters which remain set until explicitly changed? Commented Oct 21, 2017 at 13:23

3 Answers 3

2

Pass an object as a parameter:

function ElementClass ( settings ){
  for(var key in settings){
    this[key] = settings[key];
  }     
}

So you can do:

var instance = new ElementClass({
  some:"other"
});

If you want default parameters / prevent extension you could do:

function ElementClass( options ){
  var defaults = {
    some:"value"
    stays:"the same"
  };

  for(var key in defaults){
    this[key] = options[key] || defaults[key];
  }
}

So if you instantiate it:

 new ElementClass({
   some:"stuff", //overridden
   whatever:"unknown" //omitted
 });

It'll result in

{ some:"stuff", stays:"the same"}
Sign up to request clarification or add additional context in comments.

3 Comments

I'd take out the defaults outside the function, there's really no need for the constructor to be creating the same constant object every single time.
@nina what, wheres ES6?
@Jonasw, theObject.assign is ES6
0

You code appears to already use default parameters, you can also use shorthand property names and return the object and rest parameter to get any properties not initially defined

function elementClass({
  htmlType = "" // defaults to empty string
, cssClass = "" // defaults to empty string
, text = "" // defaults to empty string
, value = "" // defaults to empty string
, id = "" // defaults to empty string
, ...rest // handle any other properties passed as parameters
}) {
    return {htmlType, cssClass, text, value, id, ...rest}
}

$("#new1").click(function() {
    var newElement1 = new elementClass({
                        htmlType:"div"
                      , cssClass:"form-group"
                      , id:"div1"
                      , otherData:123
                      });
    showElement(newElement1);    
});

jsfiddle https://jsfiddle.net/3r8a6gbq/2/

9 Comments

Tanks for answer. But in this way method 2 and 3 don't work.
@AliSoltani "But in this way method 2 and 3 don't work." Not sure what you mean? The code at Answer defines default parameters to the function, which if not passed are set to the default, else the property value is overwritten by the value passed; and allows for N number of additional parameters to be passed which are also set at the returned object. Why would you need four different patterns to achieve same result?
I used method 2 and method 3 in my project and I tend to change elementClass for supporting this situation.
@AliSoltani "I used method 2 and method 3 in my project and I tend to change elementClass for supporting this situation." ? The code at Answer both defines default expected parameters and allows for parameters that are not explicitly declared to be set as properties, values of the returned object. There cannot be a conclusive Answer to a Question where you decide to change the function arbitrarily, see stackoverflow.com/help/how-to-ask. There is no need to "change" the pattern of the function which returns expected result; that leads to confusing viewers of Question and yourself.
I asked the question to know the opinions of other people. Anyway, I tested your code, but did not work in IE because Default parameters don't work in ES5. I worked with ES5.
|
0

A simple way to do this is by passing in a custom object instead of passing separate different parameters.

Creating an Interface (Optional)

You can add an interface declaration in your typings file for your intellisence.

interface ElementSettings {
    htmlType: string;
    cssClass: string;
    value: string;
    text: string;
    id: string;
}

Changing your Class

/** @param {ElementSettings} settings */
function ElementClass(settings) {
    // Throws an error if function is called without new
    if (!(this instanceof ElementClass)) {
        throw new TypeError("Cannot call a class as a function");
    }
    // Discards invalid input
    settings = settings instanceof Object ? settings : {};
    this.htmlType = settings.htmlType || "Default type";
    this.cssClass = settings.cssClass || "Default class";
    this.value = settings.value || "Default value";
    this.text = settings.text || "Default text";
    this.id = settings.id || "Default id";
}

// This can now be called using: 

new ElementClass({
    cssClass: "item",
    text: "Hello World"
});

Using a default Object

You can instead of having || "Default Value" everywhere have a default settings object and merge it with the settings parameter.

var ElementClass = (function() {
    var defaultSettings = {
        htmlType: "Default Type",
        cssClass: "Default Class",
        value: "Default Value",
        text: "Default Text",
        id: "Default Id"
    };

    /** @param {ElementSettings} settings */
    function ElementClass(settings) {
        // Throws an error if function is called without new
        if (!(this instanceof ElementClass)) {
            throw new TypeError("Cannot call a class as a function");
        }
        // Discards invalid input
        settings = settings instanceof Object ? settings : {};
        // In ES6 you could use Object.assign
        for (var property in defaultSettings) {
            this[property] = settings[property] || defaultSettings[property];
        }
    }

    return ElementClass;    
})();

Example

var ElementClass = (function () {
    var defaultSettings = {
        htmlType: "div",
        cssClass: "Default Class",
        value: "Default Value",
        text: "Default Text",
        id: "Default Id"
    };

    function ElementClass(settings) {
        if (!(this instanceof ElementClass)) throw new TypeError("Cannot call a class as a function");
        settings = settings instanceof Object ? settings : {};
        for (var property in defaultSettings) this[property] = settings[property] || defaultSettings[property];
        this.getDom = function getDom() {
            var dom = document.createElement(this.htmlType);
            dom.className = this.cssClass;
            dom.textContent = this.text;
            dom.value = this.cssClass;
            dom.id = this.id;
            return dom;
        };
    }

    return ElementClass;
})();

var form = document.querySelector("form");
var container = document.querySelector("#item-container");
form.addEventListener("submit", function (evt) {
    var formData = form.querySelectorAll("input:not([type='submit'])");
    var settings = {};
    formData.forEach(function (formItem) {
        var value = formItem.value;
        var name = formItem.getAttribute("name");
        if (value && name) settings[name] = value;
    });
    container.appendChild(new ElementClass(settings).getDom());
    evt.preventDefault();
});
#item-container>* {
background-color: rgba(100, 100, 100, 9.4);
min-width: 20px
min-height: 20px;
}
<form action="#">
  <input type="text" name="htmlType" placeholder="HTML Type" />
  <input type="text" name="cssClass" placeholder="CSS Class" />
  <input type="text" name="value" placeholder="Value" />
  <input type="text" name="text" placeholder="Text" />
  <input type="text" name="id" placeholder="Id" />
  <input type="submit" value="Create Object" />
</form>
<div id="item-container">

</div>

Some notes

JavaScript Class naming convention is UpperCamelCase so you should have ElementClass instead of elementClass. It is also a good idea to check if the Class has been called with new or as a function. So now if you do ElementClass({}) instead of new ElementClass({}) an Exception will be thrown. Finally, I wrapped the default settings Object in an IIFE with the ElementClass so that it will not be accessed/altered by other scripts.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.