传址与传值 / 操作符
上一篇的 继承 中说到 原型链继承
原型链继承过来就会破坏原先的构造函数结构(复杂数据类型拷贝只是引用地址)
我们需要原有结构时,就不能再使用了
传址与传值
传值和传址实际上都是拷贝复制,只是复制的效果不同
简单数据类型 - 传值
深拷贝:
复制详细的数据与内存空间,不影响被复制的数据;
针对当前对象的数据的所有引用结构都拷贝一份,数据在内存中是独立的。
若属性是引用类型,如果进行更改,不会影响拷贝的原对象属性。
let a = 10;
let b = a;
b = 20;
console.log(a)
console.log(b)
复杂数据类型 - 传址
浅拷贝:
只是引用地址与原数据共用内存,节省内存,互相影响
只针对当前对象的属性进行拷贝,若当前对象的属性是引用类型时,这个不考虑,不进行拷贝。
若属性是引用类型,拷贝后引用的是地址,如果进行更改,会影响拷贝的原对象属性。
let GroundPa = {
name:"谨慎",
age:"70"
}
let Pa = GroundPa;
Pa.name = "小心"
console.log(Pa)
console.log(GroundPa)
解决复杂数据类型浅拷贝的问题
方法一:
- 通过JSON数据转换
let father = {
name:"玉",
sex:"男",
age:"50",
text:undefined,
fun:function(){
console.log("学习,出人头地")
}
}
let fa = JSON.parse(JSON.stringify(father))
fa.name = "秦";
console.log(father)
console.log(fa)
- 弊端:
会丢失function 和 undefind的 数据
方法二:
- 分解为 简单数据
进行深拷贝
返回新的对象
function deep(obj){
let newObj = Array.isArray(obj)?[]:{};
// for-in 会遍历对象和原型上 和 原型链的属性和方法
// 但是我们作深拷贝的时候,是不需要原型或者原型链上的属性和方法的
for(let key in obj){
// 判断是否是对象自身的内容,如果是,才去做深拷贝
if(obj.hasOwnProperty(key)){
// 判断是否是对象(也就是复杂的数据类型)
if(typeof obj[key] === "object"){
// 如果内部依然有更深层的对象
// 那么还需要按照原有步骤,再循环检测一遍
newObj[key] = deep(obj[key]);
}else{// 如果不是,只是简单数据类型
newObj[key] = obj[key]
}
}
}
//最后,我们将检测赋值后的新对象返回,以此达成新内存的目的
return newObj;
}
操作符
以下面的代码为例
function Animal(){
this.name = "join";
}
Animal.prototype.sex = "男";
Animal.prototype.eat = function(){
console.log("我正在吃好吃的");
}
var animal = new Animal();
animal.age = 19;
animal.sex = "男";
function Son(){
Animal.call(this);
this.a = 10;
this.s ="s";
this.fn= ()=>{
console.log("我是一个孩子");
}
}
Son.prototype.score = "90";
Son.prototype.shopping = function(){
console.log("我是来逛街的");
}
Son.prototype = deepCopy(Animal.prototype);
Son.prototype.constructor = Son;
- instanceof
判断一个实例对象 是否是某个函数的实例
// 对象名 instanceof 函数名
var a1 = new Animal();
var s1 = new Son();
console.log(a1);
console.log(s1);
console.log(s1 instanceof Son);
console.log(s1 instanceof Animal);
- isPrototypeof( )
只要是原型链中出现过的原型,都可以说是该原型链所产生的原型,返回true
// 原型名.isPrototypeOf(对象名)
// 会从s1开始沿着原型链逐层向上找,看看有没有一个叫Son.prototype的
console.log(Son.prototype.isPrototypeOf(s1));
- hasOwnProperty( )
用来检测当前对象中是否有该属性, 返回值为布尔类型
不会检查原型和原型链上的内容
只会去查找构造函数中的内容
// 对象名.hasOwnProperty("属性/方法名");
console.log(s1.hasOwnProperty("fn"));
- delete
用来删除属性
delete s1.name;
- in
检查该对象是否包含指定属性
这个属性可以是对象的直接属性
也可以是prototype继承而来的属性
但是原型自身的属性/方法不行(原型链继承,重构原型,覆盖掉了)
console.log("a" in s1);
console.log("name" in s1);
console.log("eat" in s1);
console.log("score" in s1);
console.log(s1.score);