深拷贝浅拷贝,原型,类型校验,递归深拷贝

一、什么是深拷贝,浅拷贝,如何实现
值传递:javascript 有五种基本的数据类型 分别是 Boolean null undefined string number
这些基本数据赋值的时候是通过值传递的方式 栈内存
地址传递 引入的数据类型(object)指向堆内存的首地址

深拷贝和浅拷贝是针对复杂数据类型来说的,浅拷贝只拷贝一层,而深拷贝是层层拷贝。
深拷贝
深拷贝复制变量值,对于非基本类型的变量,则递归至基本类型变量后,再复制。 深拷贝后的对象与原来的对象是完全隔离的,互不影响, 对一个对象的修改并不会影响另一个对象。

浅拷贝
浅拷贝是会将对象的每个属性进行依次复制,但是当对象的属性值是引用类型时,实质复制的是其引用,当引用指向的值改变时也会跟着变化。

浅拷贝实现
Object.assign Array.from()

深拷贝实现
Array.prototype.slice()、Array.prototype.concat() 、Json.parse(json.stringify(obj))

二、递归拷贝
递归函数就是会直接或者间接调用自身的一种函数。递归是一种强大的编程技术,它把一个问题分解为一组相似的子问题,调用自身去解决它的子问题。

三、原型
JavaScript 的所有对象中都包含了一个 [proto] 内部属性,这个属性所对应的就是自身的原型,除了原型 [proto] 之外,还有 prototype 属性,当函数对象作为构造函数创建实例时,该 prototype 属性值将被作为实例对象的原型 [proto]


function People(name) {
    //隐式的执行了:
    // var this = {__proto__: People.prototype};
    this.name = name;
     //隐式的执行了:
    // return this;
}
 
// People.prototype = { constructor: People }; //这是在 People 函数被定义的时候,就有的~
 
People.prototype.sayName = function() {
    console.log('this.name --> %s', this.name);
}
 
var people1 = new People('张三');
var people2 = new People('李四');
 
people1.__proto__ === People.prototype; //true
people1.constructor === People.prototype.constuctor; //true
people1.__proto__ === people2.__proto__; //true
 
即:
1. 每个构造函数都有一个原型属性 (eg. People.prototype)。
2. 每个实例都有 __proto__ 属性, __proto__ 属性指向了实例构造函数的原型 (eg. people1.__proto__)。
3. 原型也是一个对象,是函数(Funciton)的一个属性。
4. 通过构造函数产生的对象,可以继承构造函数以及其原型上的属性和方法。

隐式原型 (proto):隐式原型的作用是用来构成原型链,实现基于原型的继承

显式原型(prototype):用 来实现基于原型的继承与属性的共享

四、类型校验
基本数据类型(undefined,number,boolean,string,Symbol(ES6新增的基本数据类型),null)
还有一种复杂的数据类型Object,Object本质是一组无序的名值对组成的。

①. typeof
1.可以判断数据类型,它返回表示数据类型的字符串(返回结果只能包括number,boolean,string,function,object,undefined);
2.可以使用typeof判断变量是否存在(如if(typeof a!=“undefined”){…});
3.Typeof 运算符的问题是无论引用的对象是什么类型 它都返回object
②.instanceof
判断 new 关键字创建的引用数据类型
不考虑 null 和 undefined(这两个比较特殊)以对象字面量创建的基本数据类型
instanceof可以判断复杂数据类型,基本数据类型不可以

推荐③.通过Object下的toString.call()方法来判断
对于 Object.prototype.toString.call(arg),若参数为 null 或 undefined,直接返回结果。
Object.prototype.toString.call(null); // => “[object Null]”
Object.prototype.toString.ca.ll(undefined); // => “[object Undefined]”
若参数不为 null 或 undefined,则将参数转为对象,再作判断。

④.根据对象的contructor判断
constructor 似乎完全可以应对基本数据类型和引用数据类型 但如果声明了一个构造函数,并且把他的原型指向了 Array 的原型,所以这种情况下,constructor 也显得力不从心除了null、undefined,因为他们不是由对象构建。

constructor是prototype对象上的属性,指向构造函数。根据实例对象寻找属性的顺序,若实例对象上没有实例属性或方法时,就去原型链上寻找,因此,实例对象也是能使用constructor属性的。

上一篇:14.函数中的prototype属性和__proto__属性


下一篇:轻松理解JS中的面向对象,顺便搞懂prototype和__proto__