Deep copy and shallow copy prototype type verification

premise:

Deep copy and shallow copy are only for reference data types such as Object and Array.

1. Stack memory

For details, see another blog data type and stack storage

2. Shallow copy and deep copy

The schematic diagrams of deep copy and shallow copy are roughly as follows:
Insert picture description here

Shallow copy only copies the pointer to an object, not the object itself. The old and new objects still share the same memory. But a deep copy will create another exactly the same object. The new object does not share memory with the original object. Modifying the new object will not change to the original object.

The difference between assignment and shallow copy
Assignment:

When assigning an object to a new variable, it is actually the address of the object on the stack, not the data in the heap. That is, two objects point to the same storage space. No matter which object changes, it is actually the content of the changed storage space. Therefore, the two objects are linked.

Shallow copy:

Shallow copy is a bitwise copy of an object. It creates a new object with an exact copy of the original object's attribute values. If the attribute is a basic type, the value of the basic type is copied; if the attribute is a memory address (reference type), the memory address is copied, so if one object changes this address, it will affect the other object. That is, the default copy constructor only performs a shallow copy copy of the object (copy member by member in turn), that is, only copy the object space without copying the resources.

Handwritten deep copy (recursive):
/**
 * 深拷贝
 */

const obj1 = {
    
    
    age: 20,
    name: 'xxx',
    address: {
    
    
        city: 'beijing'
    },
    arr: ['a', 'b', 'c']
}

const obj2 = deepClone(obj1)
obj2.address.city = 'shanghai'
obj2.arr[0] = 'a1'
console.log(obj1.address.city)
console.log(obj1.arr[0])

/**
 * 深拷贝
 * @param {Object} obj 要拷贝的对象
 */
function deepClone(obj = {
    
    }) {
    
    
    if (typeof obj !== 'object' || obj == null) {
    
    
        // obj 是 null ,或者不是对象和数组,直接返回
        return obj
    }

    // 初始化返回结果
    let result
    if (obj instanceof Array) {
    
    
        result = []
    } else {
    
    
        result = {
    
    }
    }

    for (let key in obj) {
    
    
        // 保证 key 不是原型的属性
        if (obj.hasOwnProperty(key)) {
    
    
            // 递归调用!!!
            result[key] = deepClone(obj[key])
        }
    }

    // 返回结果
    return result
}

JavaScript prototype and prototype chain

1. prototype

Each function has a prototype property, which is called the display prototype

2._ proto _

Each instance object will have the _ proto attribute, which is called the implicit prototype. The implicit prototype of
each instance object. The
proto _ attribute points to the explicit prototype prototype of its own constructor.

3. constructor

Each prototype has a constructor attribute, which points to its associated constructor.

4. Prototype chain

When obtaining object properties, if the object itself does not have this property, it will go to its prototype __proto__ to find it. If it still can't be found, it will look for the prototype of the prototype until the top (Object.prototype) is found. Object.prototype objects also have the __proto__ property value of null.

It should be noted here that Object belongs to the top level of the prototype chain, and the prototypes of all constructors point to Object.prototype

Insert picture description here


function Fun(){
    
    

  }
//    我创造了一个函数Fn
//   这个函数由Function生成(Function作为构造函数)
     var fn=new Fun()
//   我创建了一个函数fn
//   这个函数由构造函数Fun生成
     console.log(fn.__proto__===Fun.prototype)    //true
//   fn的__proto__指向其构造函数Fun的prototype
     console.log(Fun.__proto__===Function.prototype)        //true
//   Fun的__proto__指向其构造函数Function的prototype
     console.log(Function.__proto__===Function.prototype)    //true
//   Function的__proto__指向其构造函数Function的prototype
//   构造函数自身是一个函数,他是被自身构造的
     console.log(Function.prototype.__proto__===Object.prototype)    //true
//   Function.prototype的__proto__指向其构造函数Object的prototype
//   Function.prototype是一个对象,同样是一个方法,方法是函数,所以它必须有自己的构造函数也就是Object
     console.log(Fun.prototype.__proto__===Object.prototype)         //true
//   与上条相同
//   此处可以知道一点,所有构造函数的的prototype方法的__都指向__Object.prototype(除了....Object.prototype自身)
     console.log(Object.__proto__===Function.prototype)        //true
//   Object作为一个构造函数(是一个函数对象!!函数对象!!),所以他的__proto__指向Function.prototype
     console.log(Object.prototype.__proto__===null)        //true
//   Object.prototype作为一切的源头,他的__proto__是null

//  下面是一个新的,额外的例子

    var obj={
    
    }
//  创建了一个obj
    console.log(obj.__proto__===Object.prototype)        //true
//   obj作为一个直接以字面量创建的对象,所以obj__proto__直接指向了Object.prototype,而不需要经过Function了!!

//    下面是根据原型链延伸的内容
/*还有一个上文并未提到的constructor,  constructor在原型链中,是作为对象prototype的一个属性存在的,它指向构造函数
(由于主要讲原型链,这个就没在意、);*/

 console.log(obj.__proto__.__proto__===null)        //true
 console.log(obj.__proto__.constructor===Object)        //true
 console.log(obj.__proto__.constructor.__proto__===Function.prototype)        //true
 console.log(obj.__proto__.constructor.__proto__.__proto__===Object.prototype)    //true
 console.log(obj.__proto__.constructor.__proto__.__proto__.__proto__===null)        //true
 console.log(obj.__proto__.constructor.__proto__.__proto__.constructor.__proto__===Function.prototype)    //true

//            以上,有兴趣的可以一一验证  F12搞起.

js data type judgment

Four methods

typeof、instanceof、constructor、Object.prototype.toString.call()、jquery.type()

1 .typeof

