【问题标题】:how to define attributes for all properties of an object simultaneously (or set default)如何同时为对象的所有属性定义属性(或设置默认值)
【发布时间】:2014-12-30 21:34:07
【问题描述】:

我正在编写一个 AngularJS 服务提供者(函数):

  • 从 SQLite 数据库的多个不同表中获取结果
  • 将对象返回给各种控制器函数

该服务查询不同的表(具有不同的列),因此result 对象具有不同的属性 - 取决于数据来自哪个表。

  • 因此无法将 Object.defineProperties 用于特定对象属性,因为在创建查询“案例”之前我不知道属性
  • 我想我可以在“开关”中定义对象变量属性,但这看起来很乱......

当对象返回到控制器函数时,需要进行一些操作

  • 我需要能够覆盖返回对象中的一些属性(即需要writable: true
  • 准确地说,JSON.parse() 然后覆盖各种属性,因为存储在 SQLite DB 中的数组在 INSERT 之前使用 JSON.stringify() 进行转换,然后作为字符串存储在 DB 中
  • 我遇到了麻烦,因为对象的默认值是writable: false

问题:
我如何为对象的所有(未来)属性定义一个具有configurable: true, writable: true, enumerable: true 属性的对象? 即如何设置默认值对象的属性,因为我(还)不知道对象的确切属性名称?

示例代码:

this.checkRowExists = function(table, id) {     
    try {
        var deferred = $q.defer();

        switch (table) {
            case "table1" :
                var selectQuery = 'SELECT * FROM ' + table + ' WHERE id=?';
                break;
            case "table2" :
                var selectQuery = 'SELECT * FROM ' + table + ' WHERE id=?';
                break;
            case "table3" :
                var selectQuery = 'SELECT * FROM ' + table + ' WHERE id=?';
                break;
        }

        this.db.transaction(function(tx) {
            tx.executeSql(selectQuery, [id], function(tx, results) {
                    if (results.rows.length > 0){
                        var myRow = {};       // <- how to define all properties in "myRow" object as configurable and writable ??
                        var myRow = results.rows.item(0);
                        deferred.resolve(myRow);  // <- object "myRow" is returned here to various controller functions
                    } else {
                        deferred.resolve(results.rows.length);
                    }
            }, function(tx, error) {
                    console.log('checkRowExists: Error occurred while searching for profile.', error);
                deferred.reject(error);
            });
        });

        return deferred.promise;

    } catch(exception) {
        console.log('checkRowExists: Error occurred while trying this function.', exception);
    }
};

PS 代码工作正常,但只返回一个带有writable: false, enumerable: true, configurable: false 的对象,而我需要所有东西都是true

编辑:
即使在以下部分解决后仍存在问题:
- 为什么不能使用Object.defineProperty 方法手动更改属性描述符?
- 为什么enumerable: true 默认应该是 false ?这与 SQlite 数据库事务有关吗?
- 为什么writable: false, enumerable: false, configurable: false 的默认值没有应用于使用 JSON 方法克隆的新对象?
答案here - 取决于对象的创建方式 - 请参阅下面的评论

【问题讨论】:

  • 那是不可能的,但我什至看不到您的代码将writable 属性设置为false 的位置?
  • 据此,可写属性/属性描述符默认设置为 FALSE developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
  • 不,只有当你有一个属性描述符并省略一个属性时,当属性描述符对象用于创建属性时,那个属性将默认为false。但是在已经存在的属性中没有任何改变,在通过简单赋值创建的属性中,所有属性默认为true
  • 是的,部分正确-想知道'default = false'如何,但在新对象上它大多看起来是“true”-答案是它取决于对象属性的定义方式-所以如果一个对象被定义为myObject={}; myObject.a=1; 所有默认为true,但定义为Object.defineProperty(myObject, 'a', { value: 1 }); 任何未定义的描述符默认为false。比较混乱。见developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
  • 是的,我就是这么说的 :-)

标签: javascript angularjs object properties defineproperty


【解决方案1】:

问题的一半似乎是对象myRow 继承了它从即复制的对象的属性描述符/属性:
var myRow = results.rows.item(0)

问题的另一半是似乎无法更改属性描述符:
即使用Object.defineProperty(myRow, "my_property", {configurable: true});
-> 给TypeError: Cannot redefine property: my_property

部分解决方案
根据this discussion 中的第三个答案,克隆对象最优雅的方法是使用:
var newObject = JSON.parse(JSON.stringify(oldObject));
这似乎创建了一个全新的对象,它不会从“复制”对象继承属性描述符

无论出于何种原因,这都会导致对象带有
writable: true, enumerable: true, configurable: true(在 Chrome 和 Safari 中测试)
(是的,考虑到spec 中列出的所有 3 个描述符的默认值 false,这是没有意义的)
编辑:
这是因为对象的定义方式 - 请参阅 here
- 定义为 myObject={}; myObject.a=1; 所有属性描述符默认为 true,
- 定义为Object.defineProperty(myObject, 'a', { value: 1 }); 任何未定义的描述符默认为 false

所以上面代码中以下 sn-p 的输出如下所示:

tx.executeSql(selectQuery, [id], function(tx, results) {
    if (results.rows.length > 0){
            // see what the original object descriptors are set at:
            console.log( Object.getOwnPropertyDescriptor(results.rows.item(0), "my_property") );
            // -> outputs "configurable: false, enumerable: true, writable: false"
        var myRow = results.rows.item(0);
            // see what the new copied object descriptors are set at:
            console.log( Object.getOwnPropertyDescriptor(myRow, "my_property") );
            // -> outputs "configurable: false, enumerable: true, writable: false"
        var myRow2 = JSON.parse(JSON.stringify(results.rows.item(0)));
            // see what the new JSON cloned object descriptors are set at:
            console.log( Object.getOwnPropertyDescriptor(myRow, "my_property") );
            // -> outputs "configurable: true, enumerable: true, writable: true"
        deferred.resolve(myRow2);
    } else {
        deferred.resolve(results.rows.length);
    }
}, function(tx, error) {
        console.log('checkRowExists: Error occurred while searching for profile.', error);
    deferred.reject(error);
});

关于这个部分解决方案还有几个问题:
- 使用JSON.parse(JSON.stringify(object)); 复制/克隆对象的速度是多少?
- 使用JSON.parse(JSON.stringify(object)); 克隆还有其他缺点吗?
(有些列在here - 大多不适用于对象属性中的日期格式或函数)

【讨论】:

  • 回答我的一个问题,速度似乎与 JSON.parse(JSON.stringify(object)); 方法无关 - 使用 console.log(Date.now()); 检查导致 before 1419986858403after 1419986858404 即 1 毫秒带有几个嵌套数组的 21 列数据库...ymmv.
  • 如果你还有多个问题,你应该把它们放在你的question帖子中。
  • 好电话 - 将任何与部分解决方案无关的问题移至 question 帖子。谢谢
猜你喜欢
  • 2018-12-02
  • 1970-01-01
  • 2018-11-15
  • 2010-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-19
相关资源
最近更新 更多