JavaScript 删除对象属性无效。

42

我正在使用MEAN.js开展一些项目,遇到了以下问题。我想要计算一些用户的个人资料并将其保存到数据库中。但是在用户模型中的方法存在问题:

UserSchema.pre('save', function(next) {
    if (this.password && this.password.length > 6) {
        this.salt = new Buffer(crypto.randomBytes(16).toString('base64'), 'base64');
        this.password = this.hashPassword(this.password);
    }
    next();
});
如果我在修改时发送密码,它将更改凭据,因此用户下次无法登录。我想在保存之前从用户对象中删除密码,但我不能这样做(请看下面我的代码注释):
exports.signin = function(req, res, next) {
    passport.authenticate('local', function(err, user, info) {
        if (err || !user) {
            res.status(400).send(info);
        } else {
            /* Some calculations and user's object changes */
            req.login(user, function(err) {
                if(err) {
                    res.status(400).send(err);
                } else {
                    console.log(delete user.password); // returns true
                    console.log(user.password); // still returns password :(
                    //user.save();
                    //res.json(user);
                }
            });
        }
    })(req, res, next);
};

出了什么问题?为什么删除方法返回 true,但是没有任何反应?感谢您的帮助 :)


1
非严格模式下,即使属性不能被删除,delete将返回true。当通过原型链获取属性时,delete将返回true并且没有任何影响。 - Prusse
“'use strict';” 是我的控制器文件的第一行。但是我该如何删除密码属性? - ketysek
看起来不太可能,但你有检查过 password 属性是否确实是 user 对象的属性,而不是来自原型链上的某个对象(hasOwnProperty)吗?将其设置为 undefined 是不够的(抱歉,我对 MEAN 栈没有经验)。就 JSON 编码而言,结果应该没有任何区别。 - Prusse
不行,将属性设置为undefined是不起作用的... hasOwnProperty返回了false,正如你所预期的那样。 - ketysek
9个回答

63

只需要执行:

user.password = undefined;

改为:

delete user.password;

而密码属性将不会显示在输出中。


3
这将在许多情况下导致意外的结果。 - E.A.T
7
@E.A.T,这个人实际上不需要删除密码属性。根据他上面的描述,他只是想在输出的JSON中排除密码的值,只需将密码属性设置为未定义即可解决。请尝试一下。 - LEMUEL ADANE
不要覆盖密码(当调用“user.save()”时),这是@lemueladane不希望发生的情况,即使将其设置为“undefined”或“null”也可能发生。我们没有足够的关于方法或任何预保存钩子的信息。 - E.A.T
3
@E.A.T,我想他需要先使用user.save(),然后将user.password设置为undefined,最后使用res.json(user)。 - LEMUEL ADANE
2
但为什么删除用户密码不起作用? - Sunil Garg

25

JavaScript中删除运算符有一些规则。

  1. 如果属性是“严格模式”下自有的不可配置属性,则返回false。

例如:

x = 42;         // creates the property x on the global object
var y = 43;     // creates the property y on the global object, and marks it as non-configurable

// x is a property of the global object and can be deleted
delete x;       // returns true

// y is not configurable, so it cannot be deleted                
delete y;       // returns false 
  1. 如果对象从原型继承了属性,并且对象本身没有该属性,则无法通过引用对象来删除该属性。但是,您可以直接在原型上删除它。

例如:

function Foo(){}
Foo.prototype.bar = 42;
var foo = new Foo();

// returns true, but with no effect, 
// since bar is an inherited property
delete foo.bar;           

// logs 42, property still inherited
console.log(foo.bar);

因此,请交叉检查这些要点,如需更多信息,请阅读此链接


15

我遇到了类似的问题,以下方法对我有效:

// create a new copy  
let newUser= ({...user}._doc); 

// delete the copy and use newUser that thereafter. 
delete newUser.password; 


11

与MONGOOSE合作?

如果您在使用Mongoose(MongoDB的上层)时遇到此问题,则可以在find方法上使用lean属性。

