提问者:小点点

Javascript模型默认值:任何定义良好的技术?


我正在编写angularjs模型服务。然而,我想要一些方便的方法来设置默认值和嵌套模型。

这就是我得出的解决方案。

var Model = function () {
    this.assign = function (obj, members_to_set) {
        if (typeof obj !== 'undefined') {
            angular.forEach(members_to_set, function (member, index) {
                if (typeof obj[member] !== 'undefined') {
                    this[member] = obj[member];
                }
            }, this);
        }
    };



    this.assignList = function (member, obj, setter, default_) {
        this[member] = [];
        if (typeof obj !== 'undefined' && typeof obj[member] !== 'undefined') {
            angular.forEach(obj[member], function (val, index) {
                this[member].push(setter(val));
            }, this);
        } else {
            this[member].push(default_);
        }
    };

}

使用它

var Car = function(car_data){
    var defaults = {
       make: '',
       year: '',
       manufacturer: ''
    }
    this.assign(defaults, ['make', 'year']);
    this.assign(car_data, ['make', 'year']);


    //Similarly
    this.assignList('owners', car_data, function(owner_data){
          return new Owner(owner_data);
    }, new Owner()}


}
Car.prototype = new Model();

但我确信,这些问题都已得到解决,而且解决办法也很清楚。我不想重新发明这个特殊的轮子。

因此,问题是:是否有更好的方法来做到这一点?


共2个答案

匿名用户

可能有一些库可以帮助您实现这一点,但是这些库可能还附带了大量您不需要的特性。

必须应用默认值可能是许多类型的对象所关心的问题,因此我将提取它自己函数中的行为,然后从模型中使用,而不是使它成为模型类逻辑的一部分。

另外,如果您想要节省内存,默认值应该在所有实例之间共享,而不是在每个实例上复制。由于这个原因,我们避免使用angular.extend

我省略了任何模块化以保持示例简单,但是您应该模块化您的代码!

//only extend when properties have a different value
function diffExtend(obj, data, keys) {
    (keys || Object.keys(data)).forEach(function (k) {
        if (obj[k] !== data[k]) obj[k] = data[k];
    });

    return obj;
}

//Base class for every models
function Model(data, keys) {
    diffExtend(this, data, keys);
}

//Concrete Car model
function Car(data) {
    //only copy over make and year, but we could avoid passing keys to copy everything
    Model.call(this, data, ['make', 'year']);
}

Car.prototype = diffExtend(Object.create(Model.prototype), {
    constructor: Car,

    //default values (only for primitives because these aren't mutable)
    make: 'default make',
    year: 2000
});

//instanciate a new car
var c = new Car({ make: 'test', year: 2000, invalidProperty: true });

c.make; //test
c.year; //2000
c.hasOwnProperty('make'); //true
c.hasOwnProperty('year'); //false because it's on the prototype
c.invalidProperty; //undefined

现在,对于assignList函数,可以简单地使用array.prototype.map

例如。

var data = [{ make: 'test1', year: 2001 }, { make: 'test2', year: 2002 }],
    list = data? 
        data.map(function (d) { return new Model(d)}) : 
        new Model({ make: 'default model' });

也许我还没有提供一个完整的解决方案来满足您的需求,但是我相信您现在应该已经具备了实现一个完全适合您需要的高效解决方案所需的知识。

匿名用户

一种常见的方法是使用extend设置默认值。extend由angular,jquery,underscore以及可能还有许多其他库支持。

用法简单

function Foo(defaults){
    this.a = 10;
    this.b = 11;
    angular.extend(this, defaults);
}

然后,当您创建一个foo时:

var f  = new Foo({a:100, c:200, d: {d1:100, d2:200}});

console.log(f);
// Foo {a: 100, b: 11, c: 200, d: Object}

请参阅:http://plnkr.co/edit/qrjrj8yfetsicbrpxbc5?p=预览

但这比你想要的要复杂得多。我希望这能帮上忙。