Forum Discussion

APX's avatar
APX
Occasional Contributor
10 years ago

How can I clone objects in TestComplete javascript?

Hi,

 

a simple Question: how can I clone objects, in javascript without reference,  in TestComplete(is it possible)? I don't found a methode on MSDN and the standard methode "clone()" is not supported by TestComplete. 

 

little example:

 

 

var p={ // simple object
     pName:"myName",
     pSex:"Male",
     pToStr: function(){ return (this.pName+" : "+pSex);}
}
var tmp={};
clone(p, tmp);
p.Name="yourName";

if(p.Name==tmp.Name) // should be different
   Print(Error); 
else Print("was cloned");

 

 

  • So here is my solution for this Problem. We do not have the the option for using 'prototype' or 'constructor'. I have my doubts in terms of this kind of solution but it's better then nothing:

     

     

    function clone( other, obj)
    {
        if ( (other === null) || (typeof other !== "object") )
        {
         obj=other;
         return true;
        }    
        obj = obj || {};
        for ( Key in other )
        {
          if(other.hasOwnProperty(Key))
          {                        
            if(typeof other[Key] == 'function') 
            {
               obj[Key]={};  
               eval("obj."+Key.toString()+"="+other[Key].toString());           
            }
            else if(typeof other[Key] == 'object') 
            {
              obj[Key]={};//
              clone(other[Key], obj[Key]);          
            }
            else
            {         
              obj[Key]=other[Key];
            }
          }
        }
        if(obj != null)return true;
        return false;
    }

     

    Usage:

    var person={
        fName: "Max",
        lName: "Mustermann",
        hight: 181,    
        motto:{
          autor:"mySelf", 
          text:"my motto",
          printMotto: function(){
            return (this.autor+" : "+this.text);
          }
        },
        printData:function(){
          return this.fName+" ->"+this.lName+" -> "+this.hight+"->"+motto.printMotto(); 
        }
      };
    
    var copy={};
    if(clone(person, copy))
       Log.Message(person.printData()+" :: "+copy.printData());
    person=null; // or you can use undefined to clear var
    Log.Message(copy.printData());
    Log.Message(person.printData());// here we will get an error
    
    
    

    I can't compare the memory address of this both variables, so it's not really 100% a deep copy 

    If you have a better way to solve that problem, post it here.

    Thanks.

  • APX's avatar
    APX
    Occasional Contributor

    So here is my solution for this Problem. We do not have the the option for using 'prototype' or 'constructor'. I have my doubts in terms of this kind of solution but it's better then nothing:

     

     

    function clone( other, obj)
    {
        if ( (other === null) || (typeof other !== "object") )
        {
         obj=other;
         return true;
        }    
        obj = obj || {};
        for ( Key in other )
        {
          if(other.hasOwnProperty(Key))
          {                        
            if(typeof other[Key] == 'function') 
            {
               obj[Key]={};  
               eval("obj."+Key.toString()+"="+other[Key].toString());           
            }
            else if(typeof other[Key] == 'object') 
            {
              obj[Key]={};//
              clone(other[Key], obj[Key]);          
            }
            else
            {         
              obj[Key]=other[Key];
            }
          }
        }
        if(obj != null)return true;
        return false;
    }

     

    Usage:

    var person={
        fName: "Max",
        lName: "Mustermann",
        hight: 181,    
        motto:{
          autor:"mySelf", 
          text:"my motto",
          printMotto: function(){
            return (this.autor+" : "+this.text);
          }
        },
        printData:function(){
          return this.fName+" ->"+this.lName+" -> "+this.hight+"->"+motto.printMotto(); 
        }
      };
    
    var copy={};
    if(clone(person, copy))
       Log.Message(person.printData()+" :: "+copy.printData());
    person=null; // or you can use undefined to clear var
    Log.Message(copy.printData());
    Log.Message(person.printData());// here we will get an error
    
    
    

    I can't compare the memory address of this both variables, so it's not really 100% a deep copy 

    If you have a better way to solve that problem, post it here.

    Thanks.

    • k_de_boer03's avatar
      k_de_boer03
      Contributor

      TestComplete actually uses Jscript, so some Javascript functions and libraries are not supported here.

       

      I couldn't find a one-liner solution for your problem either. Any solution I found looked similar to your implementation, though I do have a comment.

      Why do you want to return a boolean? I would return the copied object, or null if something is wrong. This way you dont need the second argument to the function. Right now with your code:

       

      if((other === null) || (typeof other !== "object")) {
        return true;
      }

      It doesn't make sense to me, why would you return true when nothing happened?

       

      Also, you already do:

       

      obj = obj || {};

      with your second argument, and in your example code you do:

       

      var copy={};
      if(clone(person, copy))
      ...

      There is no need to do var copy = {}. If you would do var copy = {//some non-empty object}, then it wouldn't be a clone anymore, so thats another reason to remove the argument.

       

      I would make it something like:

       

      function clone(obj)
      {
          if((obj === null) || (typeof obj !== "object")){
              return null; // or throw an error
          }    
          var cloneObj = {};
          for(var prop in obj){
            if(obj.hasOwnProperty(prop)){                        
              if(typeof obj[prop] == 'object'){
                cloneObj[prop] = clone(obj[prop]);          
              } else {         
                cloneObj[prop] = obj[prop];
              }
            }
          }
          return cloneObj;
      }

      Note, I haven't tested this code :) 

       

      • APX's avatar
        APX
        Occasional Contributor

        It is only an example...

         

        1.) the the second argument in functions head was important for me, because: 

        function clone( other, obj)

        if this function return an object to an object is that like : var myObj = otherObj; so its save the reference from otherObj to myObj and the function that I have posted  works with the real variable.( my opinion)

         

        2.) The idea is:

        this function is for objects, functions and for standard types like: string or int, float, double, therefore the function don't return false on this: 

        if((other === null) || (typeof other !== "object")) {
        obj = other; return true; }

         

        thanks for answer, the code has become shorter.