console.log(
    typeof 100, //"number"
    typeof 'abc', //"string"
    typeof false, //"boolean"
    typeof undefined, //"undefined"
    typeof null, //"object"
    typeof [1,2,3], //"object"
    typeof {
    
    a:1,b:2,c:3}, //"object"
    typeof function(){
    
    console.log('aaa');}, //"function"
    typeof new Date(), //"object"
    typeof /^[a-zA-Z]{
    
    5,20}$/, //"object"
    typeof new Error() //"object"
    typeof new Number(100), //'object'
    typeof new String('abc'),// 'string'
    typeof new Boolean(true),//'boolean'
);

In the basic data types: Number, String, Boolean, undefined and Function in the reference data type, you can use typeof to detect the data type, and return the corresponding data type lowercase characters respectively.
Another: Number, String, Boolean created by the typeof detection constructor all return to the
basic data type of object : null. Reference data types: Array, Object, Date, RegExp. Can not use typeof detection. Will return lowercase object

2 . instanceof

In addition to using typeof to judge, you can also use instanceof. The instanceof operator needs to specify a constructor, or specify a specific type, which is used to determine whether the prototype of this constructor is on the prototype chain of a given object.


console.log(
    100 instanceof Number, //false
    'dsfsf' instanceof String, //false
    false instanceof Boolean, //false
    undefined instanceof Object, //false
    null instanceof Object, //false
    [1,2,3] instanceof Array, //true
    {
    
    a:1,b:2,c:3} instanceof Object, //true
    function(){
    
    console.log('aaa');} instanceof Function, //true
    new Date() instanceof Date, //true
    /^[a-zA-Z]{
    
    5,20}$/ instanceof RegExp, //true
    new Error() instanceof Error //true
)

Among the basic data types: Number, String, Boolean. The literal value cannot be detected by instanceof, but the value created by the constructor can be, as follows:


var num = new Number(123);
var str = new String('dsfsf');
var boolean = new Boolean(false);

Also note that both null and undefined return false, this is because their type is itself, not Object created them, so false is returned.

3 .constructor

The constructor is a property on the prototype object, pointing to the constructor. According to the order in which the instance objects are searched for attributes, if there are no instance attributes or methods on the instance objects, they will be searched on the prototype chain. Therefore, the instance objects can also use the constructor attribute.

If you output a constructor of an instance of a type, it looks like this:


console.log(new Number(123).constructor)
//ƒ Number() { [native code] }

You can see that it points to the constructor of Number. Therefore, you can use num.constructor==Number to determine whether a variable is of type Number.


var num  = 123;
var str  = 'abcdef';
var bool = true;
var arr  = [1, 2, 3, 4];
var json = {
    
    name:'wenzi', age:25};
var func = function(){
    
     console.log('this is function'); }
var und  = undefined;
var nul  = null;
var date = new Date();
var reg  = /^[a-zA-Z]{5,20}$/;
var error= new Error();

function Person(){
    
    
  
}
var tom = new Person();

// undefined和null没有constructor属性
console.log(
    tom.constructor==Person,
    num.constructor==Number,
    str.constructor==String,
    bool.constructor==Boolean,
    arr.constructor==Array,
    json.constructor==Object,
    func.constructor==Function,
    date.constructor==Date,
    reg.constructor==RegExp,
    error.constructor==Error
);
//所有结果均为true

Except for undefined and null, other types can be judged by the constructor attribute.

4. Use Object.prototype.toString.call() to detect the object type

You can get the type of each object through toString(). In order for each object to be detected by Object.prototype.toString(), it needs to be called in the form of Function.prototype.call() or Function.prototype.apply(), passing the object to be checked as the first parameter, Called thisArg.

var toString = Object.prototype.toString;

toString.call(123); //"[object Number]"
toString.call('abcdef'); //"[object String]"
toString.call(true); //"[object Boolean]"
toString.call([1, 2, 3, 4]); //"[object Array]"
toString.call({
    
    name:'wenzi', age:25}); //"[object Object]"
toString.call(function(){
    
     console.log('this is function'); }); //"[object Function]"
toString.call(undefined); //"[object Undefined]"
toString.call(null); //"[object Null]"
toString.call(new Date()); //"[object Date]"
toString.call(/^[a-zA-Z]{5,20}$/); //"[object RegExp]"
toString.call(new Error()); //"[object Error]"

In this way, you can see that Object.prototype.toString.call()the most accurate way to determine the type of a variable is the way it is used.

5. Invincible almighty method: jquery.type()

If the object is undefined or null, the corresponding "undefined" or "null" is returned

jQuery.type( undefined ) === "undefined"
jQuery.type() === "undefined"
jQuery.type( window.notDefined ) === "undefined"
jQuery.type( null ) === "null"
/*如果对象有一个内部的[[Class]]和一个浏览器的内置对象的 [[Class]] 相同,我们返回相应的 [[Class]] 名字。
 (有关此技术的更多细节。 )*/
jQuery.type( true ) === "boolean"
jQuery.type( 3 ) === "number"
jQuery.type( "test" ) === "string"
jQuery.type( function(){
    
    } ) === "function"
jQuery.type( [] ) === "array"
jQuery.type( new Date() ) === "date"
jQuery.type( new Error() ) === "error" // as of jQuery 1.9
jQuery.type( /test/ ) === "regexp"
其他一切都将返回它的类型“object”

6. You can also encapsulate a function to get the exact type of the variable

function gettype(obj) {
var type = typeof obj;

if (type !=='object') { return type; } //If it is not object type data, it can be judged directly with typeof


//If it is object type data, you must use Object.prototype.toString.call(obj) to accurately determine the type to determine
return Object.prototype.toString.call(obj).replace(/^[object (\S+)] $/,'$1');
}

Guess you like

Origin blog.csdn.net/WLIULIANBO/article/details/112584734