JS中有关对象的继承以及实例化、浅拷贝深拷贝的奥秘
一、属性的归属问题
JS对象中定义的属性和方法如果不是挂在原型链上的方法和属性(直接通过如类似x的方式进行定义)都只是在该对象上,对原型链上的没有影响。对于所有实例共用的方法可直接定义在原型链上这样实例化的的时候就不用对每个实例定义该属性方法,所有的实例均具有该方的引用见最后的输出。
function Myclass(){ this.x=" x in Myclass"; this.get=function(){}//每次实例化对象,每个对象的该方法都是独立的,是不相同的 } Myclass.prototype.y="y in Myclass"; Myclass.prototype.set=function(){};//所有实例共用该方法,对于该方法具有同一个实例 var obj=new Myclass(); console.log(obj.y);//y in Myclass obj.y="override y";//查找属性时现在当前的对象上找,没找到才到原型链上查找 console.log(obj.y);//override y delete obj.y //true console.log(obj.y);//y in Myclass var obj2=new Myclass(); console.log(obj2.y);//y in Myclass obj.z='zzz'; console.log(obj.z);//zzz console.log(obj2.z);//undefined console.log(obj.prototype);//undefined console.log(obj.get===obj2.get)//false; console.log(obj.set===obj2.set)//true,所有的实例具有相同的引用
二、JS中有关原型的__proto__和prototype的差别:
所有的实例对象都具有__proto__来表示其原型,prototype是方法具有的属性,非对象的方法的该属性为null,这两者都用于表示对象的原型链,由于很多场合下前者是私有属性一般不直接使用故可以用Object.getPrototypeOf(obj)的方式获取到原型对象,Object.create()中传入的即为创建对象的原型。
function Myclass(){ this.x=" x in Myclass"; this.get=function(){}//每次实例化对象,每个对象的该方法都是独立的,是不相同的 } Myclass.prototype.y="y in Myclass"; Myclass.prototype.set=function(){};//所有实例共用该方法,对于该方法具有同一个实例 var obj=Object.create(new Myclass()); //obj.__proto__.y=10; console.log(obj.__proto__); console.log(Myclass.prototype); var obj2=new Myclass(); console.log(Myclass.prototype===obj.__proto__.__proto__);//ture console.log(obj.x); console.log(Object.getPrototypeOf(obj2)===Myclass.prototype);//true
三、对象的实例化和继承
利用new进行实例化对象,利用原型(prototype)实现继承,在继承时只会继承原型链上的属性和方法,不会继承挂在对象自身上的属性和方法,实例化时对象具有所有的属性和方法。
function Myclass(){ this.x=" x in Myclass";//每次实例化对象,每个对象的该方法都是独立的,没有被继承 this.get=function(){} } Myclass.prototype.y="y in Myclass"; Myclass.prototype.set=function(){};//所有实例共用该方法,对于该方法具有同一个引用,定义在原型链上的属性和方法都会被继承 var obj=Object.create(Myclass.prototype);//create的第一个参数必须是原型,第二个参数用于定义属性和defineProperties/defineProperty使用方法相同 console.log(obj.x);//undefined console.log(obj.y);// y in Myclass
因而可以通过混合模式定义对象实现属性或者方法的部分继承,不想被继承的利用构造函数的方式this.property方式定义,想要被继承的直接定义在原型链上(如上面的只继承了y属性和set方法,其他的x等就没有被继承)。不过如果直接实例化会具有所有的属性和方法。通过create的方式则只具有继承的属性和方法。
//继承的时利用实例化的对象作为原型不会影响原对象实例化出来的对象
function Myclass(){ this.x=" x in Myclass"; this.get=function(){}//每次实例化对象,每个对象的该方法都是独立的,是不相同的 } Myclass.prototype.y="y in Myclass"; Myclass.prototype.set=function(){};//所有实例共用该方法,对于该方法具有同一个实例 function obj(){}; obj.prototype=new Myclass(); var obj1=new obj();//利用create出来的对象是实例是不能实例化的 obj1.x=12; var obj2=new Myclass(); console.log(obj2.x);// x in Myclass console.log(obj1.x); //12
1、JS中可以直接使用delete对对象的属性进行删除,但是不能删除原型链上的属性,和普通变量,同时当对象中的属性配置false时不可以删除该属性
1,对象属性删除(delete无法删除原型链上的属性)
function fun(){ this.name = 'mm'; } var obj = new fun(); console.log(obj.name);//mm delete obj.name; console.log(obj.name); //undefined
2,变量删除(在严格模式下不能利用delete删除变量)
var name = 'lily'; delete name; console.log(name); //lily
直接用delelte删除不了变量
3,删除不了原型链中的变量
fun.prototype.age = 18; delete obj.age; console.log(obj.age) //18
四、对象的浅拷贝深拷贝
深拷贝、浅拷贝: 浅拷贝:不会继续对对象里面的对象进行解析赋值 function deepCopy(p, c) { var c = c || {}; for (var i in p) { c[i] = p[i]; } return c; } 深拷贝: function deepCopy(p, c) { var c = c || {}; for (var i in p) { if (typeof p[i] === 'object') { c[i] = (p[i].constructor === Array) ? [] : {}; deepCopy(p[i], c[i]); } else { c[i] = p[i]; } } return c; }
比较两个对象那个是否相等如果直接用==、===比较的是对象的引用,当对象的引用是相同的时则相等。上诉进行拷贝的方式对象那个都是不相等的,只有赋值的才是相等的。所以判断对象是否相等要注意是只要属性名称、个数、值直接相等就是相等还是通过类型引用判断的。
五、对象中常用的方法
1、通过Object.preventExtention(a)可以对a对象禁止扩展
2、利用Object.seal()对对象进行密封是的对象不可配置和重新赋值
3、利用Object.freeze()对对象进行冻结使对象只能够读取,这个只是浅操作,当对象的属性还是对象时可以修改其嵌套的对象的值
4、访问对象中的属性如果没有定义会返回undefined但是访问没有定义的变量时会提示 Uncaught ReferenceError
5、对象中判断某个属性是否存在的方法:
(1)‘a’ in myobject 判断a属性是否在myobject中(会对原型链进行查找)
(2)myobject.hasOwnProperty(‘a’)这个只会当前对象上查找自生的属性是否存在但是不会在原型链上查找。
以上两种方式都可以对不可枚举的属性进行查找
不可枚举的属性是不能被遍历得到的
6、propertyIsEnumerale()用于判断属性是不是可枚举的
7、Object.keys()用于获取所有自身的可枚举属性的属性名(不包括原型链上继承的)
8、for in 循环可遍历对象那个所有的自身以及集成的可枚举的属性
9、Object.hasOwnProperty()判断某个属性是不是对象自身的属性(其中包括不可枚举的),利用for in结合即可获取所有自身可枚举属性
10、Object.getOwnPropertyNames()获取对象自身的所有的属性名
JS中的对象(如数组、方法、object)直接赋值给其他变量传递的是对象的引用,赋值后会相互影响。如: var aa={a:1,b:2};
var bb=aa;//直接将aa对象赋值,其实是将aa对象的引用赋给bb
bb.a=2;
console.log(aa);//Object {a: 2, b: 2},aa的结果受到影响。
对象直接赋值会导致动一处导致多处影响,所以最好利用拷贝的方式进行赋值。