剥离javascript对象的方法

MKa*_*ras 5 javascript node.js

在一个回购中,我看到了一条线.

var foo = JSON.parse(JSON.stringify(foo));
Run Code Online (Sandbox Code Playgroud)

我认为这是试图剥离对象的任何方法.我无法真正看到它做任何其他事情.是否有更有效的方法来尝试这个?节点是否优化了这个?

jfr*_*d00 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
       }
Run Code Online (Sandbox Code Playgroud)

注意:此剪辑中包含的行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"
Run Code Online (Sandbox Code Playgroud)

注意:这仅适用于具有普通对象类型的对象的完整副本,并且没有作为函数的自定义属性.而且,因为JSON.stringify()不支持循环引用或自引用,所以你不能拥有任何这些引用.并且,如果您对同一对象有多个引用,则每个引用都将复制到一个新的单独对象.而且,组合JSON.stringify()JSON.parse()不支持比一个普通的其他对象Object,如RegExp,Date或任何自定义对象的(他们把他们变成普通的对象).因此,这个程序有一些局限性,但它对大多数情况来说非常简单.


Per 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"
Run Code Online (Sandbox Code Playgroud)

因此,偶尔需要制作对象的实际深层副本.

  • @FelixKling - 在答案中添加了额外的警告. (2认同)