Javascript 从构造上的参数设置任意对象属性

Javascript 从构造上的参数设置任意对象属性,javascript,jquery,oop,Javascript,Jquery,Oop,在Javascript中实例化对象时,我希望启用以下场景: 对象可以在没有任何参数的情况下实例化,并使用默认属性值创建 可以使用设置对象属性初始值的参数实例化对象 解决办法应: 不指定尚未在对象上定义的特性 允许设置任意数量的属性(无、部分或全部) 易于应用于脚本定义的任何对象,这意味着我们事先不知道可以设置哪些属性 jQuery是可以使用的,尽管纯JS解决方案是受欢迎的 采用以下对象构造函数: function User() { this.name = null; th

在Javascript中实例化对象时,我希望启用以下场景:

  • 对象可以在没有任何参数的情况下实例化,并使用默认属性值创建
  • 可以使用设置对象属性初始值的参数实例化对象
解决办法应:

  • 不指定尚未在对象上定义的特性
  • 允许设置任意数量的属性(无、部分或全部)
  • 易于应用于脚本定义的任何对象,这意味着我们事先不知道可以设置哪些属性
jQuery是可以使用的,尽管纯JS解决方案是受欢迎的

采用以下对象构造函数:

function User() {
    this.name = null;
    this.email = null;
    this.password = null;
}
该解决方案应允许我实现以下目标:

new User();
// User { name: null, email: null, password: null }

newuser();
//用户名{name:“passed value”,电子邮件:“passed value”,密码:“passed value”}

newuser();
//用户{name:“传递值”,电子邮件:null,密码:null}

newuser();
//用户{name:“传递值”,电子邮件:null,密码:null}

首先,我允许对象构造函数接受一个参数

function User(params) {
...
要允许提供任意数量的参数,
params
参数将接受对象文字:

new User({name: 'name 1', id: 1});
接下来,我将
params
对象传递给一个通用函数,该函数将处理从
params
对象到
target
对象的属性赋值

function setObjectProperties(params, target) {
}
setObjectProperties
函数需要验证是否正确传递了一些数据。它检查是否定义了
参数
目标

function setObjectProperties(params, target) {
    if (params !== undefined && target !== undefined) {

    }
}
一旦我们确信我们有东西要处理,就应该迭代参数并分配给对象属性

function setObjectProperties(params, target) {
    if (params !== undefined && target !== undefined) {
        $.each(params, function (i, property) {
            this[i] = property;
        }, target);
    }
}
使用jQuery的
$。每个
函数,它迭代一个对象属性,而没有迭代所有对象属性(如原型等)的副作用。这是可行的,但意味着我们需要处理
这个
$的回调闭包内被重新定义的副作用。每个
函数。我们现在不再知道最初的物体是什么

但是,jQuery的
$.proxy
函数的设计允许我们调用函数,同时指定我们希望使用的
this

function setObjectProperties(params, target) {
    if (params !== undefined && target !== undefined) {
        $.each(params, $.proxy(function (key, value) {
                this[key] = value;
        }, target));
    }
}
这里我们告诉jQuery将
this
设置为目标参数的值,该参数在对象构造函数中设置为
this
,如下所示:

function User(params) {
    this.name = null;
    this.email = null;
    this.password = null;

    setObjectProperties(params, this);
}
还有一个问题仍然存在,我们应该检查对象上声明的属性,看看是否可以分配传入的值:

function setObjectProperties(params, target) {
    if (params !== undefined && target !== undefined) {
        $.each(params, $.proxy(function (key, value) {
            if (this.hasOwnProperty(key)) {
                this[key] = value;
            }
        }, target));
    }
}

以下是完整的最终代码:

function setObjectProperties(params, target) {
    if (params !== undefined && target !== undefined) {
        $.each(params, $.proxy(function (key, value) {
            if (this.hasOwnProperty(key)) {
                this[key] = value;
            }
        }, target));
    }
}

function User(params) {
    this.name = null;
    this.email = null;
    this.password = null;

    setObjectProperties(params, this);
}

user1 = new User();
// User { name: null, email: null, password: null }

user2 = new User({ name: 'First Last' });
// User { name: "First Last", email: null, password: null }

user3 = new User({ name: 'First Last', age: '400' });
// User { name: "First Last", email: null, password: null }
与默认对象相结合使此操作非常简单:

function User(options) {
    var defaults = {
        name: null,
        email: null,
        password: null
    };
    var options = $.extend({}, defaults, options);
    console.log(options);

}

new User(); 
// null, null, null

new User({name : 'First'});
// First, null, null

new User({name : 'First', email: 'users.name@users-email.com'});
// First, users.name@users-email.com, null

new User({name : 'First', email: 'users.name@users-email.comm', password : 'password1'});
// First, users.name@users-email.com, password1
这就是它的工作原理:

如果不想添加调用函数时传递的额外属性,请使用下面的代码,而不是
$.extend()
。此功能与原始功能相同:

function setObjectProperties(defaults, options, target) {
    var options = options || {};
    for (var prop in defaults) { 
        target[prop] = (typeof options[prop] === "undefined") ?  defaults[prop] : options[prop];
    }
}
您可以将其包装在原始函数中,并按如下方式使用:

setObjectProperties(defaults, options, this);

您可以在这里看到这个替代方案:

为什么不使用
$.extend()
–或者甚至是一个简单的
for…in
循环–来代替所有的
$。each()
混乱?这是一个不必要的复杂实现。@MattBall-完全argree。Michael-查看我的答案,了解一种更简单的方法。解决方案不应分配尚未在对象上定义的属性。对象需要定义其属性,并且不能通过尚未定义的参数设置属性。这个解决方案能做到吗?@michaelward82-为什么这很重要?变量只能通过
选项
对象访问,因此它们不会覆盖函数中的任何其他内容。还有,你为什么还要将不必要的变量传递给函数?@michaelward82-如果你不想添加传递给函数的额外属性,我已经用另一种方法更新了我的答案-不需要jQuery。谢谢,我们正在接近完美的解决方案:)但是,这需要解决。我需要这段代码存在于一个函数中,我可以(最坏的情况下)从我拥有的每个对象构造函数中使用一个简单的一行程序调用该函数。该函数似乎达到了许多期望的效果,只是它实际上没有创建或分配任何对象属性。删除当前的console.log并记录对象创建的结果,它显示所创建的对象没有公共属性。谢谢你迄今为止的努力,我觉得我们完成后会有一个很好的答案。目前,我的答案符合所有要求,但我确实认为我们可以做得比我的解决方案更好。
function User(options) {
    var defaults = {
        name: null,
        email: null,
        password: null
    };
    var options = $.extend({}, defaults, options);
    console.log(options);

}

new User(); 
// null, null, null

new User({name : 'First'});
// First, null, null

new User({name : 'First', email: 'users.name@users-email.com'});
// First, users.name@users-email.com, null

new User({name : 'First', email: 'users.name@users-email.comm', password : 'password1'});
// First, users.name@users-email.com, password1
function setObjectProperties(defaults, options, target) {
    var options = options || {};
    for (var prop in defaults) { 
        target[prop] = (typeof options[prop] === "undefined") ?  defaults[prop] : options[prop];
    }
}
setObjectProperties(defaults, options, this);