示例

不使用lean(键不会被删除)

const users = await User.find({ role: 'user' }) // no lean method
   users.forEach((user) => {
   delete user.password  // doesn't delete the password
})

console.log(users) 

/* [
    {name:'John', password:'123'}, 
    {name:'Susan', password:'456'}
   ] 
*/ 

使用“精益”(按此方式删除密钥)。
const users = await User.find({ role: 'user' }).lean() 
   users.forEach((user) => {
   delete user.password   // deletes the password
})

console.log(users) 

/* [
    {name:'John'}, 
    {name:'Susan'}
   ] 
*/ 
为什么精简模式有效 启用精简模式的查询返回的文档是纯JavaScript对象,而不是Mongoose文档。它们没有保存方法、getter/setter、虚拟属性或其他Mongoose特性。
文档是只读的,所以无法使用delete删除它们。
参考:https://dev59.com/uVYM5IYBdhLWcg3w-T0e#48137096 https://mongoosejs.com/docs/api.html#query_Query-lean 方法2:不使用精简模式 如果您想在查询时使用mongoose提供的方法删除某些属性,则可以使用select方法进行删除。
const users = await User.find({ role: 'user' }).select('-password')

console.log(users)
 /* [
      {name:'John'}, 
      {name:'Susan'}
    ] 
 */ 

参见:https://dev59.com/hGs05IYBdhLWcg3wAdWT - Khalid Abu Shawarib
1
在第一个例子中,您忘记了密码后面的一个点。 - Kamuran Sönecek
感谢@Kamuran Sönecek。已更新! - Sandeep Amarnath
1
谢谢!这可能也有所帮助:const _doc = doc.toObject(); delete _doc.prop1;。(直接使用 delete 在 Mongoose 文档对象上不起作用,因为它们被配置为不可编辑。toObject() 首先将它们转换为普通对象。然后 delete 就会起作用。) - aderchox

4
上面的答案来自 Majed A,这是解决单个对象属性的最简单的方法,我们可以通过删除...user 这个扩展符使其更加简单。只需要从你的object._doc子对象中删除该属性即可。以你的示例为例:
user.save()
delete user._doc.password
res.status(201).json(user) // The password will not be shown in JSON but it has been saved.

1

最有可能的情况是,您想删除的属性没有被该对象拥有。在这种情况下,操作的结果将显示true,但不会删除任何内容


这有道理。 - undefined

0

0
如果使用defineProperty定义了密码,则configurable默认为false(如果未设置)。在这种情况下,该属性将无法被删除。
对于我来说,Node.js仍然告诉我该属性已被删除(console.log(delete obj.prop)),但实际上并没有被删除。

function test(settings) {
  settings = {...{c: false, w:false}, ...settings}
  let obj = {}
  Object.defineProperty(obj, "prop", {
    configurable: settings.c,
    enumerable: settings.e ?? true,
    writable: settings.w,
    value: "foo"
  });
  console.log(
    JSON.stringify(settings), 
    '\nset value to 1', (function() {obj.prop = 1})() || "", 
    '\nappended bar:', (function() {obj.prop += "bar"})() || "", 
    '\nobj:', JSON.stringify(obj),
    '\ndelete:', delete obj['prop'],
    '\nobj:', JSON.stringify(obj))
}
console.log('baseline: unchangeable, undeletable');
test()
console.log('unchangeable, deletable');
test({c: true})
console.log('changeable, undeletable');
test({w: true})
console.log('changeable, deletable');
test({c: true, w: true})


0

你可以使用这个。它会跳过不需要的键而不是删除,然后返回一个对象。

let x = {1:'1', 2:2}

console.log('in', x)


function remove(Object, key){

    let outputObject = {}

    for (let inKey in Object){

        if(key == inKey){

            console.log(key , 'was deleted')

        }else{

           outputObject[inKey] = Object[inKey]

        }

    }

    return outputObject

}

let out = remove(x, 1)

console.log('out', out)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接