【问题标题】:JavaScript custom arguments in constructor构造函数中的 JavaScript 自定义参数
【发布时间】:2018-04-02 11:25:45
【问题描述】:

我使用 JavaScript (ECMAScript 5)。我有这样的课:

我的班级

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

有时我需要设置一些属性,我想使用如下代码:

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

我需要将div1 作为id 传递,但它作为第三个参数传递。

我可以使用下面的代码来做:

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

但我想尽量减少代码编号,例如:

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

fiddle

我阅读了很多主题,但找不到任何解决方案。

有什么办法吗?

提前感谢。

【问题讨论】:

  • 链接的 jsfiddle 使用的三种方法中的任何一种有什么问题?
  • @guest271314 我想使用new elementClass(htmlType ="div",cssClass = "form-group",id = "div1") 来最小化代码。
  • jsfiddle 的第一个代码示例已经使用了这种模式。您是否希望在默认参数分配的范围内自动将属性分配给对象 - 只需传递或分配参数?
  • @guest271314 没错。

标签: javascript class constructor named-parameters


【解决方案1】:

将对象作为参数传递:

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

所以你可以这样做:

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

如果你想要默认参数/阻止扩展,你可以这样做:

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

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

所以如果你实例化它:

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

这会导致

{ some:"stuff", stays:"the same"}

【讨论】:

  • 我会把defaults去掉函数外,构造函数真的不需要每次都创建相同的常量对象。
  • @nina 什么,ES6 呢?
  • @Jonasw,Object.assign 是 ES6
【解决方案2】:

您的代码似乎已经使用默认参数,您还可以使用简写属性名称并返回 object 和 rest 参数以获取任何最初未定义的属性

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/

【讨论】:

  • 回答问题。但是这样方法2和3就不行了。
  • @AliSoltani “但是在这种情况下,方法 2 和 3 不起作用。” 不确定您的意思? Answer 的代码定义了函数的默认参数,如果没有传递,则设置为默认值,否则属性值被传递的值覆盖;并允许传递 N 个附加参数,这些参数也设置在返回的对象中。为什么需要四种不同的模式才能达到相同的结果?
  • 我在项目中使用了方法2和方法3,我倾向于更改elementClass以支持这种情况。
  • @AliSoltani "我在项目中使用了方法 2 和方法 3,我倾向于更改 elementClass 以支持这种情况。" ? Answer 的代码既定义了默认的预期参数,也允许将未明确声明的参数设置为属性,即返回对象的值。对于您决定任意更改功能的问题,无法得出结论性答案,请参阅stackoverflow.com/help/how-to-ask。无需“更改”返回预期结果的函数模式;这会导致问题的观众和您自己感到困惑。
  • 我问这个问题是为了了解其他人的意见。无论如何,我测试了您的代码,但在 IE 中不起作用,因为 Default parametersES5 中不起作用。我与ES5 合作过。
【解决方案3】:

执行此操作的一种简单方法是传入自定义对象,而不是传递单独的不同参数。

创建接口(可选)

您可以在您的类型文件中添加接口声明以提高您的智能性。

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

改变你的班级

/** @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"
});

使用默认对象

您可以使用默认设置对象并将其与设置参数合并,而不是让|| "Default Value" 无处不在。

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;    
})();

示例

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>

一些注意事项

JavaScript 类命名约定是 UpperCamelCase,因此您应该使用 ElementClass 而不是 elementClass。检查类是否已使用 new 或作为函数调用也是一个好主意。所以现在如果你做ElementClass({}) 而不是new ElementClass({}) 一个Exception 将被抛出。最后,我用ElementClassdefault settings Object 包裹在IIFE 中,这样它就不会被其他脚本访问/更改。

【讨论】:

    猜你喜欢
    • 2013-04-05
    • 1970-01-01
    • 2019-09-04
    • 1970-01-01
    • 1970-01-01
    • 2016-08-06
    • 2017-07-09
    • 1970-01-01
    相关资源
    最近更新 更多