从Javascript对象中删除方法

5
在一个代码库中,我看到了一行代码。
var foo = JSON.parse(JSON.stringify(foo));

我认为这段代码试图从对象中剥离任何方法。我并没有看到它做其他事情的迹象。有更有效的方法来尝试这个吗?Node 是否会优化它?

2个回答

6
在您现在披露的代码上下文中,这种技术被用于复制传递给函数的对象,以便对该对象的修改不会修改原始对象。以下是来自您链接的上下文:
// route reply/error
this.connection.on('message', function(msg) {
   var msg = JSON.parse(JSON.stringify(msg));
   var handler;
   if (msg.type == constants.messageType.methodReturn || msg.type == constants.messageType.error) {
       handler = self.cookies[msg.replySerial];
       if (msg.type == constants.messageType.methodReturn && msg.body)
          msg.body.unshift(null); // first argument - no errors, null
       if (handler) {
          delete self.cookies[msg.replySerial];
          var props = {
             connection: self.connection,
             bus: self,
             message: msg,
             signature: msg.signature
          };
          if (msg.type == constants.messageType.methodReturn)
             handler.apply(props, msg.body); // body as array of arguments
          else
             handler.call(props, msg.body);  // body as first argument
       }

注意:这段代码中包含msg.body.unshift(null)的那一行。如果没有进行复制,它将修改原始对象。
另外,请注意重新声明var msg实际上并没有定义一个新变量。由于在此作用域中已经将msg定义为函数参数,因此var msg不会重新声明(在代码中使用var是技术上的错误)。
使用这种类型的代码的常见原因是克隆一个对象(制作一个深度复制的对象,其中包括所有属性,包括嵌入的对象和数组)。
var obj = {
   list: [1,2,3],
   items: [{language: "English", greeting: "hello"}, 
           {language: "Spanish", greeting: "hola"}, 
           {language: "French", greeting: "bonjour"}]
}

// make a completely independent copy of obj
var copy = JSON.parse(JSON.stringify(obj));

copy.items[0].greeting = "Yo";

console.log(obj.items[0].greeting);    // "hello"
console.log(copy.items[0].greeting);   // "Yo"

注意:此方法仅适用于纯对象类型且不具有自定义函数属性的完全复制。而且,由于JSON.stringify()不支持循环引用或自引用,因此您不能拥有任何这些东西。如果您有多个对同一对象的引用,则每个引用都将被复制到一个新的单独对象中。而且,JSON.stringify()JSON.parse()的组合不支持除Object以外的其他对象,如RegExpDate或任何您自己的自定义对象(它们会转换为普通对象)。因此,这种方法存在一些限制,但对于大多数情况来说,它非常简单易行。

根据Matt(在评论中)所说,可以在这里看到一个自定义函数,它可以创建一个支持循环引用和某些类型的自定义对象的克隆对象。


如果有人不知道,JavaScript中将一个对象赋给另一个变量,并不会复制对象。在JavaScript中,赋值类似于将指针引用设置为同一对象。然后每个变量都指向相同的基础对象,因此通过任何一个变量修改对象都会导致两种情况下都修改相同的对象,就像这样:

var obj = {
   list: [1,2,3],
   items: [{language: "English", greeting: "hello"}, 
           {language: "Spanish", greeting: "hola"}, 
           {language: "French", greeting: "bonjour"}]
}

var copy = obj;

// modify copy 
copy.items[0].greeting = "Yo";

// both obj and copy refer to the exact same object
console.log(obj.items[0].greeting);    // "Yo"
console.log(copy.items[0].greeting);   // "Yo"

因此,偶尔需要对对象进行实际的深度复制。

2
@FelixKling - 将您的额外注意事项添加到答案中。 - jfriend00
1
对于那些确实需要对象的深度克隆的情况,请参见此答案:https://dev59.com/83VD5IYBdhLWcg3wAGiD#13333781 - Matt Browne
1
@MattBrowne - OP问题中的方法已经实现了深度克隆。你提供的方法支持更多功能,如循环引用、重复引用,并且适用于一些自定义对象类型(尽管有些对象类型可能无法正常工作,特别是如果构造函数与其他对象链接)。 - jfriend00
@MattBrowne - 我在我的答案中添加了一个链接,用于参考你提到的克隆函数。 - jfriend00
1
@MKaras - 你需要展示这段代码的上下文,以便得到真正的答案,解释为什么要这样做,而不是猜测。现在你只是在进行学术猜测游戏,而不是实际的代码分析。 - jfriend00
显示剩余7条评论

0
如果您想从原型中删除方法,请考虑创建一个新对象并转移所有旧对象的属性。
如果您想剥离函数属性,请循环遍历对象并检查属性是否为函数:
for(key in ob)
{
    if(typeof ob[key] === 'function')
    {
        delete ob[key];
    }
}

或许你希望实现的是两者的结合。


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